Esempio n. 1
0
        private async void StartRequest(object obj)
        {
            RequestState state = (RequestState)obj;
            bool secureConnection = false;
            HttpResponseMessage responseMessage = null;
            Exception savedException = null;
            SafeWinHttpHandle connectHandle = null;
            SafeWinHttpHandle requestHandle = null;
            GCHandle requestStateHandle = new GCHandle();

            if (state.CancellationToken.IsCancellationRequested)
            {
                state.Tcs.TrySetCanceled(state.CancellationToken);
                return;
            }

            try
            {
                // Prepare context object.
                requestStateHandle = GCHandle.Alloc(state);

                EnsureSessionHandleExists(state);

                SetSessionHandleOptions();

                // Specify an HTTP server.
                connectHandle = Interop.WinHttp.WinHttpConnect(
                    _sessionHandle,
                    state.RequestMessage.RequestUri.Host,
                    (ushort)state.RequestMessage.RequestUri.Port,
                    0);
                if (connectHandle.IsInvalid)
                {
                    throw new HttpRequestException(
                        SR.net_http_client_execution_error,
                        WinHttpException.CreateExceptionUsingLastError());
                }
                connectHandle.SetParentHandle(_sessionHandle);

                if (state.RequestMessage.RequestUri.Scheme == UriSchemeHttps)
                {
                    secureConnection = true;
                }
                else
                {
                    secureConnection = false;
                }

                // Create an HTTP request handle.
                requestHandle = Interop.WinHttp.WinHttpOpenRequest(
                    connectHandle,
                    state.RequestMessage.Method.Method,
                    state.RequestMessage.RequestUri.PathAndQuery,
                    null,
                    Interop.WinHttp.WINHTTP_NO_REFERER,
                    Interop.WinHttp.WINHTTP_DEFAULT_ACCEPT_TYPES,
                    secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0);
                if (requestHandle.IsInvalid)
                {
                    throw new HttpRequestException(
                        SR.net_http_client_execution_error,
                        WinHttpException.CreateExceptionUsingLastError());
                }
                requestHandle.SetParentHandle(connectHandle);
                
                state.RequestHandle = requestHandle;

                // Set callback function.
                SetStatusCallback(requestHandle, s_staticCallback);

                // Set needed options on the request handle.
                SetRequestHandleOptions(state);

                bool chunkedModeForSend = IsChunkedModeForSend(state.RequestMessage);

                AddRequestHeaders(
                    requestHandle,
                    state.RequestMessage,
                    _cookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer ? _cookieContainer : null);

                uint proxyAuthScheme = 0;
                uint serverAuthScheme = 0;
                bool retryRequest = false;

                do
                {
                    state.CancellationToken.ThrowIfCancellationRequested();

                    PreAuthenticateRequest(state, requestHandle, proxyAuthScheme);

                    // Send a request.
                    if (!Interop.WinHttp.WinHttpSendRequest(
                        requestHandle,
                        null,
                        0,
                        IntPtr.Zero,
                        0,
                        0,
                        GCHandle.ToIntPtr(requestStateHandle)))
                    {
                        WinHttpException.ThrowExceptionUsingLastError();
                    }

                    // Send request body if present.
                    if (state.RequestMessage.Content != null)
                    {
                        using (var requestStream = new WinHttpRequestStream(requestHandle, chunkedModeForSend))
                        {
                            await state.RequestMessage.Content.CopyToAsync(
                                requestStream,
                                state.TransportContext).ConfigureAwait(false);
                            requestStream.EndUpload();
                        }
                    }

                    state.CancellationToken.ThrowIfCancellationRequested();

                    // End the request and wait for the response.
                    if (!Interop.WinHttp.WinHttpReceiveResponse(requestHandle, IntPtr.Zero))
                    {
                        int lastError = Marshal.GetLastWin32Error();
                        if (lastError == (int)Interop.WinHttp.ERROR_WINHTTP_RESEND_REQUEST)
                        {
                            retryRequest = true;
                        }
                        else if (lastError == (int)Interop.WinHttp.ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED)
                        {
                            // WinHttp will automatically drop any client SSL certificates that we
                            // have pre-set into the request handle.  For security reasons, we don't
                            // allow the certificate to be re-applied. But we need to tell WinHttp
                            // that we don't have any certificate.
                            SetNoClientCertificate(requestHandle);
                            retryRequest = true;
                        }

                        else
                        {
                            throw WinHttpException.CreateExceptionUsingError(lastError);
                        }
                    }
                    else
                    {
                        ProcessResponse(
                            state,
                            requestHandle,
                            ref proxyAuthScheme,
                            ref serverAuthScheme,
                            out retryRequest);
                    }
                } while (retryRequest);

                // Clear callback function in WinHTTP once we have a final response
                // and are ready to create the response message.
                SetStatusCallback(requestHandle, null);

                state.CancellationToken.ThrowIfCancellationRequested();

                // Create HttpResponseMessage object.
                responseMessage = CreateResponseMessage(requestHandle, state.RequestMessage);
            }
            catch (Exception ex)
            {
                if (ex is OperationCanceledException)
                {
                    savedException = ex;
                }
                else if (state.SavedException != null)
                {
                    savedException = state.SavedException;
                }
                else
                {
                    savedException = ex;
                }

                // Clear callback function in WinHTTP to prevent
                // further native callbacks as we clean up the objects.
                if (requestHandle != null)
                {
                    SetStatusCallback(requestHandle, null);
                }
            }

            if (requestStateHandle.IsAllocated)
            {
                requestStateHandle.Free();
            }

            SafeWinHttpHandle.DisposeAndClearHandle(ref connectHandle);

            // Move the task to a terminal state.
            if (responseMessage != null)
            {
                state.Tcs.TrySetResult(responseMessage);
            }
            else
            {
                HandleAsyncException(state, savedException);
            }
        }
Esempio n. 2
0
 private async Task InternalSendRequestBodyAsync(WinHttpRequestState state, bool chunkedModeForSend)
 {
     using (var requestStream = new WinHttpRequestStream(state, chunkedModeForSend))
     {
         await state.RequestMessage.Content.CopyToAsync(
             requestStream,
             state.TransportContext).ConfigureAwait(false);
         await requestStream.EndUploadAsync(state.CancellationToken).ConfigureAwait(false);
     }
 }