System.Drawing: added email to icon and test file headers
[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 \r
8 //\r
9 // Permission is hereby granted, free of charge, to any person obtaining\r
10 // a copy of this software and associated documentation files (the\r
11 // "Software"), to deal in the Software without restriction, including\r
12 // without limitation the rights to use, copy, modify, merge, publish,\r
13 // distribute, sublicense, and/or sell copies of the Software, and to\r
14 // permit persons to whom the Software is furnished to do so, subject to\r
15 // the following conditions:\r
16 // \r
17 // The above copyright notice and this permission notice shall be\r
18 // included in all copies or substantial portions of the Software.\r
19 // \r
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
27 //\r
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 long contentLength;\r
47                 private FileAccess fileAccess = FileAccess.Read;\r
48                 private string method = "GET";\r
49                 private IWebProxy proxy;\r
50                 private bool preAuthenticate;\r
51                 private int timeout = 100000;\r
52                 \r
53                 private Stream requestStream;\r
54                 private FileWebResponse webResponse;\r
55                 private AutoResetEvent requestEndEvent;\r
56                 private bool requesting;\r
57                 private bool asyncResponding;\r
58                 \r
59                 // Constructors\r
60                 \r
61                 internal FileWebRequest (Uri uri) \r
62                 { \r
63                         this.uri = uri;\r
64                         this.webHeaders = new WebHeaderCollection ();\r
65                 }\r
66                 \r
67 #if NET_2_0\r
68                 [Obsolete ("Serialization is obsoleted for this type", false)]\r
69 #endif\r
70                 protected FileWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext) \r
71                 {\r
72                         SerializationInfo info = serializationInfo;\r
73                         webHeaders = (WebHeaderCollection) info.GetValue ("headers", typeof (WebHeaderCollection));\r
74                         proxy = (IWebProxy) info.GetValue ("proxy", typeof (IWebProxy));\r
75                         uri = (Uri) info.GetValue ("uri", typeof (Uri));\r
76                         connectionGroup = info.GetString ("connectionGroupName");\r
77                         method = info.GetString ("method");\r
78                         contentLength = info.GetInt64 ("contentLength");\r
79                         timeout = info.GetInt32 ("timeout");\r
80                         fileAccess = (FileAccess) info.GetValue ("fileAccess", typeof (FileAccess));\r
81                         preAuthenticate = info.GetBoolean ("preauthenticate");\r
82                 }\r
83                 \r
84                 // Properties\r
85                 \r
86                 // currently not used according to spec\r
87                 public override string ConnectionGroupName {\r
88                         get { return connectionGroup; }\r
89                         set { connectionGroup = value; }\r
90                 }\r
91                 \r
92                 public override long ContentLength {\r
93                         get { return contentLength; }\r
94                         set {\r
95                                 if (value < 0)\r
96 #if NET_2_0\r
97                                         throw new ArgumentException ("The Content-Length value must be greater than or equal to zero.", "value");\r
98 #else\r
99                                         throw new ArgumentException ("value");\r
100 #endif\r
101                                 contentLength =  value;\r
102                         }\r
103                 }\r
104                 \r
105                 public override string ContentType { \r
106                         get { return webHeaders ["Content-Type"]; }\r
107                         set { webHeaders ["Content-Type"] = value; }\r
108                 }\r
109                 \r
110                 public override ICredentials Credentials { \r
111                         get { return credentials; }\r
112                         set { credentials = value; }\r
113                 }\r
114                 \r
115                 public override WebHeaderCollection Headers { \r
116                         get { return webHeaders; }\r
117                 }\r
118                 \r
119                 // currently not used according to spec\r
120                 public override string Method { \r
121                         get { return this.method; }\r
122                         set {\r
123                                 if (value == null || value.Length == 0)\r
124 #if NET_2_0\r
125                                         throw new ArgumentException ("Cannot set null or blank "\r
126                                                 + "methods on request.", "value");\r
127 #else\r
128                                         throw new ArgumentException ("Cannot set null or blank "\r
129                                                 + "methods on request.");\r
130 #endif\r
131                                 this.method = value;\r
132                         }\r
133                 }\r
134                 \r
135                 // currently not used according to spec\r
136                 public override bool PreAuthenticate { \r
137                         get { return preAuthenticate; }\r
138                         set { preAuthenticate = value; }\r
139                 }\r
140                 \r
141                 // currently not used according to spec\r
142                 public override IWebProxy Proxy {\r
143                         get { return proxy; }\r
144                         set { proxy = value; }\r
145                 }\r
146                 \r
147                 public override Uri RequestUri { \r
148                         get { return this.uri; }\r
149                 }\r
150                 \r
151                 public override int Timeout { \r
152                         get { return timeout; }\r
153                         set { \r
154                                 if (value < -1)\r
155 #if NET_2_0\r
156                                         throw new ArgumentOutOfRangeException ("Timeout can be "\r
157                                                 + "only set to 'System.Threading.Timeout.Infinite' "\r
158                                                 + "or a value >= 0.");\r
159 #else\r
160                                         throw new ArgumentOutOfRangeException ("value");\r
161 #endif\r
162                                 timeout = value;\r
163                         }\r
164                 }\r
165 \r
166 #if NET_2_0\r
167                 public override bool UseDefaultCredentials\r
168                 {\r
169                         get {\r
170                                 throw new NotSupportedException ();\r
171                         }\r
172                         set {\r
173                                 throw new NotSupportedException ();\r
174                         }\r
175                 }\r
176 #endif\r
177                 \r
178                 // Methods\r
179                 \r
180                 private delegate Stream GetRequestStreamCallback ();\r
181                 private delegate WebResponse GetResponseCallback ();\r
182 \r
183 #if NET_2_0\r
184                 static Exception GetMustImplement ()\r
185                 {\r
186                         return new NotImplementedException ();\r
187                 }\r
188                 \r
189                 /* LAMESPEC: Docs suggest this was present in 1.1 and\r
190                  * 1.0 profiles, but the masterinfos say otherwise\r
191                  */\r
192                 [MonoTODO]\r
193                 public override void Abort ()\r
194                 {\r
195                         throw GetMustImplement ();\r
196                 }\r
197 #endif\r
198 \r
199                 public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) \r
200                 {\r
201                         if (string.Compare ("GET", method, true) == 0 ||\r
202                                 string.Compare ("HEAD", method, true) == 0 ||\r
203                                 string.Compare ("CONNECT", method, true) == 0)\r
204                                 throw new ProtocolViolationException ("Cannot send a content-body with this verb-type.");\r
205                         lock (this) {\r
206                                 if (asyncResponding || webResponse != null)\r
207                                         throw new InvalidOperationException ("This operation cannot be performed after the request has been submitted.");\r
208                                 if (requesting)\r
209                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
210                                 requesting = true;\r
211                         }\r
212                         GetRequestStreamCallback c = new GetRequestStreamCallback (this.GetRequestStreamInternal);\r
213                         return c.BeginInvoke (callback, state);\r
214                 }\r
215                 \r
216                 public override Stream EndGetRequestStream (IAsyncResult asyncResult)\r
217                 {\r
218                         if (asyncResult == null)\r
219                                 throw new ArgumentNullException ("asyncResult");\r
220                         if (!asyncResult.IsCompleted)\r
221                                 asyncResult.AsyncWaitHandle.WaitOne ();\r
222                         AsyncResult async = (AsyncResult) asyncResult;\r
223                         GetRequestStreamCallback cb = (GetRequestStreamCallback) async.AsyncDelegate;\r
224                         return cb.EndInvoke (asyncResult);\r
225                 }\r
226 \r
227                 public override Stream GetRequestStream()\r
228                 {\r
229                         IAsyncResult asyncResult = BeginGetRequestStream (null, null);\r
230                         if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {\r
231                                 throw new WebException("The request timed out", WebExceptionStatus.Timeout);\r
232                         }\r
233                         return EndGetRequestStream (asyncResult);\r
234                 }\r
235                 \r
236                 internal Stream GetRequestStreamInternal ()\r
237                 {\r
238                         this.requestStream = new FileWebStream (\r
239                                                 this,\r
240                                                 FileMode.Create,\r
241                                                 FileAccess.Write, \r
242                                                 FileShare.Read);\r
243                         return this.requestStream;\r
244                 }\r
245                 \r
246                 public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)\r
247                 {\r
248                         lock (this) {\r
249                                 if (asyncResponding)\r
250                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
251                                 asyncResponding = true;\r
252                         }\r
253                         GetResponseCallback c = new GetResponseCallback (this.GetResponseInternal);\r
254                         return c.BeginInvoke (callback, state);\r
255                 }\r
256                 \r
257                 public override WebResponse EndGetResponse (IAsyncResult asyncResult)\r
258                 {\r
259                         if (asyncResult == null)\r
260                                 throw new ArgumentNullException ("asyncResult");\r
261                         if (!asyncResult.IsCompleted)\r
262                                 asyncResult.AsyncWaitHandle.WaitOne ();\r
263                         AsyncResult async = (AsyncResult) asyncResult;\r
264                         GetResponseCallback cb = (GetResponseCallback) async.AsyncDelegate;\r
265                         FileWebResponse webResponse = (FileWebResponse) cb.EndInvoke(asyncResult);\r
266                         asyncResponding = false;\r
267                         if (webResponse.HasError)\r
268                                 throw webResponse.Error;\r
269                         return webResponse;\r
270                 }\r
271                 \r
272                 public override WebResponse GetResponse ()\r
273                 {\r
274                         IAsyncResult asyncResult = BeginGetResponse (null, null);\r
275                         if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {\r
276                                 throw new WebException("The request timed out", WebExceptionStatus.Timeout);\r
277                         }\r
278                         return EndGetResponse (asyncResult);\r
279                 }\r
280                 \r
281                 WebResponse GetResponseInternal ()\r
282                 {\r
283                         if (webResponse != null)\r
284                                 return webResponse;\r
285                         lock (this) {\r
286                                 if (requesting) {\r
287                                         requestEndEvent = new AutoResetEvent (false);\r
288                                 }\r
289                         }\r
290                         if (requestEndEvent != null) {\r
291                                 requestEndEvent.WaitOne ();\r
292                         }\r
293                         FileStream fileStream = null;\r
294                         try {\r
295                                 fileStream = new FileWebStream (this, FileMode.Open, FileAccess.Read, FileShare.Read);\r
296                                 this.webResponse = new FileWebResponse (this.uri, fileStream);\r
297                         } catch (Exception ex) {\r
298                                 this.webResponse = new FileWebResponse (this.uri, new WebException (ex.Message, ex));\r
299                         }\r
300                         return this.webResponse;\r
301                 }\r
302                 \r
303                 void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)\r
304                 {\r
305                         GetObjectData (serializationInfo, streamingContext);\r
306                 }\r
307 \r
308 #if NET_2_0\r
309                 protected override\r
310 #endif\r
311                 void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)\r
312                 {\r
313                         SerializationInfo info = serializationInfo;\r
314                         info.AddValue ("headers", webHeaders, typeof (WebHeaderCollection));\r
315                         info.AddValue ("proxy", proxy, typeof (IWebProxy));\r
316                         info.AddValue ("uri", uri, typeof (Uri));\r
317                         info.AddValue ("connectionGroupName", connectionGroup);\r
318                         info.AddValue ("method", method);\r
319                         info.AddValue ("contentLength", contentLength);\r
320                         info.AddValue ("timeout", timeout);\r
321                         info.AddValue ("fileAccess", fileAccess);\r
322 #if NET_2_0\r
323                         info.AddValue ("preauthenticate", false);\r
324 #else\r
325                         info.AddValue ("preauthenticate", preAuthenticate);\r
326 #endif\r
327                 }\r
328                 \r
329                 internal void Close ()\r
330                 {\r
331                         // already done in class below\r
332                         // if (requestStream != null) {\r
333                         //      requestStream.Close ();\r
334                         // }\r
335 \r
336                         lock (this) {\r
337                                 requesting = false;\r
338                                 if (requestEndEvent != null) \r
339                                         requestEndEvent.Set ();\r
340                                 // requestEndEvent = null;\r
341                         }\r
342                 }\r
343                 \r
344                 // to catch the Close called on the FileStream\r
345                 internal class FileWebStream : FileStream\r
346                 {\r
347                         FileWebRequest webRequest;\r
348                         \r
349                         internal FileWebStream (FileWebRequest webRequest,    \r
350                                                 FileMode mode,\r
351                                                 FileAccess access,\r
352                                                 FileShare share)\r
353                                 : base (webRequest.RequestUri.LocalPath, \r
354                                         mode, access, share)\r
355                         {\r
356                                 this.webRequest = webRequest;\r
357                         }\r
358                         \r
359                         public override void Close() \r
360                         {\r
361                                 base.Close ();\r
362                                 FileWebRequest req = webRequest;\r
363                                 webRequest = null;\r
364                                 if (req != null)\r
365                                         req.Close ();\r
366                         }\r
367                 }\r
368         }\r
369 }\r