New test.
[mono.git] / mcs / class / System / System.Net / FileWebRequest.cs
1 //\r
2 // System.Net.FileWebRequest\r
3 //\r
4 // Author:\r
5 //   Lawrence Pit (loz@cable.a2000.nl)\r
6 //\r
7
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 \r
29 using System;\r
30 using System.Collections;\r
31 using System.IO;\r
32 using System.Runtime.Serialization;\r
33 using System.Runtime.Remoting.Messaging;\r
34 using System.Threading;\r
35 \r
36 namespace System.Net \r
37 {\r
38         [Serializable]\r
39         public class FileWebRequest : WebRequest, ISerializable\r
40         {\r
41                 private Uri uri;\r
42                 private WebHeaderCollection webHeaders;\r
43                 \r
44                 private ICredentials credentials;\r
45                 private string connectionGroup;\r
46                 private string method = "GET";\r
47                 private int timeout = 100000;\r
48                 \r
49                 private Stream requestStream;\r
50                 private FileWebResponse webResponse;\r
51                 private AutoResetEvent requestEndEvent;\r
52                 private bool requesting;\r
53                 private bool asyncResponding;\r
54                 \r
55                 // Constructors\r
56                 \r
57                 internal FileWebRequest (Uri uri) \r
58                 { \r
59                         this.uri = uri;\r
60                         this.webHeaders = new WebHeaderCollection ();\r
61                 }               \r
62                 \r
63                 protected FileWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext) \r
64                 {\r
65                         SerializationInfo info = serializationInfo;\r
66 \r
67                         method = info.GetString ("method");\r
68                         uri = (Uri) info.GetValue ("uri", typeof (Uri));\r
69                         timeout = info.GetInt32 ("timeout");\r
70                         connectionGroup = info.GetString ("connectionGroup");\r
71                         webHeaders = (WebHeaderCollection) info.GetValue ("webHeaders", typeof (WebHeaderCollection));\r
72                 }\r
73                 \r
74                 // Properties\r
75                 \r
76                 // currently not used according to spec\r
77                 public override string ConnectionGroupName { \r
78                         get { return connectionGroup; }\r
79                         set { connectionGroup = value; }\r
80                 }\r
81                 \r
82                 public override long ContentLength { \r
83                         get { \r
84                                 try {\r
85                                         return Int64.Parse (webHeaders ["Content-Length"]); \r
86                                 } catch (Exception) {\r
87                                         return 0;\r
88                                 }\r
89                         }\r
90                         set { \r
91                                 if (value < 0)\r
92                                         throw new ArgumentException ("value");\r
93                                 webHeaders ["Content-Length"] = Convert.ToString (value);\r
94                         }\r
95                 }\r
96                 \r
97                 public override string ContentType { \r
98                         get { return webHeaders ["Content-Type"]; }\r
99                         set { webHeaders ["Content-Type"] = value; }\r
100                 }\r
101                 \r
102                 public override ICredentials Credentials { \r
103                         get { return credentials; }\r
104                         set { credentials = value; }\r
105                 }\r
106                 \r
107                 public override WebHeaderCollection Headers { \r
108                         get { return webHeaders; }\r
109                 }\r
110                 \r
111                 // currently not used according to spec\r
112                 public override string Method { \r
113                         get { return this.method; }\r
114                         set { this.method = value; }\r
115                 }\r
116                 \r
117                 // currently not used according to spec\r
118                 public override bool PreAuthenticate { \r
119                         get { throw new NotSupportedException (); }\r
120                         set { throw new NotSupportedException (); }\r
121                 }\r
122                 \r
123                 // currently not used according to spec\r
124                 public override IWebProxy Proxy { \r
125                         get { throw new NotSupportedException (); }\r
126                         set { throw new NotSupportedException (); }\r
127                 }\r
128                 \r
129                 public override Uri RequestUri { \r
130                         get { return this.uri; }\r
131                 }\r
132                 \r
133                 public override int Timeout { \r
134                         get { return timeout; }\r
135                         set { \r
136                                 if (value < 0)\r
137                                         throw new ArgumentException ("value");\r
138                                 timeout = value;\r
139                         }\r
140                 }\r
141                 \r
142                 // Methods\r
143                 \r
144                 private delegate Stream GetRequestStreamCallback ();\r
145                 private delegate WebResponse GetResponseCallback ();\r
146 \r
147                 public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) \r
148                 {               \r
149                         if (method == null || (!method.Equals ("PUT") && !method.Equals ("POST")))\r
150                                 throw new ProtocolViolationException ("Cannot send file when method is: " + this.method + ". Method must be PUT.");\r
151                         // workaround for bug 24943\r
152                         Exception e = null;\r
153                         lock (this) {\r
154                                 if (asyncResponding || webResponse != null)\r
155                                         e = new InvalidOperationException ("This operation cannot be performed after the request has been submitted.");\r
156                                 else if (requesting)\r
157                                         e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
158                                 else\r
159                                         requesting = true;\r
160                         }\r
161                         if (e != null)\r
162                                 throw e;\r
163                         /*\r
164                         lock (this) {\r
165                                 if (asyncResponding || webResponse != null)\r
166                                         throw new InvalidOperationException ("This operation cannot be performed after the request has been submitted.");\r
167                                 if (requesting)\r
168                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
169                                 requesting = true;\r
170                         }\r
171                         */\r
172                         GetRequestStreamCallback c = new GetRequestStreamCallback (this.GetRequestStreamInternal);\r
173                         return c.BeginInvoke (callback, state);                 \r
174                 }\r
175                 \r
176                 public override Stream EndGetRequestStream (IAsyncResult asyncResult)\r
177                 {\r
178                         if (asyncResult == null)\r
179                                 throw new ArgumentNullException ("asyncResult");\r
180                         if (!asyncResult.IsCompleted)\r
181                                 asyncResult.AsyncWaitHandle.WaitOne ();                         \r
182                         AsyncResult async = (AsyncResult) asyncResult;\r
183                         GetRequestStreamCallback cb = (GetRequestStreamCallback) async.AsyncDelegate;\r
184                         return cb.EndInvoke (asyncResult);\r
185                 }\r
186 \r
187                 public override Stream GetRequestStream()\r
188                 {\r
189                         IAsyncResult asyncResult = BeginGetRequestStream (null, null);\r
190                         if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {\r
191                                 throw new WebException("The request timed out", WebExceptionStatus.Timeout);\r
192                         }\r
193                         return EndGetRequestStream (asyncResult);\r
194                 }\r
195                 \r
196                 internal Stream GetRequestStreamInternal ()\r
197                 {\r
198                         this.requestStream = new FileWebStream (\r
199                                                 this,\r
200                                                 FileMode.CreateNew,\r
201                                                 FileAccess.Write, \r
202                                                 FileShare.Read);\r
203                         return this.requestStream;\r
204                 }\r
205                 \r
206                 public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)\r
207                 {\r
208                         // workaround for bug 24943\r
209                         Exception e = null;\r
210                         lock (this) {\r
211                                 if (asyncResponding)\r
212                                         e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
213                                 else \r
214                                         asyncResponding = true;\r
215                         }\r
216                         if (e != null)\r
217                                 throw e;\r
218                         /*\r
219                         lock (this) {\r
220                                 if (asyncResponding)\r
221                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
222                                 asyncResponding = true;\r
223                         }\r
224                         */\r
225                         GetResponseCallback c = new GetResponseCallback (this.GetResponseInternal);\r
226                         return c.BeginInvoke (callback, state);\r
227                 }\r
228 \r
229                 public override WebResponse EndGetResponse (IAsyncResult asyncResult)\r
230                 {\r
231                         if (asyncResult == null)\r
232                                 throw new ArgumentNullException ("asyncResult");\r
233                         if (!asyncResult.IsCompleted)\r
234                                 asyncResult.AsyncWaitHandle.WaitOne ();                 \r
235                         AsyncResult async = (AsyncResult) asyncResult;\r
236                         GetResponseCallback cb = (GetResponseCallback) async.AsyncDelegate;\r
237                         WebResponse webResponse = cb.EndInvoke(asyncResult);\r
238                         asyncResponding = false;\r
239                         return webResponse;\r
240                 }\r
241                                 \r
242                 public override WebResponse GetResponse ()\r
243                 {\r
244                         IAsyncResult asyncResult = BeginGetResponse (null, null);\r
245                         if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {\r
246                                 throw new WebException("The request timed out", WebExceptionStatus.Timeout);\r
247                         }\r
248                         return EndGetResponse (asyncResult);\r
249                 }\r
250                         \r
251                 WebResponse GetResponseInternal ()\r
252                 {\r
253                         if (webResponse != null)\r
254                                 return webResponse;                     \r
255                         lock (this) {\r
256                                 if (requesting) {\r
257                                         requestEndEvent = new AutoResetEvent (false);\r
258                                 }\r
259                         }\r
260                         if (requestEndEvent != null) {\r
261                                 requestEndEvent.WaitOne ();\r
262                         }\r
263                         FileStream fileStream = new FileWebStream (\r
264                                                         this,\r
265                                                         FileMode.Open, \r
266                                                         FileAccess.Read, \r
267                                                         FileShare.Read);\r
268                         this.webResponse = new FileWebResponse (this.uri, fileStream);\r
269                         return (WebResponse) this.webResponse;\r
270                 }\r
271                 \r
272                 void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)\r
273                 {\r
274                         SerializationInfo info = serializationInfo;\r
275 \r
276                         info.AddValue ("method", method);\r
277                         info.AddValue ("uri", uri, typeof (Uri));\r
278                         info.AddValue ("timeout", timeout);\r
279                         info.AddValue ("connectionGroup", connectionGroup);\r
280                         info.AddValue ("webHeaders", webHeaders, typeof (WebHeaderCollection));\r
281                 }\r
282                 \r
283                 internal void Close ()\r
284                 {\r
285                         // already done in class below\r
286                         // if (requestStream != null) {\r
287                         //      requestStream.Close ();\r
288                         // }\r
289 \r
290                         lock (this) {                   \r
291                                 requesting = false;\r
292                                 if (requestEndEvent != null) \r
293                                         requestEndEvent.Set ();\r
294                                 // requestEndEvent = null;\r
295                         }\r
296                 }\r
297                 \r
298                 // to catch the Close called on the FileStream\r
299                 internal class FileWebStream : FileStream\r
300                 {\r
301                         FileWebRequest webRequest;\r
302                         \r
303                         internal FileWebStream (FileWebRequest webRequest,    \r
304                                                 FileMode mode,\r
305                                                 FileAccess access,\r
306                                                 FileShare share)\r
307                                 : base (webRequest.RequestUri.LocalPath, \r
308                                         mode, access, share)\r
309                         {\r
310                                 this.webRequest = webRequest;\r
311                         }\r
312                                                 \r
313                         public override void Close() \r
314                         {\r
315                                 base.Close ();\r
316                                 FileWebRequest req = webRequest;\r
317                                 webRequest = null;\r
318                                 if (req != null)\r
319                                         req.Close ();\r
320                         }\r
321                 }\r
322         }\r
323 }\r