59456d6df0bb91dbaaae0de6a84b01c3e6b4ccf0
[mono.git] / mcs / class / System.Net.Http / HttpClientEx.cs
1 using System;
2 using System.IO;
3 using System.Net;
4 #if XAMCORE_2_0
5 using CoreFoundation;
6 using Foundation;
7 using ObjCRuntime;
8 #elif MONOMAC
9 using MonoMac.CoreFoundation;
10 using MonoMac.Foundation;
11 using MonoMac.ObjCRuntime;
12 #else
13 using MonoTouch.CoreFoundation;
14 using MonoTouch.Foundation;
15 using MonoTouch.ObjCRuntime;
16 #endif
17
18 #if SYSTEM_NET_HTTP && !MONOMAC
19 namespace System.Net.Http {
20
21         public partial class HttpClient {
22
23                 public HttpClient ()
24                         : this (GetDefaultHandler (), true)
25                 {
26                 }
27
28                 // note: the linker will re-write this to only reference the selected handler
29                 // but we want this to work "as expected" even if the application is not being linked
30                 static HttpMessageHandler GetDefaultHandler ()
31                 {
32                         return RuntimeOptions.GetHttpMessageHandler ();
33                 }
34         }
35 #else
36 // due to historical reasons (around CFNetwork) Xamarin.Mac includes this inside it's profile assembly
37 // and not a custom System.Net.Http assembly
38 namespace Foundation {
39 #endif
40
41         partial class NSUrlSessionHandler {
42
43                 bool allowAutoRedirect;
44                 ICredentials credentials;
45                 bool sentRequest;
46
47                 public bool AllowAutoRedirect {
48                         get {
49                                 return allowAutoRedirect;
50                         }
51                         set {
52                                 EnsureModifiability ();
53                                 allowAutoRedirect = value;
54                         }
55                 }
56
57                 public ICredentials Credentials {
58                         get {
59                                 return credentials;
60                         }
61                         set {
62                                 EnsureModifiability ();
63                                 credentials = value;
64                         }
65                 }
66
67                 internal void EnsureModifiability ()
68                 {
69                         if (sentRequest)
70                                 throw new InvalidOperationException (
71                                         "This instance has already started one or more requests. " +
72                                         "Properties can only be modified before sending the first request.");
73                 }
74
75                 // almost identical to ModernHttpClient version but it uses the constants from monotouch.dll | Xamarin.[iOS|WatchOS|TVOS].dll
76                 static Exception createExceptionForNSError(NSError error)
77                 {
78                         var webExceptionStatus = WebExceptionStatus.UnknownError;
79
80                         var innerException = new NSErrorException(error);
81
82                         // errors that exists in both share the same error code, so we can use a single switch/case
83                         // this also ease watchOS integration as if does not expose CFNetwork but (I would not be 
84                         // surprised if it)could return some of it's error codes
85 #if MONOTOUCH_WATCH
86                         if (error.Domain == NSError.NSUrlErrorDomain) {
87 #else
88                         if ((error.Domain == NSError.NSUrlErrorDomain) || (error.Domain == NSError.CFNetworkErrorDomain)) {
89 #endif
90                                 // Parse the enum into a web exception status or exception. Some
91                                 // of these values don't necessarily translate completely to
92                                 // what WebExceptionStatus supports, so made some best guesses
93                                 // here.  For your reading pleasure, compare these:
94                                 //
95                                 // 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
96                                 // .NET docs: http://msdn.microsoft.com/en-us/library/system.net.webexceptionstatus(v=vs.110).aspx
97                                 switch ((NSUrlError) (long) error.Code) {
98                                 case NSUrlError.Cancelled:
99                                 case NSUrlError.UserCancelledAuthentication:
100 #if !MONOTOUCH_WATCH
101                                 case (NSUrlError) NSNetServicesStatus.CancelledError:
102 #endif
103                                         // No more processing is required so just return.
104                                         return new OperationCanceledException(error.LocalizedDescription, innerException);
105                                 case NSUrlError.BadURL:
106                                 case NSUrlError.UnsupportedURL:
107                                 case NSUrlError.CannotConnectToHost:
108                                 case NSUrlError.ResourceUnavailable:
109                                 case NSUrlError.NotConnectedToInternet:
110                                 case NSUrlError.UserAuthenticationRequired:
111                                 case NSUrlError.InternationalRoamingOff:
112                                 case NSUrlError.CallIsActive:
113                                 case NSUrlError.DataNotAllowed:
114 #if !MONOTOUCH_WATCH
115                                 case (NSUrlError) CFNetworkErrors.Socks5BadCredentials:
116                                 case (NSUrlError) CFNetworkErrors.Socks5UnsupportedNegotiationMethod:
117                                 case (NSUrlError) CFNetworkErrors.Socks5NoAcceptableMethod:
118                                 case (NSUrlError) CFNetworkErrors.HttpAuthenticationTypeUnsupported:
119                                 case (NSUrlError) CFNetworkErrors.HttpBadCredentials:
120                                 case (NSUrlError) CFNetworkErrors.HttpBadURL:
121 #endif
122                                         webExceptionStatus = WebExceptionStatus.ConnectFailure;
123                                         break;
124                                 case NSUrlError.TimedOut:
125 #if !MONOTOUCH_WATCH
126                                 case (NSUrlError) CFNetworkErrors.NetServiceTimeout:
127 #endif
128                                         webExceptionStatus = WebExceptionStatus.Timeout;
129                                         break;
130                                 case NSUrlError.CannotFindHost:
131                                 case NSUrlError.DNSLookupFailed:
132 #if !MONOTOUCH_WATCH
133                                 case (NSUrlError) CFNetworkErrors.HostNotFound:
134                                 case (NSUrlError) CFNetworkErrors.NetServiceDnsServiceFailure:
135 #endif
136                                         webExceptionStatus = WebExceptionStatus.NameResolutionFailure;
137                                         break;
138                                 case NSUrlError.DataLengthExceedsMaximum:
139                                         webExceptionStatus = WebExceptionStatus.MessageLengthLimitExceeded;
140                                         break;
141                                 case NSUrlError.NetworkConnectionLost:
142 #if !MONOTOUCH_WATCH
143                                 case (NSUrlError) CFNetworkErrors.HttpConnectionLost:
144 #endif
145                                         webExceptionStatus = WebExceptionStatus.ConnectionClosed;
146                                         break;
147                                 case NSUrlError.HTTPTooManyRedirects:
148                                 case NSUrlError.RedirectToNonExistentLocation:
149 #if !MONOTOUCH_WATCH
150                                 case (NSUrlError) CFNetworkErrors.HttpRedirectionLoopDetected:
151 #endif
152                                         webExceptionStatus = WebExceptionStatus.ProtocolError;
153                                         break;
154                                 case NSUrlError.RequestBodyStreamExhausted:
155 #if !MONOTOUCH_WATCH
156                                 case (NSUrlError) CFNetworkErrors.SocksUnknownClientVersion:
157                                 case (NSUrlError) CFNetworkErrors.SocksUnsupportedServerVersion:
158                                 case (NSUrlError) CFNetworkErrors.HttpParseFailure:
159 #endif
160                                         webExceptionStatus = WebExceptionStatus.SendFailure;
161                                         break;
162                                 case NSUrlError.BadServerResponse:
163                                 case NSUrlError.ZeroByteResource:
164                                 case NSUrlError.CannotDecodeRawData:
165                                 case NSUrlError.CannotDecodeContentData:
166                                 case NSUrlError.CannotParseResponse:
167                                 case NSUrlError.FileDoesNotExist:
168                                 case NSUrlError.FileIsDirectory:
169                                 case NSUrlError.NoPermissionsToReadFile:
170                                 case NSUrlError.CannotLoadFromNetwork:
171                                 case NSUrlError.CannotCreateFile:
172                                 case NSUrlError.CannotOpenFile:
173                                 case NSUrlError.CannotCloseFile:
174                                 case NSUrlError.CannotWriteToFile:
175                                 case NSUrlError.CannotRemoveFile:
176                                 case NSUrlError.CannotMoveFile:
177                                 case NSUrlError.DownloadDecodingFailedMidStream:
178                                 case NSUrlError.DownloadDecodingFailedToComplete:
179 #if !MONOTOUCH_WATCH
180                                 case (NSUrlError) CFNetworkErrors.Socks4RequestFailed:
181                                 case (NSUrlError) CFNetworkErrors.Socks4IdentdFailed:
182                                 case (NSUrlError) CFNetworkErrors.Socks4IdConflict:
183                                 case (NSUrlError) CFNetworkErrors.Socks4UnknownStatusCode:
184                                 case (NSUrlError) CFNetworkErrors.Socks5BadState:
185                                 case (NSUrlError) CFNetworkErrors.Socks5BadResponseAddr:
186                                 case (NSUrlError) CFNetworkErrors.CannotParseCookieFile:
187                                 case (NSUrlError) CFNetworkErrors.NetServiceUnknown:
188                                 case (NSUrlError) CFNetworkErrors.NetServiceCollision:
189                                 case (NSUrlError) CFNetworkErrors.NetServiceNotFound:
190                                 case (NSUrlError) CFNetworkErrors.NetServiceInProgress:
191                                 case (NSUrlError) CFNetworkErrors.NetServiceBadArgument:
192                                 case (NSUrlError) CFNetworkErrors.NetServiceInvalid:
193 #endif
194                                         webExceptionStatus = WebExceptionStatus.ReceiveFailure;
195                                         break;
196                                 case NSUrlError.SecureConnectionFailed:
197                                         webExceptionStatus = WebExceptionStatus.SecureChannelFailure;
198                                         break;
199                                 case NSUrlError.ServerCertificateHasBadDate:
200                                 case NSUrlError.ServerCertificateHasUnknownRoot:
201                                 case NSUrlError.ServerCertificateNotYetValid:
202                                 case NSUrlError.ServerCertificateUntrusted:
203                                 case NSUrlError.ClientCertificateRejected:
204                                 case NSUrlError.ClientCertificateRequired:
205                                         webExceptionStatus = WebExceptionStatus.TrustFailure;
206                                         break;
207 #if !MONOTOUCH_WATCH
208                                 case (NSUrlError) CFNetworkErrors.HttpProxyConnectionFailure:
209                                 case (NSUrlError) CFNetworkErrors.HttpBadProxyCredentials:
210                                 case (NSUrlError) CFNetworkErrors.PacFileError:
211                                 case (NSUrlError) CFNetworkErrors.PacFileAuth:
212                                 case (NSUrlError) CFNetworkErrors.HttpsProxyConnectionFailure:
213                                 case (NSUrlError) CFNetworkErrors.HttpsProxyFailureUnexpectedResponseToConnectMethod:
214                                         webExceptionStatus = WebExceptionStatus.RequestProhibitedByProxy;
215                                         break;
216 #endif
217                                 }
218                         } 
219
220                         // Always create a WebException so that it can be handled by the client.
221                         return new WebException(error.LocalizedDescription, innerException); //, webExceptionStatus, response: null);
222                 }
223         }
224 }