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