899c10f7676cf64ab0e93991de1d25c89444aec5
[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 using System;\r
9 using System.Collections;\r
10 using System.IO;\r
11 using System.Runtime.Serialization;\r
12 using System.Runtime.Remoting.Messaging;\r
13 using System.Threading;\r
14 \r
15 namespace System.Net \r
16 {\r
17         [Serializable]\r
18         public class FileWebRequest : WebRequest, ISerializable\r
19         {\r
20                 private Uri uri;\r
21                 private WebHeaderCollection webHeaders;\r
22                 \r
23                 private ICredentials credentials;\r
24                 private string connectionGroup;\r
25                 private string method;\r
26                 private int timeout;\r
27                 \r
28                 private Stream requestStream = null;\r
29                 private FileWebResponse webResponse = null;\r
30                 private AutoResetEvent requestEndEvent = null;\r
31                 private bool requesting = false;\r
32                 private bool asyncResponding = false;\r
33                 \r
34                 // Constructors\r
35                 \r
36                 internal FileWebRequest (Uri uri) \r
37                 { \r
38                         this.uri = uri;\r
39                         this.webHeaders = new WebHeaderCollection ();\r
40                         this.method = "GET";\r
41                         this.timeout = System.Threading.Timeout.Infinite; \r
42                 }               \r
43                 \r
44                 [MonoTODO]\r
45                 protected FileWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext) \r
46                 {\r
47                         throw new NotImplementedException ();\r
48                 }\r
49                 \r
50                 // Properties\r
51                 \r
52                 // currently not used according to spec\r
53                 public override string ConnectionGroupName { \r
54                         get { return connectionGroup; }\r
55                         set { connectionGroup = value; }\r
56                 }\r
57                 \r
58                 public override long ContentLength { \r
59                         get { \r
60                                 try {\r
61                                         return Int64.Parse (webHeaders ["Content-Length"]); \r
62                                 } catch (Exception) {\r
63                                         return 0;\r
64                                 }\r
65                         }\r
66                         set { \r
67                                 if (value < 0)\r
68                                         throw new ArgumentException ("value");\r
69                                 webHeaders ["Content-Length"] = Convert.ToString (value);\r
70                         }\r
71                 }\r
72                 \r
73                 public override string ContentType { \r
74                         get { return webHeaders ["Content-Type"]; }\r
75                         set { webHeaders ["Content-Type"] = value; }\r
76                 }\r
77                 \r
78                 public override ICredentials Credentials { \r
79                         get { return credentials; }\r
80                         set { credentials = value; }\r
81                 }\r
82                 \r
83                 public override WebHeaderCollection Headers { \r
84                         get { return webHeaders; }\r
85                 }\r
86                 \r
87                 // currently not used according to spec\r
88                 public override string Method { \r
89                         get { return this.method; }\r
90                         set { this.method = value; }\r
91                 }\r
92                 \r
93                 // currently not used according to spec\r
94                 public override bool PreAuthenticate { \r
95                         get { throw new NotSupportedException (); }\r
96                         set { throw new NotSupportedException (); }\r
97                 }\r
98                 \r
99                 // currently not used according to spec\r
100                 public override IWebProxy Proxy { \r
101                         get { throw new NotSupportedException (); }\r
102                         set { throw new NotSupportedException (); }\r
103                 }\r
104                 \r
105                 public override Uri RequestUri { \r
106                         get { return this.uri; }\r
107                 }\r
108                 \r
109                 public override int Timeout { \r
110                         get { return timeout; }\r
111                         set { \r
112                                 if (value < 0)\r
113                                         throw new ArgumentException ("value");\r
114                                 timeout = value;\r
115                         }\r
116                 }\r
117                 \r
118                 // Methods\r
119                 \r
120                 private delegate Stream GetRequestStreamCallback ();\r
121                 private delegate WebResponse GetResponseCallback ();\r
122 \r
123                 public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) \r
124                 {               \r
125                         if (method == null || (!method.Equals ("PUT") && !method.Equals ("POST")))\r
126                                 throw new ProtocolViolationException ("Cannot send file when method is: " + this.method + ". Method must be PUT.");\r
127                         // workaround for bug 24943\r
128                         Exception e = null;\r
129                         lock (this) {\r
130                                 if (asyncResponding || webResponse != null)\r
131                                         e = new InvalidOperationException ("This operation cannot be performed after the request has been submitted.");\r
132                                 else if (requesting)\r
133                                         e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
134                                 else\r
135                                         requesting = true;\r
136                         }\r
137                         if (e != null)\r
138                                 throw e;\r
139                         /*\r
140                         lock (this) {\r
141                                 if (asyncResponding || webResponse != null)\r
142                                         throw new InvalidOperationException ("This operation cannot be performed after the request has been submitted.");\r
143                                 if (requesting)\r
144                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
145                                 requesting = true;\r
146                         }\r
147                         */\r
148                         GetRequestStreamCallback c = new GetRequestStreamCallback (this.GetRequestStreamInternal);\r
149                         return c.BeginInvoke (callback, state);                 \r
150                 }\r
151                 \r
152                 public override Stream EndGetRequestStream (IAsyncResult asyncResult)\r
153                 {\r
154                         if (asyncResult == null)\r
155                                 throw new ArgumentNullException ("asyncResult");\r
156                         if (!asyncResult.IsCompleted)\r
157                                 asyncResult.AsyncWaitHandle.WaitOne ();                         \r
158                         AsyncResult async = (AsyncResult) asyncResult;\r
159                         GetRequestStreamCallback cb = (GetRequestStreamCallback) async.AsyncDelegate;\r
160                         return cb.EndInvoke (asyncResult);\r
161                 }\r
162 \r
163                 public override Stream GetRequestStream()\r
164                 {\r
165                         IAsyncResult asyncResult = BeginGetRequestStream (null, null);\r
166                         if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {\r
167                                 throw new WebException("The request timed out", WebExceptionStatus.Timeout);\r
168                         }\r
169                         return EndGetRequestStream (asyncResult);\r
170                 }\r
171                 \r
172                 internal Stream GetRequestStreamInternal ()\r
173                 {\r
174                         this.requestStream = new FileWebStream (\r
175                                                 this,\r
176                                                 FileMode.CreateNew,\r
177                                                 FileAccess.Write, \r
178                                                 FileShare.Read);\r
179                         return this.requestStream;\r
180                 }\r
181                 \r
182                 public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)\r
183                 {\r
184                         // workaround for bug 24943\r
185                         Exception e = null;\r
186                         lock (this) {\r
187                                 if (asyncResponding)\r
188                                         e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
189                                 else \r
190                                         asyncResponding = true;\r
191                         }\r
192                         if (e != null)\r
193                                 throw e;\r
194                         /*\r
195                         lock (this) {\r
196                                 if (asyncResponding)\r
197                                         throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");\r
198                                 asyncResponding = true;\r
199                         }\r
200                         */\r
201                         GetResponseCallback c = new GetResponseCallback (this.GetResponseInternal);\r
202                         return c.BeginInvoke (callback, state);\r
203                 }\r
204 \r
205                 public override WebResponse EndGetResponse (IAsyncResult asyncResult)\r
206                 {\r
207                         if (asyncResult == null)\r
208                                 throw new ArgumentNullException ("asyncResult");\r
209                         if (!asyncResult.IsCompleted)\r
210                                 asyncResult.AsyncWaitHandle.WaitOne ();                 \r
211                         AsyncResult async = (AsyncResult) asyncResult;\r
212                         GetResponseCallback cb = (GetResponseCallback) async.AsyncDelegate;\r
213                         WebResponse webResponse = cb.EndInvoke(asyncResult);\r
214                         asyncResponding = false;\r
215                         return webResponse;\r
216                 }\r
217                                 \r
218                 public override WebResponse GetResponse ()\r
219                 {\r
220                         IAsyncResult asyncResult = BeginGetResponse (null, null);\r
221                         if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {\r
222                                 throw new WebException("The request timed out", WebExceptionStatus.Timeout);\r
223                         }\r
224                         return EndGetResponse (asyncResult);\r
225                 }\r
226                         \r
227                 public WebResponse GetResponseInternal ()\r
228                 {\r
229                         if (webResponse != null)\r
230                                 return webResponse;                     \r
231                         lock (this) {\r
232                                 if (requesting) {\r
233                                         requestEndEvent = new AutoResetEvent (false);\r
234                                 }\r
235                         }\r
236                         if (requestEndEvent != null) {\r
237                                 requestEndEvent.WaitOne ();\r
238                         }\r
239                         FileStream fileStream = new FileWebStream (\r
240                                                         this,\r
241                                                         FileMode.Open, \r
242                                                         FileAccess.Read, \r
243                                                         FileShare.Read);\r
244                         this.webResponse = new FileWebResponse (this.uri, fileStream);\r
245                         return (WebResponse) this.webResponse;\r
246                 }\r
247                 \r
248                 [MonoTODO]\r
249                 void ISerializable.GetObjectData (SerializationInfo serializationInfo,\r
250                                                   StreamingContext streamingContext)\r
251                 {\r
252                         throw new NotImplementedException ();\r
253                 }\r
254                 \r
255                 internal void Close ()\r
256                 {\r
257                         // already done in class below\r
258                         // if (requestStream != null) {\r
259                         //      requestStream.Close ();\r
260                         // }\r
261 \r
262                         lock (this) {                   \r
263                                 requesting = false;\r
264                                 if (requestEndEvent != null) \r
265                                         requestEndEvent.Set ();\r
266                                 // requestEndEvent = null;\r
267                         }\r
268                 }\r
269                 \r
270                 // to catch the Close called on the FileStream\r
271                 internal class FileWebStream : FileStream\r
272                 {\r
273                         FileWebRequest webRequest;\r
274                         \r
275                         internal FileWebStream (FileWebRequest webRequest,    \r
276                                                 FileMode mode,\r
277                                                 FileAccess access,\r
278                                                 FileShare share)\r
279                                 : base (webRequest.RequestUri.LocalPath, \r
280                                         mode, access, share)\r
281                         {\r
282                                 this.webRequest = webRequest;\r
283                         }\r
284                                                 \r
285                         public override void Close() \r
286                         {\r
287                                 base.Close ();\r
288                                 FileWebRequest req = webRequest;\r
289                                 webRequest = null;\r
290                                 if (req != null)\r
291                                         req.Close ();\r
292                         }\r
293                 }\r
294         }\r
295 }