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-2010 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.
37 using System.Threading;
39 namespace System.Net {
41 // note: this type is effectively sealed to transparent code since it's default .ctor is marked with [SecuritySafeCritical]
42 public class WebClient {
44 WebHeaderCollection headers;
45 WebHeaderCollection responseHeaders;
48 Encoding encoding = Encoding.UTF8;
49 bool allow_read_buffering = true;
52 CallbackData callback_data;
56 // kind of calling NativeMethods.plugin_instance_get_source_location (PluginHost.Handle)
57 // but without adding dependency on System.Windows.dll. GetData is [SecurityCritical]
58 // this makes the default .ctor [SecuritySafeCritical] which would be a problem (inheritance)
59 // but it happens that MS SL2 also has this default .ctor as SSC :-)
60 baseAddress = (AppDomain.CurrentDomain.GetData ("xap_uri") as string);
61 locker = new object ();
66 public string BaseAddress {
67 get { return baseAddress; }
69 if (String.IsNullOrEmpty (value)) {
70 baseAddress = String.Empty;
73 if (!Uri.TryCreate (value, UriKind.Absolute, out uri))
74 throw new ArgumentException ("Invalid URI");
76 baseAddress = Uri.UnescapeDataString (uri.AbsoluteUri);
81 [MonoTODO ("provide credentials to the client stack")]
82 public ICredentials Credentials { get; set; }
84 // this is an unvalidated collection, HttpWebRequest is responsable to validate it
85 public WebHeaderCollection Headers {
88 headers = new WebHeaderCollection ();
92 set { headers = value; }
95 public WebHeaderCollection ResponseHeaders {
96 get { return responseHeaders; }
99 public Encoding Encoding {
100 get { return encoding; }
103 throw new ArgumentNullException ("value");
109 get { return is_busy; }
112 [MonoTODO ("value is unused, current implementation always works like it's true (default)")]
113 public bool AllowReadStreamBuffering {
114 get { return allow_read_buffering; }
115 set { allow_read_buffering = value; }
123 throw new NotSupportedException ("WebClient does not support conccurent I/O operations.");
134 private string DetermineMethod (Uri address, string method)
139 if (address.Scheme == Uri.UriSchemeFtp)
144 public event DownloadProgressChangedEventHandler DownloadProgressChanged;
145 public event DownloadStringCompletedEventHandler DownloadStringCompleted;
146 public event OpenReadCompletedEventHandler OpenReadCompleted;
147 public event OpenWriteCompletedEventHandler OpenWriteCompleted;
148 public event UploadProgressChangedEventHandler UploadProgressChanged;
149 public event UploadStringCompletedEventHandler UploadStringCompleted;
150 public event WriteStreamClosedEventHandler WriteStreamClosed;
152 WebRequest SetupRequest (Uri uri, string method, CallbackData callbackData)
154 callback_data = callbackData;
155 WebRequest request = GetWebRequest (uri);
156 request.Method = DetermineMethod (uri, method);
157 foreach (string header in Headers.AllKeys)
158 request.Headers.SetHeader (header, Headers [header]);
162 Stream ProcessResponse (WebResponse response)
164 responseHeaders = response.Headers;
165 HttpWebResponse hwr = (response as HttpWebResponse);
167 throw new NotSupportedException ();
169 HttpStatusCode status_code = HttpStatusCode.NotFound;
172 status_code = hwr.StatusCode;
173 if (status_code == HttpStatusCode.OK)
174 s = response.GetResponseStream ();
176 catch (Exception e) {
177 throw new WebException ("NotFound", e, WebExceptionStatus.UnknownError, response);
180 if (status_code != HttpStatusCode.OK)
181 throw new WebException ("NotFound", null, WebExceptionStatus.UnknownError, response);
186 public void CancelAsync ()
192 void CompleteAsync ()
198 public object user_token;
199 public SynchronizationContext sync_context;
201 public CallbackData (object user_token, byte [] data)
203 this.user_token = user_token;
205 this.sync_context = SynchronizationContext.Current ?? new SynchronizationContext ();
207 public CallbackData (object user_token) : this (user_token, null)
212 // DownloadStringAsync
214 public void DownloadStringAsync (Uri address)
216 DownloadStringAsync (address, null);
219 public void DownloadStringAsync (Uri address, object userToken)
222 throw new ArgumentNullException ("address");
228 request = SetupRequest (address, "GET", new CallbackData (userToken));
229 request.BeginGetResponse (new AsyncCallback (DownloadStringAsyncCallback), null);
231 catch (Exception e) {
232 WebException wex = new WebException ("Could not start operation.", e);
233 OnDownloadStringCompleted (
234 new DownloadStringCompletedEventArgs (null, wex, false, userToken));
239 private void DownloadStringAsyncCallback (IAsyncResult result)
245 WebResponse response = request.EndGetResponse (result);
246 Stream stream = ProcessResponse (response);
248 using (StreamReader sr = new StreamReader (stream, encoding, true)) {
249 data = sr.ReadToEnd ();
252 catch (WebException web) {
253 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
256 catch (Exception e) {
260 callback_data.sync_context.Post (delegate (object sender) {
261 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (data, ex, cancel, callback_data.user_token));
268 public void OpenReadAsync (Uri address)
270 OpenReadAsync (address, null);
273 public void OpenReadAsync (Uri address, object userToken)
276 throw new ArgumentNullException ("address");
282 request = SetupRequest (address, "GET", new CallbackData (userToken));
283 request.BeginGetResponse (new AsyncCallback (OpenReadAsyncCallback), null);
285 catch (Exception e) {
286 WebException wex = new WebException ("Could not start operation.", e);
287 OnOpenReadCompleted (
288 new OpenReadCompletedEventArgs (null, wex, false, userToken));
293 private void OpenReadAsyncCallback (IAsyncResult result)
295 Stream stream = null;
299 WebResponse response = request.EndGetResponse (result);
300 stream = ProcessResponse (response);
302 catch (WebException web) {
303 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
306 catch (Exception e) {
310 callback_data.sync_context.Post (delegate (object sender) {
311 OnOpenReadCompleted (new OpenReadCompletedEventArgs (stream, ex, cancel, callback_data.user_token));
318 public void OpenWriteAsync (Uri address)
320 OpenWriteAsync (address, null);
323 public void OpenWriteAsync (Uri address, string method)
325 OpenWriteAsync (address, method, null);
328 public void OpenWriteAsync (Uri address, string method, object userToken)
331 throw new ArgumentNullException ("address");
337 request = SetupRequest (address, method, new CallbackData (userToken));
338 request.BeginGetRequestStream (new AsyncCallback (OpenWriteAsyncCallback), null);
340 catch (Exception e) {
341 WebException wex = new WebException ("Could not start operation.", e);
342 OnOpenWriteCompleted (
343 new OpenWriteCompletedEventArgs (null, wex, false, userToken));
348 private void OpenWriteAsyncCallback (IAsyncResult result)
350 Stream stream = null;
353 InternalWebRequestStreamWrapper internal_stream;
356 stream = request.EndGetRequestStream (result);
357 internal_stream = (InternalWebRequestStreamWrapper) stream;
358 internal_stream.WebClient = this;
359 internal_stream.WebClientData = callback_data;
361 catch (WebException web) {
362 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
365 catch (Exception e) {
369 callback_data.sync_context.Post (delegate (object sender) {
370 OnOpenWriteCompleted (new OpenWriteCompletedEventArgs (stream, ex, cancel, callback_data.user_token));
375 internal void WriteStreamClosedCallback (object WebClientData)
378 request.BeginGetResponse (OpenWriteAsyncResponseCallback, WebClientData);
380 catch (Exception e) {
381 callback_data.sync_context.Post (delegate (object sender) {
382 OnWriteStreamClosed (new WriteStreamClosedEventArgs (e));
387 private void OpenWriteAsyncResponseCallback (IAsyncResult result)
390 WebResponse response = request.EndGetResponse (result);
391 ProcessResponse (response);
393 catch (Exception e) {
394 callback_data.sync_context.Post (delegate (object sender) {
395 OnWriteStreamClosed (new WriteStreamClosedEventArgs (e));
402 public void UploadStringAsync (Uri address, string data)
404 UploadStringAsync (address, null, data);
407 public void UploadStringAsync (Uri address, string method, string data)
409 UploadStringAsync (address, method, data, null);
412 public void UploadStringAsync (Uri address, string method, string data, object userToken)
415 throw new ArgumentNullException ("address");
417 throw new ArgumentNullException ("data");
423 request = SetupRequest (address, method, new CallbackData (userToken, encoding.GetBytes (data)));
424 request.BeginGetRequestStream (new AsyncCallback (UploadStringRequestAsyncCallback), null);
426 catch (Exception e) {
427 WebException wex = new WebException ("Could not start operation.", e);
428 OnUploadStringCompleted (
429 new UploadStringCompletedEventArgs (null, wex, false, userToken));
434 private void UploadStringRequestAsyncCallback (IAsyncResult result)
437 Stream stream = request.EndGetRequestStream (result);
438 stream.Write (callback_data.data, 0, callback_data.data.Length);
439 request.BeginGetResponse (new AsyncCallback (UploadStringResponseAsyncCallback), null);
447 private void UploadStringResponseAsyncCallback (IAsyncResult result)
453 WebResponse response = request.EndGetResponse (result);
454 Stream stream = ProcessResponse (response);
456 using (StreamReader sr = new StreamReader (stream, encoding, true)) {
457 data = sr.ReadToEnd ();
460 catch (WebException web) {
461 cancel = (web.Status == WebExceptionStatus.RequestCanceled);
464 catch (InvalidOperationException ioe) {
465 ex = new WebException ("An exception occurred during a WebClient request", ioe);
467 catch (Exception e) {
471 callback_data.sync_context.Post (delegate (object sender) {
472 OnUploadStringCompleted (new UploadStringCompletedEventArgs (data, ex, cancel, callback_data.user_token));
477 protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
479 DownloadProgressChangedEventHandler handler = DownloadProgressChanged;
484 protected virtual void OnOpenReadCompleted (OpenReadCompletedEventArgs args)
487 OpenReadCompletedEventHandler handler = OpenReadCompleted;
489 handler (this, args);
492 protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs args)
495 DownloadStringCompletedEventHandler handler = DownloadStringCompleted;
497 handler (this, args);
500 protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs args)
503 OpenWriteCompletedEventHandler handler = OpenWriteCompleted;
505 handler (this, args);
508 protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
510 UploadProgressChangedEventHandler handler = UploadProgressChanged;
515 protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs args)
518 UploadStringCompletedEventHandler handler = UploadStringCompleted;
520 handler (this, args);
523 protected virtual void OnWriteStreamClosed (WriteStreamClosedEventArgs e)
526 WriteStreamClosedEventHandler handler = WriteStreamClosed;
531 protected virtual WebRequest GetWebRequest (Uri address)
534 throw new ArgumentNullException ("address");
536 // if the URI is relative then we use our base address URI to make an absolute one
537 Uri uri = address.IsAbsoluteUri ? address : new Uri (new Uri (baseAddress), address);
539 WebRequest request = WebRequest.Create (uri);
541 request.progress = delegate (long read, long length) {
542 callback_data.sync_context.Post (delegate (object sender) {
543 OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (read, length, callback_data.user_token));
550 protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
552 return request.EndGetResponse (result);