HttpClientEx.cs 8.6 KB

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