2 // System.Net.WebClient
5 // Lawrence Pit (loz@cable.a2000.nl)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Atsushi Enomoto (atsushi@ximian.com)
8 // Miguel de Icaza (miguel@ximian.com)
9 // Stephane Delcroix (sdelcroix@novell.com)
11 // Copyright 2003 Ximian, Inc. (http://www.ximian.com)
12 // Copyright 2006, 2008, 2009 Novell, Inc. (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 namespace System.Net {
40 // note: this type is effectively sealed to transparent code since it's default .ctor is marked with [SecuritySafeCritical]
41 public class WebClient {
43 private delegate void ProgressChangedDelegate (long read, long length, object state);
45 WebHeaderCollection headers;
46 WebHeaderCollection responseHeaders;
50 Encoding encoding = Encoding.UTF8;
51 bool allow_read_buffering = true;
57 // kind of calling NativeMethods.plugin_instance_get_source_location (PluginHost.Handle)
58 // but without adding dependency on System.Windows.dll. GetData is [SecurityCritical]
59 // this makes the default .ctor [SecuritySafeCritical] which would be a problem (inheritance)
60 // but it happens that MS SL2 also has this default .ctor as SSC :-)
61 baseAddress = new Uri (AppDomain.CurrentDomain.GetData ("xap_uri") as string);
62 locker = new object ();
67 public string BaseAddress {
69 if (baseString == null) {
70 if (baseAddress == null)
73 baseString = baseAddress.ToString ();
79 if (String.IsNullOrEmpty (value)) {
82 baseAddress = new Uri (value);
87 // this is an unvalidated collection, HttpWebRequest is responsable to validate it
88 public WebHeaderCollection Headers {
91 headers = new WebHeaderCollection ();
95 set { headers = value; }
98 // note: it's public in SL3 beta 1 - but we need it right now
99 internal WebHeaderCollection ResponseHeaders {
100 get { return responseHeaders; }
103 public Encoding Encoding {
104 get { return encoding; }
107 throw new ArgumentNullException ("value");
113 get { return is_busy; }
116 [MonoTODO ("value is unused, current implementation always works like it's true (default)")]
117 public bool AllowReadStreamBuffering {
118 get { return allow_read_buffering; }
119 set { allow_read_buffering = value; }
127 throw new NotSupportedException ("WebClient does not support conccurent I/O operations.");
138 private string DetermineMethod (Uri address, string method)
143 if (address.Scheme == Uri.UriSchemeFtp)
148 public event DownloadProgressChangedEventHandler DownloadProgressChanged;
149 public event DownloadStringCompletedEventHandler DownloadStringCompleted;
150 public event OpenReadCompletedEventHandler OpenReadCompleted;
151 public event OpenWriteCompletedEventHandler OpenWriteCompleted;
152 public event UploadProgressChangedEventHandler UploadProgressChanged;
153 public event UploadStringCompletedEventHandler UploadStringCompleted;
154 public event WriteStreamClosedEventHandler WriteStreamClosed;
156 WebRequest SetupRequest (Uri uri, string method)
158 WebRequest request = GetWebRequest (uri);
159 request.Method = DetermineMethod (uri, method);
163 Stream ProcessResponse (WebResponse response)
165 responseHeaders = response.Headers;
166 HttpWebResponse hwr = (response as HttpWebResponse);
168 throw new NotSupportedException ();
170 HttpStatusCode status_code = HttpStatusCode.NotFound;
173 status_code = hwr.StatusCode;
174 if (status_code == HttpStatusCode.OK)
175 s = response.GetResponseStream ();
177 catch (Exception e) {
178 throw new WebException ("NotFound", e, WebExceptionStatus.UnknownError, response);
181 if (status_code != HttpStatusCode.OK)
182 throw new WebException ("NotFound", null, WebExceptionStatus.UnknownError, response);
187 public void CancelAsync ()
193 void CompleteAsync ()
200 // DownloadStringAsync
202 public void DownloadStringAsync (Uri address)
204 DownloadStringAsync (address, null);
207 public void DownloadStringAsync (Uri address, object userToken)
210 throw new ArgumentNullException ("address");
216 request = SetupRequest (address, "GET");
217 request.BeginGetResponse (new AsyncCallback (DownloadStringAsyncCallback), userToken);
219 catch (Exception e) {
220 WebException wex = new WebException ("Could not start operation.", e);
221 OnDownloadStringCompleted (
222 new DownloadStringCompletedEventArgs (null, wex, false, userToken));
227 private void DownloadStringAsyncCallback (IAsyncResult result)
233 WebResponse response = request.EndGetResponse (result);
234 Stream stream = ProcessResponse (response);
236 using (StreamReader sr = new StreamReader (stream, encoding, true)) {
237 data = sr.ReadToEnd ();
240 catch (WebException web) {
241 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
244 catch (Exception e) {
248 OnDownloadStringCompleted (
249 new DownloadStringCompletedEventArgs (data, ex, cancel, result.AsyncState));
255 public void OpenReadAsync (Uri address)
257 OpenReadAsync (address, null);
260 public void OpenReadAsync (Uri address, object userToken)
263 throw new ArgumentNullException ("address");
269 request = SetupRequest (address, "GET");
270 request.BeginGetResponse (new AsyncCallback (OpenReadAsyncCallback), userToken);
272 catch (Exception e) {
273 WebException wex = new WebException ("Could not start operation.", e);
274 OnOpenReadCompleted (
275 new OpenReadCompletedEventArgs (null, wex, false, userToken));
280 private void OpenReadAsyncCallback (IAsyncResult result)
282 Stream stream = null;
286 WebResponse response = request.EndGetResponse (result);
287 stream = ProcessResponse (response);
289 catch (WebException web) {
290 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
293 catch (Exception e) {
297 OnOpenReadCompleted (
298 new OpenReadCompletedEventArgs (stream, ex, cancel, result.AsyncState));
304 public void OpenWriteAsync (Uri address)
306 OpenWriteAsync (address, null);
309 public void OpenWriteAsync (Uri address, string method)
311 OpenWriteAsync (address, method, null);
314 public void OpenWriteAsync (Uri address, string method, object userToken)
317 throw new ArgumentNullException ("address");
323 request = SetupRequest (address, method);
324 request.BeginGetRequestStream (new AsyncCallback (OpenWriteAsyncCallback), userToken);
326 catch (Exception e) {
327 WebException wex = new WebException ("Could not start operation.", e);
328 OnOpenWriteCompleted (
329 new OpenWriteCompletedEventArgs (null, wex, false, userToken));
334 private void OpenWriteAsyncCallback (IAsyncResult result)
336 Stream stream = null;
340 stream = request.EndGetRequestStream (result);
342 catch (WebException web) {
343 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
346 catch (Exception e) {
350 OnOpenWriteCompleted (
351 new OpenWriteCompletedEventArgs (stream, ex, cancel, result.AsyncState));
357 public void UploadStringAsync (Uri address, string data)
359 UploadStringAsync (address, null, data);
362 public void UploadStringAsync (Uri address, string method, string data)
364 UploadStringAsync (address, method, data, null);
367 public void UploadStringAsync (Uri address, string method, string data, object userToken)
370 throw new ArgumentNullException ("address");
372 throw new ArgumentNullException ("data");
378 request = SetupRequest (address, method);
379 object[] bag = new object [] { encoding.GetBytes (data), userToken };
381 request.BeginGetRequestStream (new AsyncCallback (UploadStringRequestAsyncCallback), bag);
383 catch (Exception e) {
384 WebException wex = new WebException ("Could not start operation.", e);
385 OnUploadStringCompleted (
386 new UploadStringCompletedEventArgs (null, wex, false, userToken));
391 private void UploadStringRequestAsyncCallback (IAsyncResult result)
394 object[] bag = (result.AsyncState as object[]);
395 byte[] data = (bag [0] as byte[]);
396 Stream stream = request.EndGetRequestStream (result);
397 stream.Write (data, 0, data.Length);
398 request.BeginGetResponse (new AsyncCallback (UploadStringResponseAsyncCallback), bag [1]);
406 private void UploadStringResponseAsyncCallback (IAsyncResult result)
412 WebResponse response = request.EndGetResponse (result);
413 Stream stream = ProcessResponse (response);
415 using (StreamReader sr = new StreamReader (stream, encoding, true)) {
416 data = sr.ReadToEnd ();
419 catch (WebException web) {
420 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
423 catch (Exception e) {
427 OnUploadStringCompleted (
428 new UploadStringCompletedEventArgs (data, ex, cancel, result.AsyncState));
432 protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
434 if (DownloadProgressChanged != null) {
435 DownloadProgressChanged (this, e);
439 protected virtual void OnOpenReadCompleted (OpenReadCompletedEventArgs args)
442 if (OpenReadCompleted != null) {
443 OpenReadCompleted (this, args);
447 protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs args)
450 if (DownloadStringCompleted != null) {
451 DownloadStringCompleted (this, args);
455 protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs args)
458 if (OpenWriteCompleted != null)
459 OpenWriteCompleted (this, args);
462 protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
464 if (UploadProgressChanged != null)
465 UploadProgressChanged (this, e);
468 protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs args)
471 if (UploadStringCompleted != null)
472 UploadStringCompleted (this, args);
475 protected virtual void OnWriteStreamClosed (WriteStreamClosedEventArgs e)
477 throw new NotImplementedException ();
480 protected virtual WebRequest GetWebRequest (Uri address)
483 throw new ArgumentNullException ("address");
485 // if the URI is relative then we use our base address URI to make an absolute one
486 Uri uri = address.IsAbsoluteUri ? address : new Uri (baseAddress, address);
488 WebRequest request = WebRequest.Create (uri);
490 request.SetupProgressDelegate ((ProgressChangedDelegate) delegate (long read, long length, object state) {
491 OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (read, length, state));
496 protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
498 return request.EndGetResponse (result);