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 // stream.EnableEvents(CF.CFRunLoop.Main, CF.CFRunLoop.ModeCommon); 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; // we do not care about the first stream cbs stream.HasBytesAvailableEvent -= HandleHasBytesAvailableEvent; stream.ErrorEvent -= HandleErrorEvent; stream.ClosedEvent -= HandleClosedEvent; // 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); }
protected internal override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { sentRequest = true; CFHTTPStream stream; using (var message = CreateWebRequestAsync(request)) { if (request.Content != null) { var data = await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false); message.SetBody(data); } stream = CFHTTPStream.CreateForHTTPRequest(message); } if (useSystemProxy) { var proxies = CF.CFNetwork.GetSystemProxySettings(); if (proxies.HTTPEnable) { stream.SetProxy(proxies); } } stream.ShouldAutoredirect = allowAutoRedirect; stream.HasBytesAvailableEvent += HandleHasBytesAvailableEvent; stream.ErrorEvent += HandleErrorEvent; stream.ClosedEvent += HandleClosedEvent; var response = new TaskCompletionSource <HttpResponseMessage> (); if (cancellationToken.IsCancellationRequested) { response.SetCanceled(); return(await response.Task); } var bucket = new StreamBucket() { Request = request, Response = response, }; streamBuckets.Add(stream.Handle, bucket); // // Always schedule stream events handling on main-loop. Due to ConfigureAwait (false) we may end up // on any thread-pool thread which may not have run-loop running // #if XAMCORE_2_0 stream.EnableEvents(CF.CFRunLoop.Main, CF.CFRunLoop.ModeCommon); #else stream.EnableEvents(CF.CFRunLoop.Main, CF.CFRunLoop.CFRunLoopCommonModes); #endif stream.Open(); bucket.CancellationTokenRegistration = cancellationToken.Register(() => { StreamBucket bucket2; if (!streamBuckets.TryGetValue(stream.Handle, out bucket2)) { return; } bucket2.Response.TrySetCanceled(); CloseStream(stream); }); return(await response.Task); }