diff options
author | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-03-29 21:27:07 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-29 21:27:07 +0300 |
commit | 15a0b97b1069e0f07c66e0fe875a58597d971201 (patch) | |
tree | 876b258304e42e07d6dddff3b03e5a36c254508c /mcs/class/System.Net.Http | |
parent | 9ebf3a834c47a2d5a73523a6b85c11327dd5adaf (diff) |
[System.Net.Http] Move Mac/iOS specific HttpMessageHandler's to Xamarin.*.dll (#13746)
* Revert "[System.Net.Http] Move NSUrlSessionHandler from xamarin-macios to mono (#13229)"
This reverts commit 5bf74a995465dd54ceb4a2311c2d6041258e8fe0.
* [System.Net.Http] Move Mac/iOS specific HttpMessageHandler's to Xamarin.*.dll
We decided to move these types into Xamarin products since they can't be
used without the underlying infrastructure anyway.
* Bump API snapshot submodule
* [csproj] Update project files
Diffstat (limited to 'mcs/class/System.Net.Http')
16 files changed, 66 insertions, 1829 deletions
diff --git a/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs b/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs index 7cd48a91baa..0e3386fdc81 100644 --- a/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs +++ b/mcs/class/System.Net.Http/Assembly/AssemblyInfo.cs @@ -66,3 +66,9 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo ("System.Net.Http.WebRequest, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] +#if MONOTOUCH || XAMMAC || XAMMAC_4_5 +[assembly: TypeForwardedToAttribute (typeof(System.Net.Http.NSUrlSessionHandler))] +#if !MONOTOUCH_WATCH +[assembly: TypeForwardedToAttribute (typeof(System.Net.Http.CFNetworkHandler))] +#endif +#endif diff --git a/mcs/class/System.Net.Http/CFContentStream.cs b/mcs/class/System.Net.Http/CFContentStream.cs deleted file mode 100644 index d8bba8f0f9a..00000000000 --- a/mcs/class/System.Net.Http/CFContentStream.cs +++ /dev/null @@ -1,156 +0,0 @@ -// -// 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; -using System.Runtime.ExceptionServices; - -#if XAMCORE_4_0 -using CFNetwork; -using CoreFoundation; -#elif XAMCORE_2_0 -using CoreServices; -using CoreFoundation; -#else -using MonoTouch.CoreServices; -using MonoTouch.CoreFoundation; -#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; - ExceptionDispatchInfo http_exception; - - // 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; - this.http_stream.ErrorEvent += HandleErrorEvent; - data = new BufferData () { - Buffer = new byte [4096], - }; - data_event = new AutoResetEvent (false); - data_read_event = new AutoResetEvent (true); - data_mutex = new Mutex (); - } - - void HandleErrorEvent (object sender, CFStream.StreamEventArgs e) - { - var gotMutex = data_mutex.WaitOne (); - if (gotMutex) { - var stream = (CFHTTPStream)sender; - if (e.EventType == CFStreamEventType.ErrorOccurred) - Volatile.Write (ref http_exception, ExceptionDispatchInfo.Capture (stream.GetError ())); - data_mutex.ReleaseMutex (); - } - } - - 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; - this.http_stream.ErrorEvent -= HandleErrorEvent; - data_mutex.ReleaseMutex (); - - data_event.Set (); - } - - protected internal override async Task SerializeToStreamAsync (Stream stream, TransportContext context) - { - while (data_event.WaitOne ()) { - data_mutex.WaitOne (); - if (http_exception != null) { - http_exception.Throw (); - data_mutex.ReleaseMutex (); - break; - } - 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; - } - } -} diff --git a/mcs/class/System.Net.Http/CFNetworkHandler.cs b/mcs/class/System.Net.Http/CFNetworkHandler.cs deleted file mode 100644 index 617d572592c..00000000000 --- a/mcs/class/System.Net.Http/CFNetworkHandler.cs +++ /dev/null @@ -1,389 +0,0 @@ -// -// 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 bool StreamCanBeDisposed; - - public void Close () - { - CancellationTokenRegistration.Dispose (); - if (ContentStream != null) { - // The Close method of the CFContentStream blocks as you can see: - // public void Close () - // { - // data_read_event.WaitOne (); // make sure there's no pending data - // - // data_mutex.WaitOne (); - // data = null; - // this.http_stream.ErrorEvent -= HandleErrorEvent; - // data_mutex.ReleaseMutex (); - // - // data_event.Set (); - // } - // This means. that when we want to ignore the data of the content, which happens - // in the first request of a redirect, if we want to close, ignoring the content - // we will have a deadlock. - // Dispose will clean all the data, without waiting for the read, which by design in the - // CFContentStream, blocks the thread. This happens ONLY after the first request that gets - // a redirect status code. All other cases should call close. - if (StreamCanBeDisposed) - ContentStream.Dispose (); - else - 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 ?? (cookies = new CookieContainer ()); - } - 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) - { - return await SendAsync (request, cancellationToken, true).ConfigureAwait (false); - } - - internal async Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken, bool isFirstRequest) - { - 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); - } - } - - if (!isFirstRequest && allowAutoRedirect) - 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); - }); - - if (isFirstRequest) { - var initialRequest = await response.Task; - var status = initialRequest.StatusCode; - if (IsRedirect (status) && allowAutoRedirect) { - bucket.StreamCanBeDisposed = true; - // remove headers in a redirect for Authentication. - request.Headers.Authorization = null; - return await SendAsync (request, cancellationToken, false).ConfigureAwait (false); - } - return initialRequest; - } - return await response.Task; - } - - // Decide if we redirect or not, similar to what is done in the managed handler - // https://github.com/mono/mono/blob/eca15996c7163f331c9f2cd0a17b63e8f92b1d55/mcs/class/referencesource/System/net/System/Net/HttpWebRequest.cs#L5681 - static bool IsRedirect (HttpStatusCode status) - { - return status == HttpStatusCode.Ambiguous || // 300 - status == HttpStatusCode.Moved || // 301 - status == HttpStatusCode.Redirect || // 302 - status == HttpStatusCode.RedirectMethod || // 303 - status == HttpStatusCode.RedirectKeepVerb; // 307 - } - - 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; - // might not have been called (e.g. no data) but initialize critical data - HandleHasBytesAvailableEvent (sender, e); - CloseStream (stream); - } - - void CloseStream (CFHTTPStream stream) - { - lock (streamBuckets) { - if (streamBuckets.TryGetValue (stream.Handle, out var 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); - } - } - - // cancellation (CancellationTokenRegistration) can happen in parallel - if (!bucket.Response.Task.IsCanceled) { - 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); - } - } -} diff --git a/mcs/class/System.Net.Http/HttpClientEx.cs b/mcs/class/System.Net.Http/HttpClientEx.cs deleted file mode 100644 index fd5621c22e3..00000000000 --- a/mcs/class/System.Net.Http/HttpClientEx.cs +++ /dev/null @@ -1,229 +0,0 @@ -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 () - { -#if MONOTOUCH_WATCH - // There's only one valid handler type for watchOS - return new NSUrlSessionHandler (); -#else - return RuntimeOptions.GetHttpMessageHandler (); -#endif - } - } -#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); - } - } -} diff --git a/mcs/class/System.Net.Http/Makefile b/mcs/class/System.Net.Http/Makefile index 88f80d2e8a2..3eef96a6b2f 100644 --- a/mcs/class/System.Net.Http/Makefile +++ b/mcs/class/System.Net.Http/Makefile @@ -11,20 +11,30 @@ ifeq (monodroid,$(PROFILE)) LIB_MCS_FLAGS += -d:XAMARIN_MODERN endif -ifneq (,$(filter monotouch monotouch_tv monotouch_watch,$(PROFILE))) -LIB_MCS_FLAGS += -D:XAMCORE_2_0 -D:XAMARIN_MODERN -D:SYSTEM_NET_HTTP -D:UNIFIED -D:__UNIFIED__ -endif - ifeq (monotouch,$(PROFILE)) API_BIN_REFS := Xamarin.iOS +LIB_MCS_FLAGS += -d:XAMARIN_MODERN endif ifeq (monotouch_tv,$(PROFILE)) API_BIN_REFS := Xamarin.TVOS +LIB_MCS_FLAGS += -d:XAMARIN_MODERN endif ifeq (monotouch_watch,$(PROFILE)) API_BIN_REFS := Xamarin.WatchOS +LIB_MCS_FLAGS += -d:XAMARIN_MODERN +endif + +ifeq (xammac,$(PROFILE)) +API_BIN_REFS := Xamarin.Mac +LIB_MCS_FLAGS += -d:XAMARIN_MODERN +endif + +ifeq (xammac_net_4_5,$(PROFILE)) +# we can't use API_BIN_REFS for xammac_net_4_5 as it inherits from net_4_x.make +LIB_MCS_FLAGS += -r:$(topdir)/../external/binary-reference-assemblies/build/monotouch/Xamarin.Mac.dll +LIB_MCS_FLAGS += -d:XAMARIN_MODERN endif TEST_LIB_REFS = System System.Core diff --git a/mcs/class/System.Net.Http/NSUrlSessionHandler.cs b/mcs/class/System.Net.Http/NSUrlSessionHandler.cs deleted file mode 100644 index 17835da99f6..00000000000 --- a/mcs/class/System.Net.Http/NSUrlSessionHandler.cs +++ /dev/null @@ -1,896 +0,0 @@ -// -// NSUrlSessionHandler.cs: -// -// Authors: -// Paul Betts <paul@paulbetts.org> -// Nick Berardi <nick@nickberardi.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; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using System.Text; - -#if UNIFIED -using CoreFoundation; -using Foundation; -using Security; -#else -using MonoTouch.CoreFoundation; -using MonoTouch.Foundation; -using MonoTouch.Security; -using System.Globalization; -using nint = System.Int32; -using nuint = System.UInt32; -#endif - -#if !MONOMAC -using UIKit; -#endif - -#if SYSTEM_NET_HTTP -namespace System.Net.Http { -#else -namespace Foundation { -#endif - - // useful extensions for the class in order to set it in a header - static class NSHttpCookieExtensions - { - static void AppendSegment(StringBuilder builder, string name, string value) - { - if (builder.Length > 0) - builder.Append ("; "); - - builder.Append (name); - if (value != null) - builder.Append ("=").Append (value); - } - - // returns the header for a cookie - public static string GetHeaderValue (this NSHttpCookie cookie) - { - var header = new StringBuilder(); - AppendSegment (header, cookie.Name, cookie.Value); - AppendSegment (header, NSHttpCookie.KeyPath.ToString (), cookie.Path.ToString ()); - AppendSegment (header, NSHttpCookie.KeyDomain.ToString (), cookie.Domain.ToString ()); - AppendSegment (header, NSHttpCookie.KeyVersion.ToString (), cookie.Version.ToString ()); - - if (cookie.Comment != null) - AppendSegment (header, NSHttpCookie.KeyComment.ToString (), cookie.Comment.ToString()); - - if (cookie.CommentUrl != null) - AppendSegment (header, NSHttpCookie.KeyCommentUrl.ToString (), cookie.CommentUrl.ToString()); - - if (cookie.Properties.ContainsKey (NSHttpCookie.KeyDiscard)) - AppendSegment (header, NSHttpCookie.KeyDiscard.ToString (), null); - - if (cookie.ExpiresDate != null) { - // Format according to RFC1123; 'r' uses invariant info (DateTimeFormatInfo.InvariantInfo) - var dateStr = ((DateTime) cookie.ExpiresDate).ToUniversalTime ().ToString("r", CultureInfo.InvariantCulture); - AppendSegment (header, NSHttpCookie.KeyExpires.ToString (), dateStr); - } - - if (cookie.Properties.ContainsKey (NSHttpCookie.KeyMaximumAge)) { - var timeStampString = (NSString) cookie.Properties[NSHttpCookie.KeyMaximumAge]; - AppendSegment (header, NSHttpCookie.KeyMaximumAge.ToString (), timeStampString); - } - - if (cookie.IsSecure) - AppendSegment (header, NSHttpCookie.KeySecure.ToString(), null); - - if (cookie.IsHttpOnly) - AppendSegment (header, "httponly", null); // Apple does not show the key for the httponly - - return header.ToString (); - } - } - - public partial class NSUrlSessionHandler : HttpMessageHandler - { - private const string SetCookie = "Set-Cookie"; - readonly Dictionary<string, string> headerSeparators = new Dictionary<string, string> { - ["User-Agent"] = " ", - ["Server"] = " " - }; - - readonly NSUrlSession session; - readonly Dictionary<NSUrlSessionTask, InflightData> inflightRequests; - readonly object inflightRequestsLock = new object (); -#if !MONOMAC && !MONOTOUCH_WATCH - readonly bool isBackgroundSession = false; - NSObject notificationToken; // needed to make sure we do not hang if not using a background session -#endif - - static NSUrlSessionConfiguration CreateConfig () - { - // modifying the configuration does not affect future calls - var config = NSUrlSessionConfiguration.DefaultSessionConfiguration; - // but we want, by default, the timeout from HttpClient to have precedence over the one from NSUrlSession - // Double.MaxValue does not work, so default to 24 hours - config.TimeoutIntervalForRequest = 24 * 60 * 60; - config.TimeoutIntervalForResource = 24 * 60 * 60; - return config; - } - - public NSUrlSessionHandler () : this (CreateConfig ()) - { - } - - [CLSCompliant (false)] - public NSUrlSessionHandler (NSUrlSessionConfiguration configuration) - { - if (configuration == null) - throw new ArgumentNullException (nameof (configuration)); - -#if !MONOMAC && !MONOTOUCH_WATCH - // if the configuration has an identifier, we are dealing with a background session, - // therefore, we do not have to listen to the notifications. - isBackgroundSession = !string.IsNullOrEmpty (configuration.Identifier); -#endif - - AllowAutoRedirect = true; - - // we cannot do a bitmask but we can set the minimum based on ServicePointManager.SecurityProtocol minimum - var sp = ServicePointManager.SecurityProtocol; - if ((sp & SecurityProtocolType.Ssl3) != 0) - configuration.TLSMinimumSupportedProtocol = SslProtocol.Ssl_3_0; - else if ((sp & SecurityProtocolType.Tls) != 0) - configuration.TLSMinimumSupportedProtocol = SslProtocol.Tls_1_0; - else if ((sp & SecurityProtocolType.Tls11) != 0) - configuration.TLSMinimumSupportedProtocol = SslProtocol.Tls_1_1; - else if ((sp & SecurityProtocolType.Tls12) != 0) - configuration.TLSMinimumSupportedProtocol = SslProtocol.Tls_1_2; - - session = NSUrlSession.FromConfiguration (configuration, (INSUrlSessionDelegate) new NSUrlSessionHandlerDelegate (this), null); - inflightRequests = new Dictionary<NSUrlSessionTask, InflightData> (); - } - -#if !MONOMAC && !MONOTOUCH_WATCH - - void AddNotification () - { - if (!isBackgroundSession && notificationToken == null) - notificationToken = NSNotificationCenter.DefaultCenter.AddObserver (UIApplication.WillResignActiveNotification, BackgroundNotificationCb); - } - - void RemoveNotification () - { - if (notificationToken != null) { - NSNotificationCenter.DefaultCenter.RemoveObserver (notificationToken); - notificationToken = null; - } - } - - void BackgroundNotificationCb (NSNotification obj) - { - // we do not need to call the lock, we call cancel on the source, that will trigger all the needed code to - // clean the resources and such - foreach (var r in inflightRequests.Values) { - r.CompletionSource.TrySetCanceled (); - } - } -#endif - - public long MaxInputInMemory { get; set; } = long.MaxValue; - - void RemoveInflightData (NSUrlSessionTask task, bool cancel = true) - { - lock (inflightRequestsLock) { - if (inflightRequests.TryGetValue (task, out var data)) { - if (cancel) - data.CancellationTokenSource.Cancel (); - data.Dispose (); - inflightRequests.Remove (task); - } -#if !MONOMAC && !MONOTOUCH_WATCH - // do we need to be notified? If we have not inflightData, we do not - if (inflightRequests.Count == 0) - RemoveNotification (); -#endif - } - - if (cancel) - task?.Cancel (); - - task?.Dispose (); - } - - protected override void Dispose (bool disposing) - { -#if !MONOMAC && !MONOTOUCH_WATCH - // remove the notification if present, method checks against null - RemoveNotification (); -#endif - lock (inflightRequestsLock) { - foreach (var pair in inflightRequests) { - pair.Key?.Cancel (); - pair.Key?.Dispose (); - pair.Value?.Dispose (); - } - - inflightRequests.Clear (); - } - base.Dispose (disposing); - } - - bool disableCaching; - - public bool DisableCaching { - get { - return disableCaching; - } - set { - EnsureModifiability (); - disableCaching = value; - } - } - - string GetHeaderSeparator (string name) - { - string value; - if (!headerSeparators.TryGetValue (name, out value)) - value = ","; - return value; - } - - async Task<NSUrlRequest> CreateRequest (HttpRequestMessage request) - { - var stream = Stream.Null; - var headers = request.Headers as IEnumerable<KeyValuePair<string, IEnumerable<string>>>; - - if (request.Content != null) { - stream = await request.Content.ReadAsStreamAsync ().ConfigureAwait (false); - headers = System.Linq.Enumerable.ToArray(headers.Union (request.Content.Headers)); - } - - var nsrequest = new NSMutableUrlRequest { - AllowsCellularAccess = true, - CachePolicy = DisableCaching ? NSUrlRequestCachePolicy.ReloadIgnoringCacheData : NSUrlRequestCachePolicy.UseProtocolCachePolicy, - HttpMethod = request.Method.ToString ().ToUpperInvariant (), - Url = NSUrl.FromString (request.RequestUri.AbsoluteUri), - Headers = headers.Aggregate (new NSMutableDictionary (), (acc, x) => { - acc.Add (new NSString (x.Key), new NSString (string.Join (GetHeaderSeparator (x.Key), x.Value))); - return acc; - }) - }; - if (stream != Stream.Null) { - // HttpContent.TryComputeLength is `protected internal` :-( but it's indirectly called by headers - var length = request.Content.Headers.ContentLength; - if (length.HasValue && (length <= MaxInputInMemory)) - nsrequest.Body = NSData.FromStream (stream); - else - nsrequest.BodyStream = new WrappedNSInputStream (stream); - } - return nsrequest; - } - -#if SYSTEM_NET_HTTP || MONOMAC - internal -#endif - protected override async Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken) - { - Volatile.Write (ref sentRequest, true); - - var nsrequest = await CreateRequest (request).ConfigureAwait(false); - var dataTask = session.CreateDataTask (nsrequest); - - var tcs = new TaskCompletionSource<HttpResponseMessage> (); - - lock (inflightRequestsLock) { -#if !MONOMAC && !MONOTOUCH_WATCH - // Add the notification whenever needed - AddNotification (); -#endif - inflightRequests.Add (dataTask, new InflightData { - RequestUrl = request.RequestUri.AbsoluteUri, - CompletionSource = tcs, - CancellationToken = cancellationToken, - CancellationTokenSource = new CancellationTokenSource (), - Stream = new NSUrlSessionDataTaskStream (), - Request = request - }); - } - - if (dataTask.State == NSUrlSessionTaskState.Suspended) - dataTask.Resume (); - - // as per documentation: - // If this token is already in the canceled state, the - // delegate will be run immediately and synchronously. - // Any exception the delegate generates will be - // propagated out of this method call. - // - // The execution of the register ensures that if we - // receive a already cancelled token or it is cancelled - // just before this call, we will cancel the task. - // Other approaches are harder, since querying the state - // of the token does not guarantee that in the next - // execution a threads cancels it. - cancellationToken.Register (() => { - RemoveInflightData (dataTask); - tcs.TrySetCanceled (); - }); - - return await tcs.Task.ConfigureAwait (false); - } - -#if MONOMAC - // Needed since we strip during linking since we're inside a product assembly. - [Preserve (AllMembers = true)] -#endif - partial class NSUrlSessionHandlerDelegate : NSUrlSessionDataDelegate - { - readonly NSUrlSessionHandler sessionHandler; - - public NSUrlSessionHandlerDelegate (NSUrlSessionHandler handler) - { - sessionHandler = handler; - } - - InflightData GetInflightData (NSUrlSessionTask task) - { - var inflight = default (InflightData); - - lock (sessionHandler.inflightRequestsLock) - if (sessionHandler.inflightRequests.TryGetValue (task, out inflight)) { - // ensure that we did not cancel the request, if we did, do cancel the task - if (inflight.CancellationToken.IsCancellationRequested) - task?.Cancel (); - return inflight; - } - - // if we did not manage to get the inflight data, we either got an error or have been canceled, lets cancel the task, that will execute DidCompleteWithError - task?.Cancel (); - return null; - } - - public override void DidReceiveResponse (NSUrlSession session, NSUrlSessionDataTask dataTask, NSUrlResponse response, Action<NSUrlSessionResponseDisposition> completionHandler) - { - var inflight = GetInflightData (dataTask); - - if (inflight == null) - return; - - try { - var urlResponse = (NSHttpUrlResponse)response; - var status = (int)urlResponse.StatusCode; - - var content = new NSUrlSessionDataTaskStreamContent (inflight.Stream, () => { - if (!inflight.Completed) { - dataTask.Cancel (); - } - - inflight.Disposed = true; - inflight.Stream.TrySetException (new ObjectDisposedException ("The content stream was disposed.")); - - sessionHandler.RemoveInflightData (dataTask); - }, inflight.CancellationTokenSource.Token); - - // NB: The double cast is because of a Xamarin compiler bug - var httpResponse = new HttpResponseMessage ((HttpStatusCode)status) { - Content = content, - RequestMessage = inflight.Request - }; - httpResponse.RequestMessage.RequestUri = new Uri (urlResponse.Url.AbsoluteString); - - foreach (var v in urlResponse.AllHeaderFields) { - // NB: Cocoa trolling us so hard by giving us back dummy dictionary entries - if (v.Key == null || v.Value == null) continue; - // NSUrlSession tries to be smart with cookies, we will not use the raw value but the ones provided by the cookie storage - if (v.Key.ToString () == SetCookie) continue; - - httpResponse.Headers.TryAddWithoutValidation (v.Key.ToString (), v.Value.ToString ()); - httpResponse.Content.Headers.TryAddWithoutValidation (v.Key.ToString (), v.Value.ToString ()); - } - - var cookies = session.Configuration.HttpCookieStorage.CookiesForUrl (response.Url); - for (var index = 0; index < cookies.Length; index++) { - httpResponse.Headers.TryAddWithoutValidation (SetCookie, cookies [index].GetHeaderValue ()); - } - - inflight.Response = httpResponse; - - // We don't want to send the response back to the task just yet. Because we want to mimic .NET behavior - // as much as possible. When the response is sent back in .NET, the content stream is ready to read or the - // request has completed, because of this we want to send back the response in DidReceiveData or DidCompleteWithError - if (dataTask.State == NSUrlSessionTaskState.Suspended) - dataTask.Resume (); - - } catch (Exception ex) { - inflight.CompletionSource.TrySetException (ex); - inflight.Stream.TrySetException (ex); - - sessionHandler.RemoveInflightData (dataTask); - } - - completionHandler (NSUrlSessionResponseDisposition.Allow); - } - - public override void DidReceiveData (NSUrlSession session, NSUrlSessionDataTask dataTask, NSData data) - { - var inflight = GetInflightData (dataTask); - - if (inflight == null) - return; - - inflight.Stream.Add (data); - SetResponse (inflight); - } - - public override void DidCompleteWithError (NSUrlSession session, NSUrlSessionTask task, NSError error) - { - var inflight = GetInflightData (task); - - // this can happen if the HTTP request times out and it is removed as part of the cancellation process - if (inflight != null) { - // set the stream as finished - inflight.Stream.TrySetReceivedAllData (); - - // send the error or send the response back - if (error != null) { - // got an error, cancel the stream operatios before we do anything - inflight.CancellationTokenSource.Cancel (); - inflight.Errored = true; - - var exc = createExceptionForNSError (error); - inflight.CompletionSource.TrySetException (exc); - inflight.Stream.TrySetException (exc); - } else { - inflight.Completed = true; - SetResponse (inflight); - } - - sessionHandler.RemoveInflightData (task, cancel: false); - } - } - - void SetResponse (InflightData inflight) - { - lock (inflight.Lock) { - if (inflight.ResponseSent) - return; - - if (inflight.CancellationTokenSource.Token.IsCancellationRequested) - return; - - if (inflight.CompletionSource.Task.IsCompleted) - return; - - var httpResponse = inflight.Response; - - inflight.ResponseSent = true; - - // EVIL HACK: having TrySetResult inline was blocking the request from completing - Task.Run (() => inflight.CompletionSource.TrySetResult (httpResponse)); - } - } - - public override void WillCacheResponse (NSUrlSession session, NSUrlSessionDataTask dataTask, NSCachedUrlResponse proposedResponse, Action<NSCachedUrlResponse> completionHandler) - { - completionHandler (sessionHandler.DisableCaching ? null : proposedResponse); - } - - public override void WillPerformHttpRedirection (NSUrlSession session, NSUrlSessionTask task, NSHttpUrlResponse response, NSUrlRequest newRequest, Action<NSUrlRequest> completionHandler) - { - completionHandler (sessionHandler.AllowAutoRedirect ? newRequest : null); - } - - public override void DidReceiveChallenge (NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler) - { - var inflight = GetInflightData (task); - - if (inflight == null) - return; - - // case for the basic auth failing up front. As per apple documentation: - // The URL Loading System is designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers using - // the addValue(_:forHTTPHeaderField:) or setValue(_:forHTTPHeaderField:) methods: - // Authorization - // Connection - // Host - // Proxy-Authenticate - // Proxy-Authorization - // WWW-Authenticate - // but we are hiding such a situation from our users, we can nevertheless know if the header was added and deal with it. The idea is as follows, - // check if we are in the first attempt, if we are (PreviousFailureCount == 0), we check the headers of the request and if we do have the Auth - // header, it means that we do not have the correct credentials, in any other case just do what it is expected. - - if (challenge.PreviousFailureCount == 0) { - var authHeader = inflight.Request?.Headers?.Authorization; - if (!(string.IsNullOrEmpty (authHeader?.Scheme) && string.IsNullOrEmpty (authHeader?.Parameter))) { - completionHandler (NSUrlSessionAuthChallengeDisposition.RejectProtectionSpace, null); - return; - } - } - - if (sessionHandler.Credentials != null && TryGetAuthenticationType (challenge.ProtectionSpace, out string authType)) { - NetworkCredential credentialsToUse = null; - if (authType != RejectProtectionSpaceAuthType) { - var uri = inflight.Request.RequestUri; - credentialsToUse = sessionHandler.Credentials.GetCredential (uri, authType); - } - - if (credentialsToUse != null) { - var credential = new NSUrlCredential (credentialsToUse.UserName, credentialsToUse.Password, NSUrlCredentialPersistence.ForSession); - completionHandler (NSUrlSessionAuthChallengeDisposition.UseCredential, credential); - } else { - // Rejecting the challenge allows the next authentication method in the request to be delivered to - // the DidReceiveChallenge method. Another authentication method may have credentials available. - completionHandler (NSUrlSessionAuthChallengeDisposition.RejectProtectionSpace, null); - } - } else { - completionHandler (NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, challenge.ProposedCredential); - } - } - - static readonly string RejectProtectionSpaceAuthType = "reject"; - - static bool TryGetAuthenticationType (NSUrlProtectionSpace protectionSpace, out string authenticationType) - { - if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodNTLM) { - authenticationType = "NTLM"; - } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodHTTPBasic) { - authenticationType = "basic"; - } else if (protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodNegotiate || - protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodHTMLForm || - protectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodHTTPDigest) { - // Want to reject this authentication type to allow the next authentication method in the request to - // be used. - authenticationType = RejectProtectionSpaceAuthType; - } else { - // ServerTrust, ClientCertificate or Default. - authenticationType = null; - return false; - } - return true; - } - } - -#if MONOMAC - // Needed since we strip during linking since we're inside a product assembly. - [Preserve (AllMembers = true)] -#endif - class InflightData : IDisposable - { - public readonly object Lock = new object (); - public string RequestUrl { get; set; } - - public TaskCompletionSource<HttpResponseMessage> CompletionSource { get; set; } - public CancellationToken CancellationToken { get; set; } - public CancellationTokenSource CancellationTokenSource { get; set; } - public NSUrlSessionDataTaskStream Stream { get; set; } - public HttpRequestMessage Request { get; set; } - public HttpResponseMessage Response { get; set; } - - public bool ResponseSent { get; set; } - public bool Errored { get; set; } - public bool Disposed { get; set; } - public bool Completed { get; set; } - public bool Done { get { return Errored || Disposed || Completed || CancellationToken.IsCancellationRequested; } } - - public void Dispose() - { - Dispose (true); - GC.SuppressFinalize(this); - } - - // The bulk of the clean-up code is implemented in Dispose(bool) - protected virtual void Dispose (bool disposing) - { - if (disposing) { - if (CancellationTokenSource != null) { - CancellationTokenSource.Dispose (); - CancellationTokenSource = null; - } - } - } - - } - -#if MONOMAC - // Needed since we strip during linking since we're inside a product assembly. - [Preserve (AllMembers = true)] -#endif - class NSUrlSessionDataTaskStreamContent : StreamContent - { - Action disposed; - - public NSUrlSessionDataTaskStreamContent (NSUrlSessionDataTaskStream source, Action onDisposed, CancellationToken token) : base (source, token) - { - disposed = onDisposed; - } - - protected override void Dispose (bool disposing) - { - var action = Interlocked.Exchange (ref disposed, null); - action?.Invoke (); - - base.Dispose (disposing); - } - } - -#if MONOMAC - // Needed since we strip during linking since we're inside a product assembly. - [Preserve (AllMembers = true)] -#endif - class NSUrlSessionDataTaskStream : Stream - { - readonly Queue<NSData> data; - readonly object dataLock = new object (); - - long position; - long length; - - bool receivedAllData; - Exception exc; - - NSData current; - Stream currentStream; - - public NSUrlSessionDataTaskStream () - { - data = new Queue<NSData> (); - } - - public void Add (NSData d) - { - lock (dataLock) { - data.Enqueue (d); - length += (int)d.Length; - } - } - - public void TrySetReceivedAllData () - { - receivedAllData = true; - } - - public void TrySetException (Exception e) - { - exc = e; - TrySetReceivedAllData (); - } - - void ThrowIfNeeded (CancellationToken cancellationToken) - { - if (exc != null) - throw exc; - - cancellationToken.ThrowIfCancellationRequested (); - } - - public override int Read (byte [] buffer, int offset, int count) - { - return ReadAsync (buffer, offset, count).Result; - } - - public override async Task<int> ReadAsync (byte [] buffer, int offset, int count, CancellationToken cancellationToken) - { - // try to throw on enter - ThrowIfNeeded (cancellationToken); - - while (current == null) { - lock (dataLock) { - if (data.Count == 0 && receivedAllData && position == length) - return 0; - - if (data.Count > 0 && current == null) { - current = data.Peek (); - currentStream = current.AsStream (); - break; - } - } - - try { - await Task.Delay (50, cancellationToken).ConfigureAwait (false); - } catch (TaskCanceledException ex) { - // add a nicer exception for the user to catch, add the cancelation exception - // to have a decent stack - throw new TimeoutException ("The request timed out.", ex); - } - } - - // try to throw again before read - ThrowIfNeeded (cancellationToken); - - var d = currentStream; - var bufferCount = Math.Min (count, (int)(d.Length - d.Position)); - var bytesRead = await d.ReadAsync (buffer, offset, bufferCount, cancellationToken).ConfigureAwait (false); - - // add the bytes read from the pointer to the position - position += bytesRead; - - // remove the current primary reference if the current position has reached the end of the bytes - if (d.Position == d.Length) { - lock (dataLock) { - // this is the same object, it was done to make the cleanup - data.Dequeue (); - currentStream?.Dispose (); - // We cannot use current?.Dispose. The reason is the following one: - // In the DidReceiveResponse, if iOS realizes that a buffer can be reused, - // because the data is the same, it will do so. Such a situation does happen - // between requests, that is, request A and request B will get the same NSData - // (buffer) in the delegate. In this case, we cannot dispose the NSData because - // it might be that a different request received it and it is present in - // its NSUrlSessionDataTaskStream stream. We can only trust the gc to do the job - // which is better than copying the data over. - current = null; - currentStream = null; - } - } - - return bytesRead; - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override bool CanTimeout => false; - - public override long Length => length; - - public override void SetLength (long value) - { - throw new InvalidOperationException (); - } - - public override long Position { - get { return position; } - set { throw new InvalidOperationException (); } - } - - public override long Seek (long offset, SeekOrigin origin) - { - throw new InvalidOperationException (); - } - - public override void Flush () - { - throw new InvalidOperationException (); - } - - public override void Write (byte [] buffer, int offset, int count) - { - throw new InvalidOperationException (); - } - } - -#if MONOMAC - // Needed since we strip during linking since we're inside a product assembly. - [Preserve (AllMembers = true)] -#endif - class WrappedNSInputStream : NSInputStream - { - NSStreamStatus status; - CFRunLoopSource source; - readonly Stream stream; - bool notifying; - - public WrappedNSInputStream (Stream inputStream) - { - status = NSStreamStatus.NotOpen; - stream = inputStream; - source = new CFRunLoopSource (Handle); - } - - public override NSStreamStatus Status => status; - - public override void Open () - { - status = NSStreamStatus.Open; - Notify (CFStreamEventType.OpenCompleted); - } - - public override void Close () - { - status = NSStreamStatus.Closed; - } - - public override nint Read (IntPtr buffer, nuint len) - { - var sourceBytes = new byte [len]; - var read = stream.Read (sourceBytes, 0, (int)len); - Marshal.Copy (sourceBytes, 0, buffer, (int)len); - - if (notifying) - return read; - - notifying = true; - if (stream.CanSeek && stream.Position == stream.Length) { - Notify (CFStreamEventType.EndEncountered); - status = NSStreamStatus.AtEnd; - } - notifying = false; - - return read; - } - - public override bool HasBytesAvailable () - { - return true; - } - - protected override bool GetBuffer (out IntPtr buffer, out nuint len) - { - // Just call the base implemention (which will return false) - return base.GetBuffer (out buffer, out len); - } - - // NSInvalidArgumentException Reason: *** -propertyForKey: only defined for abstract class. Define -[System_Net_Http_NSUrlSessionHandler_WrappedNSInputStream propertyForKey:]! - protected override NSObject GetProperty (NSString key) - { - return null; - } - - protected override bool SetProperty (NSObject property, NSString key) - { - return false; - } - - protected override bool SetCFClientFlags (CFStreamEventType inFlags, IntPtr inCallback, IntPtr inContextPtr) - { - // Just call the base implementation, which knows how to handle everything. - return base.SetCFClientFlags (inFlags, inCallback, inContextPtr); - } - - public override void Schedule (NSRunLoop aRunLoop, string mode) - { - var cfRunLoop = aRunLoop.GetCFRunLoop (); - var nsMode = new NSString (mode); - - cfRunLoop.AddSource (source, nsMode); - - if (notifying) - return; - - notifying = true; - Notify (CFStreamEventType.HasBytesAvailable); - notifying = false; - } - - public override void Unschedule (NSRunLoop aRunLoop, string mode) - { - var cfRunLoop = aRunLoop.GetCFRunLoop (); - var nsMode = new NSString (mode); - - cfRunLoop.RemoveSource (source, nsMode); - } - - protected override void Dispose (bool disposing) - { - stream?.Dispose (); - } - } - } -} diff --git a/mcs/class/System.Net.Http/RuntimeOptions.cs b/mcs/class/System.Net.Http/RuntimeOptions.cs deleted file mode 100644 index 6e4c152ca0e..00000000000 --- a/mcs/class/System.Net.Http/RuntimeOptions.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.IO; -using System.Text; -using System.Net.Http; - -#if XAMCORE_2_0 -using Foundation; -using ObjCRuntime; -#elif MONOMAC -using MonoMac.Foundation; -using MonoMac.ObjCRuntime; -#else -#error Unknown platform -#endif - -namespace System.Net.Http { - class RuntimeOptions - { - const string HttpClientHandlerValue = "HttpClientHandler"; - const string CFNetworkHandlerValue = "CFNetworkHandler"; - const string NSUrlSessionHandlerValue = "NSUrlSessionHandler"; - - const string DefaultTlsProviderValue = "default"; - const string LegacyTlsProviderValue = "legacy"; - const string AppleTlsProviderValue = "appletls"; - - string http_message_handler; - - - internal static RuntimeOptions Read () - { - // for iOS NSBundle.ResourcePath returns the path to the root of the app bundle - // for macOS apps NSBundle.ResourcePath returns foo.app/Contents/Resources - // for macOS frameworks NSBundle.ResourcePath returns foo.app/Versions/Current/Resources - Class bundle_finder = new Class (typeof (NSObject.NSObject_Disposer)); - var resource_dir = NSBundle.FromClass (bundle_finder).ResourcePath; - var plist_path = GetFileName (resource_dir); - - if (!File.Exists (plist_path)) - return null; - - using (var plist = NSDictionary.FromFile (plist_path)) { - var options = new RuntimeOptions (); - options.http_message_handler = (NSString) plist ["HttpMessageHandler"]; - return options; - } - } - -#if MONOMAC - [Preserve] -#endif - internal static HttpMessageHandler GetHttpMessageHandler () - { - RuntimeOptions options = null; - - try { - options = RuntimeOptions.Read (); - } catch (FileNotFoundException){ - // this happens on the Mono SDKs since we don't have a real Xamarin.iOS.dll so we can't resolve NSObject - } - - if (options == null) { -#if MONOTOUCH_WATCH - return new NSUrlSessionHandler (); -#else - return new HttpClientHandler (); -#endif - } - - // all types will be present as this is executed only when the linker is not enabled - var handler_name = options.http_message_handler; - var t = Type.GetType (handler_name, false); - - HttpMessageHandler handler = null; - if (t != null) - handler = Activator.CreateInstance (t) as HttpMessageHandler; - if (handler != null) - return handler; -#if MONOTOUCH_WATCH - Console.WriteLine ("{0} is not a valid HttpMessageHandler, defaulting to NSUrlSessionHandler", handler_name); - return new NSUrlSessionHandler (); -#else - Console.WriteLine ("{0} is not a valid HttpMessageHandler, defaulting to System.Net.Http.HttpClientHandler", handler_name); - return new HttpClientHandler (); -#endif - } - - // Use either Create() or Read(). - RuntimeOptions () - { - } - - static string GetFileName (string resource_dir) - { - return Path.Combine (resource_dir, "runtime-options.plist"); - } - } -} diff --git a/mcs/class/System.Net.Http/System.Net.Http.csproj b/mcs/class/System.Net.Http/System.Net.Http.csproj index 911e9419817..3fa5bd74f60 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.csproj +++ b/mcs/class/System.Net.Http/System.Net.Http.csproj @@ -39,17 +39,17 @@ <PropertyGroup Condition=" '$(Platform)' == 'monotouch' "> <OutputPath>./../../class/lib/monotouch</OutputPath> <IntermediateOutputPath>./../../class/obj/$(AssemblyName)-monotouch</IntermediateOutputPath> - <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MOBILE;MOBILE_LEGACY;MONO;MONOTOUCH;DISABLE_REMOTING;DISABLE_COM;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;FULL_AOT_RUNTIME;XAMCORE_2_0;XAMARIN_MODERN;SYSTEM_NET_HTTP;UNIFIED;__UNIFIED__</DefineConstants> + <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MOBILE;MOBILE_LEGACY;MONO;MONOTOUCH;DISABLE_REMOTING;DISABLE_COM;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;FULL_AOT_RUNTIME;XAMARIN_MODERN</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(Platform)' == 'monotouch_watch' "> <OutputPath>./../../class/lib/monotouch_watch</OutputPath> <IntermediateOutputPath>./../../class/obj/$(AssemblyName)-monotouch_watch</IntermediateOutputPath> - <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MOBILE;MOBILE_LEGACY;MONO;MONOTOUCH;DISABLE_REMOTING;DISABLE_COM;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;FULL_AOT_RUNTIME;FEATURE_NO_BSD_SOCKETS;MONOTOUCH_WATCH;XAMCORE_2_0;XAMARIN_MODERN;SYSTEM_NET_HTTP;UNIFIED;__UNIFIED__</DefineConstants> + <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MOBILE;MOBILE_LEGACY;MONO;MONOTOUCH;DISABLE_REMOTING;DISABLE_COM;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;FULL_AOT_RUNTIME;FEATURE_NO_BSD_SOCKETS;MONOTOUCH_WATCH;XAMARIN_MODERN</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(Platform)' == 'monotouch_tv' "> <OutputPath>./../../class/lib/monotouch_tv</OutputPath> <IntermediateOutputPath>./../../class/obj/$(AssemblyName)-monotouch_tv</IntermediateOutputPath> - <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MOBILE;MOBILE_LEGACY;MONO;MONOTOUCH;DISABLE_REMOTING;DISABLE_COM;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;FULL_AOT_RUNTIME;MONOTOUCH_TV;XAMCORE_2_0;XAMARIN_MODERN;SYSTEM_NET_HTTP;UNIFIED;__UNIFIED__</DefineConstants> + <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MOBILE;MOBILE_LEGACY;MONO;MONOTOUCH;DISABLE_REMOTING;DISABLE_COM;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;FULL_AOT_RUNTIME;MONOTOUCH_TV;XAMARIN_MODERN</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(Platform)' == 'testing_aot_full_interp' "> <OutputPath>./../../class/lib/testing_aot_full_interp</OutputPath> @@ -74,12 +74,12 @@ <PropertyGroup Condition=" '$(Platform)' == 'xammac' "> <OutputPath>./../../class/lib/xammac</OutputPath> <IntermediateOutputPath>./../../class/obj/$(AssemblyName)-xammac</IntermediateOutputPath> - <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MONO;MOBILE;MOBILE_DYNAMIC;XAMMAC;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;XAMARIN_MODERN</DefineConstants> + <DefineConstants>NET_1_1;NET_2_0;NET_2_1;NET_3_5;NET_4_0;NET_4_5;MONO;MOBILE;MOBILE_DYNAMIC;XAMMAC;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;XAMARIN_MODERN;XAMARIN_MODERN</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(Platform)' == 'xammac_net_4_5' "> <OutputPath>./../../class/lib/xammac_net_4_5</OutputPath> <IntermediateOutputPath>./../../class/obj/$(AssemblyName)-xammac_net_4_5</IntermediateOutputPath> - <DefineConstants>NET_4_0;NET_4_5;NET_4_6;MONO;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;NO_SYSTEM_DRAWING_DEPENDENCY;NO_WINFORMS_DEPENDENCY;NO_SYSTEM_WEB_DEPENDENCY;XAMMAC_4_5;XAMARIN_MODERN</DefineConstants> + <DefineConstants>NET_4_0;NET_4_5;NET_4_6;MONO;FEATURE_INTERCEPTABLE_THREADPOOL_CALLBACK;NO_SYSTEM_DRAWING_DEPENDENCY;NO_WINFORMS_DEPENDENCY;NO_SYSTEM_WEB_DEPENDENCY;XAMMAC_4_5;XAMARIN_MODERN;XAMARIN_MODERN</DefineConstants> </PropertyGroup> <PropertyGroup Condition=" '$(Platform)' == 'orbis' "> <OutputPath>./../../class/lib/orbis</OutputPath> @@ -164,7 +164,7 @@ <Compile Include="System.Net.Http\DelegatingHandler.cs" /> <Compile Include="System.Net.Http\FormUrlEncodedContent.cs" /> <Compile Include="System.Net.Http\HttpClient.cs" /> - <Compile Include="System.Net.Http\HttpClient.mac.cs" /> + <Compile Include="System.Net.Http\HttpClient.macios.cs" /> <Compile Include="System.Net.Http\HttpCompletionOption.cs" /> <Compile Include="System.Net.Http\HttpContent.cs" /> <Compile Include="System.Net.Http\HttpMessageHandler.cs" /> @@ -873,10 +873,7 @@ </When> <When Condition="'$(Platform)' == 'monotouch_watch'"> <ItemGroup> - <Compile Include="HttpClientEx.cs" /> - <Compile Include="NSUrlSessionHandler.cs" /> <Compile Include="PlatformHelper.Legacy.cs" /> - <Compile Include="RuntimeOptions.cs" /> <Compile Include="System.Net.Http.Headers\AuthenticationHeaderValue.cs" /> <Compile Include="System.Net.Http.Headers\CacheControlHeaderValue.cs" /> <Compile Include="System.Net.Http.Headers\CollectionExtensions.cs" /> @@ -915,6 +912,7 @@ <Compile Include="System.Net.Http\DelegatingHandler.cs" /> <Compile Include="System.Net.Http\FormUrlEncodedContent.cs" /> <Compile Include="System.Net.Http\HttpClient.cs" /> + <Compile Include="System.Net.Http\HttpClient.macios.cs" /> <Compile Include="System.Net.Http\HttpClientHandler.platformnotsupported.cs" /> <Compile Include="System.Net.Http\HttpCompletionOption.cs" /> <Compile Include="System.Net.Http\HttpContent.cs" /> @@ -936,16 +934,11 @@ <ItemGroup> <Compile Include="..\..\..\external\corefx\src\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\CancellationHelper.cs" /> <Compile Include="..\..\..\external\corefx\src\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\ConnectHelper.cs" /> - <Compile Include="CFContentStream.cs" /> - <Compile Include="CFNetworkHandler.cs" /> - <Compile Include="HttpClientEx.cs" /> <Compile Include="HttpClientHandler.Legacy.cs" /> <Compile Include="HttpClientHandler.cs" /> <Compile Include="IMonoHttpClientHandler.cs" /> <Compile Include="MonoWebRequestHandler.cs" /> - <Compile Include="NSUrlSessionHandler.cs" /> <Compile Include="PlatformHelper.Legacy.cs" /> - <Compile Include="RuntimeOptions.cs" /> <Compile Include="System.Net.Http.Headers\AuthenticationHeaderValue.cs" /> <Compile Include="System.Net.Http.Headers\CacheControlHeaderValue.cs" /> <Compile Include="System.Net.Http.Headers\CollectionExtensions.cs" /> @@ -984,6 +977,7 @@ <Compile Include="System.Net.Http\DelegatingHandler.cs" /> <Compile Include="System.Net.Http\FormUrlEncodedContent.cs" /> <Compile Include="System.Net.Http\HttpClient.cs" /> + <Compile Include="System.Net.Http\HttpClient.macios.cs" /> <Compile Include="System.Net.Http\HttpCompletionOption.cs" /> <Compile Include="System.Net.Http\HttpContent.cs" /> <Compile Include="System.Net.Http\HttpMessageHandler.cs" /> @@ -1004,16 +998,11 @@ <ItemGroup> <Compile Include="..\..\..\external\corefx\src\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\CancellationHelper.cs" /> <Compile Include="..\..\..\external\corefx\src\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\ConnectHelper.cs" /> - <Compile Include="CFContentStream.cs" /> - <Compile Include="CFNetworkHandler.cs" /> - <Compile Include="HttpClientEx.cs" /> <Compile Include="HttpClientHandler.Legacy.cs" /> <Compile Include="HttpClientHandler.cs" /> <Compile Include="IMonoHttpClientHandler.cs" /> <Compile Include="MonoWebRequestHandler.cs" /> - <Compile Include="NSUrlSessionHandler.cs" /> <Compile Include="PlatformHelper.Legacy.cs" /> - <Compile Include="RuntimeOptions.cs" /> <Compile Include="System.Net.Http.Headers\AuthenticationHeaderValue.cs" /> <Compile Include="System.Net.Http.Headers\CacheControlHeaderValue.cs" /> <Compile Include="System.Net.Http.Headers\CollectionExtensions.cs" /> @@ -1052,6 +1041,7 @@ <Compile Include="System.Net.Http\DelegatingHandler.cs" /> <Compile Include="System.Net.Http\FormUrlEncodedContent.cs" /> <Compile Include="System.Net.Http\HttpClient.cs" /> + <Compile Include="System.Net.Http\HttpClient.macios.cs" /> <Compile Include="System.Net.Http\HttpCompletionOption.cs" /> <Compile Include="System.Net.Http\HttpContent.cs" /> <Compile Include="System.Net.Http\HttpMessageHandler.cs" /> @@ -1231,6 +1221,20 @@ <Private>False</Private> </Reference> </ItemGroup> + <ItemGroup Condition=" '$(Platform)' == 'xammac' "> + <Reference Include="./../../../external/binary-reference-assemblies/build/monotouch/Xamarin.Mac.dll"> + <SpecificVersion>False</SpecificVersion> + <HintPath>./../../../external/binary-reference-assemblies/build/monotouch/Xamarin.Mac.dll</HintPath> + <Private>False</Private> + </Reference> + </ItemGroup> + <ItemGroup Condition=" '$(Platform)' == 'xammac_net_4_5' "> + <Reference Include="./../../../external/binary-reference-assemblies/build/monotouch/Xamarin.Mac.dll"> + <SpecificVersion>False</SpecificVersion> + <HintPath>./../../../external/binary-reference-assemblies/build/monotouch/Xamarin.Mac.dll</HintPath> + <Private>False</Private> + </Reference> + </ItemGroup> <!-- @ALL_REFERENCES@ --> <!-- @ALL_RESOURCES@ --> <PropertyGroup> diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpClient.mac.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpClient.mac.cs deleted file mode 100644 index 42f664c0ed3..00000000000 --- a/mcs/class/System.Net.Http/System.Net.Http/HttpClient.mac.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Reflection; - -[assembly:System.Runtime.CompilerServices.InternalsVisibleTo ("Xamarin.Mac, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] - -namespace System.Net.Http { - public partial class HttpClient { - - public HttpClient () - : this (GetDefaultHandler (), true) - { - } - - // note: the linker will re-write ObjCRuntime.RuntimeOptions.GetHttpMessageHandler to return the correct type - // unlike, XI where this method itself gets rewritten during linking - static HttpMessageHandler GetDefaultHandler () - { - Type type = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.Mac"); - var method = type.GetMethod ("GetHttpMessageHandler", BindingFlags.Static | BindingFlags.NonPublic); - return (HttpMessageHandler)method.Invoke (null, null); - } - } -} diff --git a/mcs/class/System.Net.Http/System.Net.Http/HttpClient.macios.cs b/mcs/class/System.Net.Http/System.Net.Http/HttpClient.macios.cs new file mode 100644 index 00000000000..a60a7941b23 --- /dev/null +++ b/mcs/class/System.Net.Http/System.Net.Http/HttpClient.macios.cs @@ -0,0 +1,17 @@ +using System; +using System.Reflection; + +namespace System.Net.Http { + public partial class HttpClient { + + public HttpClient () + : this (CreateDefaultHandler ()) + { + } + + static HttpMessageHandler CreateDefaultHandler () + { + return ObjCRuntime.RuntimeOptions.GetHttpMessageHandler (); + } + } +} diff --git a/mcs/class/System.Net.Http/monotouch_System.Net.Http.dll.sources b/mcs/class/System.Net.Http/monotouch_System.Net.Http.dll.sources index 64cdbb68748..f4de7b4ea31 100644 --- a/mcs/class/System.Net.Http/monotouch_System.Net.Http.dll.sources +++ b/mcs/class/System.Net.Http/monotouch_System.Net.Http.dll.sources @@ -1,6 +1,2 @@ #include legacy.sources -CFContentStream.cs -CFNetworkHandler.cs -HttpClientEx.cs -NSUrlSessionHandler.cs -RuntimeOptions.cs +System.Net.Http/HttpClient.macios.cs diff --git a/mcs/class/System.Net.Http/monotouch_runtime_System.Net.Http.dll.sources b/mcs/class/System.Net.Http/monotouch_runtime_System.Net.Http.dll.sources index 704cd9f69ab..f4de7b4ea31 100644 --- a/mcs/class/System.Net.Http/monotouch_runtime_System.Net.Http.dll.sources +++ b/mcs/class/System.Net.Http/monotouch_runtime_System.Net.Http.dll.sources @@ -1 +1,2 @@ #include legacy.sources +System.Net.Http/HttpClient.macios.cs diff --git a/mcs/class/System.Net.Http/monotouch_tv_System.Net.Http.dll.sources b/mcs/class/System.Net.Http/monotouch_tv_System.Net.Http.dll.sources index 64cdbb68748..f4de7b4ea31 100644 --- a/mcs/class/System.Net.Http/monotouch_tv_System.Net.Http.dll.sources +++ b/mcs/class/System.Net.Http/monotouch_tv_System.Net.Http.dll.sources @@ -1,6 +1,2 @@ #include legacy.sources -CFContentStream.cs -CFNetworkHandler.cs -HttpClientEx.cs -NSUrlSessionHandler.cs -RuntimeOptions.cs +System.Net.Http/HttpClient.macios.cs diff --git a/mcs/class/System.Net.Http/monotouch_watch_System.Net.Http.dll.sources b/mcs/class/System.Net.Http/monotouch_watch_System.Net.Http.dll.sources index c8cb6acafb1..8f6e9ebbc19 100644 --- a/mcs/class/System.Net.Http/monotouch_watch_System.Net.Http.dll.sources +++ b/mcs/class/System.Net.Http/monotouch_watch_System.Net.Http.dll.sources @@ -1,5 +1,3 @@ #include legacy.sources System.Net.Http/HttpClientHandler.platformnotsupported.cs -HttpClientEx.cs -NSUrlSessionHandler.cs -RuntimeOptions.cs +System.Net.Http/HttpClient.macios.cs diff --git a/mcs/class/System.Net.Http/xammac_System.Net.Http.dll.sources b/mcs/class/System.Net.Http/xammac_System.Net.Http.dll.sources index c2f4a641674..f4de7b4ea31 100644 --- a/mcs/class/System.Net.Http/xammac_System.Net.Http.dll.sources +++ b/mcs/class/System.Net.Http/xammac_System.Net.Http.dll.sources @@ -1,2 +1,2 @@ #include legacy.sources -System.Net.Http/HttpClient.mac.cs +System.Net.Http/HttpClient.macios.cs diff --git a/mcs/class/System.Net.Http/xammac_net_4_5_System.Net.Http.dll.sources b/mcs/class/System.Net.Http/xammac_net_4_5_System.Net.Http.dll.sources index c2f4a641674..f4de7b4ea31 100644 --- a/mcs/class/System.Net.Http/xammac_net_4_5_System.Net.Http.dll.sources +++ b/mcs/class/System.Net.Http/xammac_net_4_5_System.Net.Http.dll.sources @@ -1,2 +1,2 @@ #include legacy.sources -System.Net.Http/HttpClient.mac.cs +System.Net.Http/HttpClient.macios.cs |