Discussed with @rolfbjarne, these were missed in the initial import of the mono-extension sources.
--- /dev/null
+//
+// CFContentStream.cs
+//
+// Authors:
+// Marek Safar <marek.safar@gmail.com>
+//
+// Copyright (C) 2013 Xamarin Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Threading;
+using System.Threading.Tasks;
+using System.IO;
+using System.Net;
+
+#if XAMCORE_4_0
+using CFNetwork;
+#elif XAMCORE_2_0
+using CoreServices;
+#else
+using MonoTouch.CoreServices;
+#endif
+
+namespace System.Net.Http
+{
+ class BufferData
+ {
+ public byte[] Buffer;
+ public int Length;
+ }
+
+ class CFContentStream : HttpContent
+ {
+ readonly CFHTTPStream http_stream;
+ BufferData data;
+ Mutex data_mutex;
+ AutoResetEvent data_event;
+ AutoResetEvent data_read_event;
+
+ // The requirements are:
+ // * We must read at least one byte from the stream every time
+ // we get a HasBytesAvailable event.
+ // * SerializeToStreamAsync is executed on a separate thread,
+ // so reads must somehow be synchronized with that thread.
+ //
+ // Current implementation:
+ // * We read data in ReadStreamData (on the same thread
+ // we got the HasBytesAvailable event, i.e. inside the
+ // HasBytesAvailable event handler).
+ // * Data is stored in a class-level buffer.
+ // * SerializeToStreamAsync blocks while waiting for
+ // data from ReadStreamData.
+ // * ReadStreamData will only read more data once SerializeToStreamAsync
+ // has consumed any existing data. This means we'll be
+ // blocking in the HasBytesAvailable event handler until
+ // any previously read data has been processed (this prevents
+ // any unbound memory growth).
+
+ public CFContentStream (CFHTTPStream stream)
+ {
+ this.http_stream = stream;
+ data = new BufferData () {
+ Buffer = new byte [4096],
+ };
+ data_event = new AutoResetEvent (false);
+ data_read_event = new AutoResetEvent (true);
+ data_mutex = new Mutex ();
+ }
+
+ public void ReadStreamData ()
+ {
+ data_read_event.WaitOne (); // make sure there's no pending data.
+
+ data_mutex.WaitOne ();
+ data.Length = (int) http_stream.Read (data.Buffer, 0, data.Buffer.Length);
+ data_mutex.ReleaseMutex ();
+
+ data_event.Set ();
+ }
+
+ public void Close ()
+ {
+ data_read_event.WaitOne (); // make sure there's no pending data
+
+ data_mutex.WaitOne ();
+ data = null;
+ data_mutex.ReleaseMutex ();
+
+ data_event.Set ();
+ }
+
+ protected internal override async Task SerializeToStreamAsync (Stream stream, TransportContext context)
+ {
+ while (data_event.WaitOne ()) {
+ data_mutex.WaitOne ();
+ if (data == null || data.Length <= 0) {
+ data_mutex.ReleaseMutex ();
+ data_read_event.Set ();
+ break;
+ }
+
+ await stream.WriteAsync (data.Buffer, 0, data.Length).ConfigureAwait (false);
+ data_mutex.ReleaseMutex ();
+
+ data_read_event.Set ();
+ }
+ }
+
+ protected internal override bool TryComputeLength (out long length)
+ {
+ length = 0;
+ return false;
+ }
+ }
+}
--- /dev/null
+//
+// CFNetworkHandler.cs
+//
+// Authors:
+// Marek Safar <marek.safar@gmail.com>
+//
+// Copyright (C) 2013 Xamarin Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Threading;
+using System.Net.Http.Headers;
+using System.Threading.Tasks;
+using System.IO;
+using System.Collections.Generic;
+using System.Net;
+
+#if XAMCORE_4_0
+using CFNetwork;
+using CoreFoundation;
+using CF=CoreFoundation;
+#elif XAMCORE_2_0
+using CoreServices;
+using CoreFoundation;
+using CF=CoreFoundation;
+#else
+using MonoTouch.CoreServices;
+using MonoTouch.CoreFoundation;
+using CF=MonoTouch.CoreFoundation;
+#endif
+
+namespace System.Net.Http
+{
+ public class CFNetworkHandler : HttpMessageHandler
+ {
+ class StreamBucket
+ {
+ public TaskCompletionSource<HttpResponseMessage> Response;
+ public HttpRequestMessage Request;
+ public CancellationTokenRegistration CancellationTokenRegistration;
+ public CFContentStream ContentStream;
+
+ public void Close ()
+ {
+ CancellationTokenRegistration.Dispose ();
+ ContentStream.Close ();
+ }
+ }
+
+ bool allowAutoRedirect;
+ bool sentRequest;
+ bool useSystemProxy;
+ CookieContainer cookies;
+
+ Dictionary<IntPtr, StreamBucket> streamBuckets;
+
+ public CFNetworkHandler ()
+ {
+ allowAutoRedirect = true;
+ streamBuckets = new Dictionary<IntPtr, StreamBucket> ();
+ }
+
+ void EnsureModifiability ()
+ {
+ if (sentRequest)
+ throw new InvalidOperationException (
+ "This instance has already started one or more requests. " +
+ "Properties can only be modified before sending the first request.");
+ }
+
+ public bool AllowAutoRedirect {
+ get {
+ return allowAutoRedirect;
+ }
+ set {
+ EnsureModifiability ();
+ allowAutoRedirect = value;
+ }
+ }
+
+ public CookieContainer CookieContainer {
+ get {
+ return cookies;
+ }
+ set {
+ EnsureModifiability ();
+ cookies = value;
+ }
+ }
+
+ public bool UseSystemProxy {
+ get {
+ return useSystemProxy;
+ }
+ set {
+ EnsureModifiability ();
+ useSystemProxy = value;
+ }
+ }
+
+ // TODO: Add more properties
+
+ protected override void Dispose (bool disposing)
+ {
+ // TODO: CloseStream remaining stream buckets if there are any
+
+ base.Dispose (disposing);
+ }
+
+ CFHTTPMessage CreateWebRequestAsync (HttpRequestMessage request)
+ {
+ var req = CFHTTPMessage.CreateRequest (request.RequestUri, request.Method.Method, request.Version);
+
+ // TODO:
+/*
+ if (wr.ProtocolVersion == HttpVersion.Version10) {
+ wr.KeepAlive = request.Headers.ConnectionKeepAlive;
+ } else {
+ wr.KeepAlive = request.Headers.ConnectionClose != true;
+ }
+
+ if (useDefaultCredentials) {
+ wr.UseDefaultCredentials = true;
+ } else {
+ wr.Credentials = credentials;
+ }
+
+ if (useProxy) {
+ wr.Proxy = proxy;
+ }
+*/
+ if (cookies != null) {
+ string cookieHeader = cookies.GetCookieHeader (request.RequestUri);
+ if (cookieHeader != "")
+ req.SetHeaderFieldValue ("Cookie", cookieHeader);
+ }
+
+ foreach (var header in request.Headers) {
+ foreach (var value in header.Value) {
+ req.SetHeaderFieldValue (header.Key, value);
+ }
+ }
+
+ if (request.Content != null) {
+ foreach (var header in request.Content.Headers) {
+ foreach (var value in header.Value) {
+ req.SetHeaderFieldValue (header.Key, value);
+ }
+ }
+ }
+
+ return req;
+ }
+
+ protected internal override async Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ sentRequest = true;
+
+ CFHTTPStream stream;
+ using (var message = CreateWebRequestAsync (request))
+ {
+ if (request.Content != null) {
+ var data = await request.Content.ReadAsByteArrayAsync ().ConfigureAwait (false);
+ message.SetBody (data);
+ }
+
+ stream = CFHTTPStream.CreateForHTTPRequest (message);
+ }
+
+ if (useSystemProxy) {
+ var proxies = CF.CFNetwork.GetSystemProxySettings ();
+ if (proxies.HTTPEnable) {
+ stream.SetProxy (proxies);
+ }
+ }
+
+ stream.ShouldAutoredirect = allowAutoRedirect;
+ stream.HasBytesAvailableEvent += HandleHasBytesAvailableEvent;
+ stream.ErrorEvent += HandleErrorEvent;
+ stream.ClosedEvent += HandleClosedEvent;
+
+ var response = new TaskCompletionSource<HttpResponseMessage> ();
+
+ if (cancellationToken.IsCancellationRequested) {
+ response.SetCanceled ();
+ return await response.Task;
+ }
+
+ var bucket = new StreamBucket () {
+ Request = request,
+ Response = response,
+ };
+
+ streamBuckets.Add (stream.Handle, bucket);
+
+ //
+ // Always schedule stream events handling on main-loop. Due to ConfigureAwait (false) we may end up
+ // on any thread-pool thread which may not have run-loop running
+ //
+#if XAMCORE_2_0
+ stream.EnableEvents (CF.CFRunLoop.Main, CF.CFRunLoop.ModeCommon);
+#else
+ stream.EnableEvents (CF.CFRunLoop.Main, CF.CFRunLoop.CFRunLoopCommonModes);
+#endif
+
+ stream.Open ();
+
+ bucket.CancellationTokenRegistration = cancellationToken.Register (() => {
+ StreamBucket bucket2;
+ if (!streamBuckets.TryGetValue (stream.Handle, out bucket2))
+ return;
+
+ bucket2.Response.TrySetCanceled ();
+ CloseStream (stream);
+ });
+
+ return await response.Task;
+ }
+
+ void HandleErrorEvent (object sender, CFStream.StreamEventArgs e)
+ {
+ var stream = (CFHTTPStream)sender;
+
+ StreamBucket bucket;
+ if (!streamBuckets.TryGetValue (stream.Handle, out bucket))
+ return;
+
+ bucket.Response.TrySetException (stream.GetError ());
+ CloseStream (stream);
+ }
+
+ void HandleClosedEvent (object sender, CFStream.StreamEventArgs e)
+ {
+ var stream = (CFHTTPStream)sender;
+ CloseStream (stream);
+ }
+
+ void CloseStream (CFHTTPStream stream)
+ {
+ StreamBucket bucket;
+ if (streamBuckets.TryGetValue (stream.Handle, out bucket)) {
+ bucket.Close ();
+ streamBuckets.Remove (stream.Handle);
+ }
+
+ stream.Close ();
+ }
+
+ void HandleHasBytesAvailableEvent (object sender, CFStream.StreamEventArgs e)
+ {
+ var stream = (CFHTTPStream) sender;
+
+ StreamBucket bucket;
+ if (!streamBuckets.TryGetValue (stream.Handle, out bucket))
+ return;
+
+ if (bucket.Response.Task.IsCompleted) {
+ bucket.ContentStream.ReadStreamData ();
+ return;
+ }
+
+ var header = stream.GetResponseHeader ();
+
+ // Is this possible?
+ if (!header.IsHeaderComplete)
+ throw new NotImplementedException ();
+
+ bucket.ContentStream = new CFContentStream (stream);
+
+ var response_msg = new HttpResponseMessage (header.ResponseStatusCode);
+ response_msg.RequestMessage = bucket.Request;
+ response_msg.ReasonPhrase = header.ResponseStatusLine;
+ response_msg.Content = bucket.ContentStream;
+
+ var fields = header.GetAllHeaderFields ();
+ if (fields != null) {
+ foreach (var entry in fields) {
+ if (entry.Key == null)
+ continue;
+
+ var key = entry.Key.ToString ();
+ var value = entry.Value == null ? string.Empty : entry.Value.ToString ();
+ HttpHeaders item_headers;
+ if (HttpHeaders.GetKnownHeaderKind (key) == Headers.HttpHeaderKind.Content) {
+ item_headers = response_msg.Content.Headers;
+ } else {
+ item_headers = response_msg.Headers;
+
+ if (cookies != null && (key == "Set-Cookie" || key == "Set-Cookie2"))
+ AddCookie (value, bucket.Request.RequestUri, key);
+ }
+
+ item_headers.TryAddWithoutValidation (key, value);
+ }
+ }
+
+ bucket.Response.TrySetResult (response_msg);
+
+ bucket.ContentStream.ReadStreamData ();
+ }
+
+ void AddCookie (string value, Uri uri, string header)
+ {
+ CookieCollection cookies1 = null;
+ try {
+ cookies1 = cookies.CookieCutter (uri, header, value, false);
+ } catch {
+ }
+
+ if (cookies1 != null && cookies1.Count != 0)
+ cookies.Add (cookies1);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using System.Net;
+#if XAMCORE_2_0
+using CoreFoundation;
+using Foundation;
+using ObjCRuntime;
+#elif MONOMAC
+using MonoMac.CoreFoundation;
+using MonoMac.Foundation;
+using MonoMac.ObjCRuntime;
+#else
+using MonoTouch.CoreFoundation;
+using MonoTouch.Foundation;
+using MonoTouch.ObjCRuntime;
+#endif
+
+#if SYSTEM_NET_HTTP && !MONOMAC
+namespace System.Net.Http {
+
+ public partial class HttpClient {
+
+ public HttpClient ()
+ : this (GetDefaultHandler (), true)
+ {
+ }
+
+ // note: the linker will re-write this to only reference the selected handler
+ // but we want this to work "as expected" even if the application is not being linked
+ static HttpMessageHandler GetDefaultHandler ()
+ {
+ return RuntimeOptions.GetHttpMessageHandler ();
+ }
+ }
+#else
+// due to historical reasons (around CFNetwork) Xamarin.Mac includes this inside it's profile assembly
+// and not a custom System.Net.Http assembly
+namespace Foundation {
+#endif
+
+ partial class NSUrlSessionHandler {
+
+ bool allowAutoRedirect;
+ ICredentials credentials;
+ bool sentRequest;
+
+ public bool AllowAutoRedirect {
+ get {
+ return allowAutoRedirect;
+ }
+ set {
+ EnsureModifiability ();
+ allowAutoRedirect = value;
+ }
+ }
+
+ public ICredentials Credentials {
+ get {
+ return credentials;
+ }
+ set {
+ EnsureModifiability ();
+ credentials = value;
+ }
+ }
+
+ internal void EnsureModifiability ()
+ {
+ if (sentRequest)
+ throw new InvalidOperationException (
+ "This instance has already started one or more requests. " +
+ "Properties can only be modified before sending the first request.");
+ }
+
+ // almost identical to ModernHttpClient version but it uses the constants from monotouch.dll | Xamarin.[iOS|WatchOS|TVOS].dll
+ static Exception createExceptionForNSError(NSError error)
+ {
+ var webExceptionStatus = WebExceptionStatus.UnknownError;
+
+ var innerException = new NSErrorException(error);
+
+ // errors that exists in both share the same error code, so we can use a single switch/case
+ // this also ease watchOS integration as if does not expose CFNetwork but (I would not be
+ // surprised if it)could return some of it's error codes
+#if MONOTOUCH_WATCH
+ if (error.Domain == NSError.NSUrlErrorDomain) {
+#else
+ if ((error.Domain == NSError.NSUrlErrorDomain) || (error.Domain == NSError.CFNetworkErrorDomain)) {
+#endif
+ // Parse the enum into a web exception status or exception. Some
+ // of these values don't necessarily translate completely to
+ // what WebExceptionStatus supports, so made some best guesses
+ // here. For your reading pleasure, compare these:
+ //
+ // Apple docs: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/index.html#//apple_ref/doc/constant_group/URL_Loading_System_Error_Codes
+ // .NET docs: http://msdn.microsoft.com/en-us/library/system.net.webexceptionstatus(v=vs.110).aspx
+ switch ((NSUrlError) (long) error.Code) {
+ case NSUrlError.Cancelled:
+ case NSUrlError.UserCancelledAuthentication:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) NSNetServicesStatus.CancelledError:
+#endif
+ // No more processing is required so just return.
+ return new OperationCanceledException(error.LocalizedDescription, innerException);
+ case NSUrlError.BadURL:
+ case NSUrlError.UnsupportedURL:
+ case NSUrlError.CannotConnectToHost:
+ case NSUrlError.ResourceUnavailable:
+ case NSUrlError.NotConnectedToInternet:
+ case NSUrlError.UserAuthenticationRequired:
+ case NSUrlError.InternationalRoamingOff:
+ case NSUrlError.CallIsActive:
+ case NSUrlError.DataNotAllowed:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.Socks5BadCredentials:
+ case (NSUrlError) CFNetworkErrors.Socks5UnsupportedNegotiationMethod:
+ case (NSUrlError) CFNetworkErrors.Socks5NoAcceptableMethod:
+ case (NSUrlError) CFNetworkErrors.HttpAuthenticationTypeUnsupported:
+ case (NSUrlError) CFNetworkErrors.HttpBadCredentials:
+ case (NSUrlError) CFNetworkErrors.HttpBadURL:
+#endif
+ webExceptionStatus = WebExceptionStatus.ConnectFailure;
+ break;
+ case NSUrlError.TimedOut:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.NetServiceTimeout:
+#endif
+ webExceptionStatus = WebExceptionStatus.Timeout;
+ break;
+ case NSUrlError.CannotFindHost:
+ case NSUrlError.DNSLookupFailed:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.HostNotFound:
+ case (NSUrlError) CFNetworkErrors.NetServiceDnsServiceFailure:
+#endif
+ webExceptionStatus = WebExceptionStatus.NameResolutionFailure;
+ break;
+ case NSUrlError.DataLengthExceedsMaximum:
+ webExceptionStatus = WebExceptionStatus.MessageLengthLimitExceeded;
+ break;
+ case NSUrlError.NetworkConnectionLost:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.HttpConnectionLost:
+#endif
+ webExceptionStatus = WebExceptionStatus.ConnectionClosed;
+ break;
+ case NSUrlError.HTTPTooManyRedirects:
+ case NSUrlError.RedirectToNonExistentLocation:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.HttpRedirectionLoopDetected:
+#endif
+ webExceptionStatus = WebExceptionStatus.ProtocolError;
+ break;
+ case NSUrlError.RequestBodyStreamExhausted:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.SocksUnknownClientVersion:
+ case (NSUrlError) CFNetworkErrors.SocksUnsupportedServerVersion:
+ case (NSUrlError) CFNetworkErrors.HttpParseFailure:
+#endif
+ webExceptionStatus = WebExceptionStatus.SendFailure;
+ break;
+ case NSUrlError.BadServerResponse:
+ case NSUrlError.ZeroByteResource:
+ case NSUrlError.CannotDecodeRawData:
+ case NSUrlError.CannotDecodeContentData:
+ case NSUrlError.CannotParseResponse:
+ case NSUrlError.FileDoesNotExist:
+ case NSUrlError.FileIsDirectory:
+ case NSUrlError.NoPermissionsToReadFile:
+ case NSUrlError.CannotLoadFromNetwork:
+ case NSUrlError.CannotCreateFile:
+ case NSUrlError.CannotOpenFile:
+ case NSUrlError.CannotCloseFile:
+ case NSUrlError.CannotWriteToFile:
+ case NSUrlError.CannotRemoveFile:
+ case NSUrlError.CannotMoveFile:
+ case NSUrlError.DownloadDecodingFailedMidStream:
+ case NSUrlError.DownloadDecodingFailedToComplete:
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.Socks4RequestFailed:
+ case (NSUrlError) CFNetworkErrors.Socks4IdentdFailed:
+ case (NSUrlError) CFNetworkErrors.Socks4IdConflict:
+ case (NSUrlError) CFNetworkErrors.Socks4UnknownStatusCode:
+ case (NSUrlError) CFNetworkErrors.Socks5BadState:
+ case (NSUrlError) CFNetworkErrors.Socks5BadResponseAddr:
+ case (NSUrlError) CFNetworkErrors.CannotParseCookieFile:
+ case (NSUrlError) CFNetworkErrors.NetServiceUnknown:
+ case (NSUrlError) CFNetworkErrors.NetServiceCollision:
+ case (NSUrlError) CFNetworkErrors.NetServiceNotFound:
+ case (NSUrlError) CFNetworkErrors.NetServiceInProgress:
+ case (NSUrlError) CFNetworkErrors.NetServiceBadArgument:
+ case (NSUrlError) CFNetworkErrors.NetServiceInvalid:
+#endif
+ webExceptionStatus = WebExceptionStatus.ReceiveFailure;
+ break;
+ case NSUrlError.SecureConnectionFailed:
+ webExceptionStatus = WebExceptionStatus.SecureChannelFailure;
+ break;
+ case NSUrlError.ServerCertificateHasBadDate:
+ case NSUrlError.ServerCertificateHasUnknownRoot:
+ case NSUrlError.ServerCertificateNotYetValid:
+ case NSUrlError.ServerCertificateUntrusted:
+ case NSUrlError.ClientCertificateRejected:
+ case NSUrlError.ClientCertificateRequired:
+ webExceptionStatus = WebExceptionStatus.TrustFailure;
+ break;
+#if !MONOTOUCH_WATCH
+ case (NSUrlError) CFNetworkErrors.HttpProxyConnectionFailure:
+ case (NSUrlError) CFNetworkErrors.HttpBadProxyCredentials:
+ case (NSUrlError) CFNetworkErrors.PacFileError:
+ case (NSUrlError) CFNetworkErrors.PacFileAuth:
+ case (NSUrlError) CFNetworkErrors.HttpsProxyConnectionFailure:
+ case (NSUrlError) CFNetworkErrors.HttpsProxyFailureUnexpectedResponseToConnectMethod:
+ webExceptionStatus = WebExceptionStatus.RequestProhibitedByProxy;
+ break;
+#endif
+ }
+ }
+
+ // Always create a WebException so that it can be handled by the client.
+ return new WebException(error.LocalizedDescription, innerException); //, webExceptionStatus, response: null);
+ }
+ }
+}