System.Net.Http.WinHttpResponseParser.CreateResponseMessage C# (CSharp) Méthode

CreateResponseMessage() public static méthode

public static CreateResponseMessage ( WinHttpRequestState state, bool doManualDecompressionCheck ) : HttpResponseMessage
state WinHttpRequestState
doManualDecompressionCheck bool
Résultat HttpResponseMessage
        public static HttpResponseMessage CreateResponseMessage(
            WinHttpRequestState state,
            bool doManualDecompressionCheck)
        {
            HttpRequestMessage request = state.RequestMessage;
            SafeWinHttpHandle requestHandle = state.RequestHandle;
            CookieUsePolicy cookieUsePolicy = state.Handler.CookieUsePolicy;
            CookieContainer cookieContainer = state.Handler.CookieContainer;
            var response = new HttpResponseMessage();
            bool stripEncodingHeaders = false;

            // Create a single buffer to use for all subsequent WinHttpQueryHeaders string interop calls.
            // This buffer is the length needed for WINHTTP_QUERY_RAW_HEADERS_CRLF, which includes the status line
            // and all headers separated by CRLF, so it should be large enough for any individual status line or header queries.
            int bufferLength = GetResponseHeaderCharBufferLength(requestHandle, Interop.WinHttp.WINHTTP_QUERY_RAW_HEADERS_CRLF);
            char[] buffer = ArrayPool<char>.Shared.Rent(bufferLength);
            try
            {
                // Get HTTP version, status code, reason phrase from the response headers.

                if (IsResponseHttp2(requestHandle))
                {
                    response.Version = WinHttpHandler.HttpVersion20;
                }
                else
                {
                    int versionLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_VERSION, buffer);
                    response.Version =
                        CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.1", buffer, 0, versionLength) ? HttpVersionInternal.Version11 :
                        CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase("HTTP/1.0", buffer, 0, versionLength) ? HttpVersionInternal.Version10 :
                        WinHttpHandler.HttpVersionUnknown;
                }

                response.StatusCode = (HttpStatusCode)GetResponseHeaderNumberInfo(
                    requestHandle,
                    Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE);

                int reasonPhraseLength = GetResponseHeader(requestHandle, Interop.WinHttp.WINHTTP_QUERY_STATUS_TEXT, buffer);
                response.ReasonPhrase = reasonPhraseLength > 0 ?
                    GetReasonPhrase(response.StatusCode, buffer, reasonPhraseLength) :
                    string.Empty;

                // Create response stream and wrap it in a StreamContent object.
                var responseStream = new WinHttpResponseStream(requestHandle, state);
                state.RequestHandle = null; // ownership successfully transfered to WinHttpResponseStram.
                Stream decompressedStream = responseStream;

                if (doManualDecompressionCheck)
                {
                    int contentEncodingStartIndex = 0;
                    int contentEncodingLength = GetResponseHeader(
                        requestHandle,
                        Interop.WinHttp.WINHTTP_QUERY_CONTENT_ENCODING,
                        buffer);

                    CharArrayHelpers.Trim(buffer, ref contentEncodingStartIndex, ref contentEncodingLength);

                    if (contentEncodingLength > 0)
                    {
                        if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(
                            EncodingNameGzip, buffer, contentEncodingStartIndex, contentEncodingLength))
                        {
                            decompressedStream = new GZipStream(responseStream, CompressionMode.Decompress);
                            stripEncodingHeaders = true;
                        }
                        else if (CharArrayHelpers.EqualsOrdinalAsciiIgnoreCase(
                            EncodingNameDeflate, buffer, contentEncodingStartIndex, contentEncodingLength))
                        {
                            decompressedStream = new DeflateStream(responseStream, CompressionMode.Decompress);
                            stripEncodingHeaders = true;
                        }
                    }
                }

                response.Content = new NoWriteNoSeekStreamContent(decompressedStream, state.CancellationToken);
                response.RequestMessage = request;

                // Parse raw response headers and place them into response message.
                ParseResponseHeaders(requestHandle, response, buffer, stripEncodingHeaders);

                if (response.RequestMessage.Method != HttpMethod.Head)
                {
                    state.ExpectedBytesToRead = response.Content.Headers.ContentLength;
                }

                return response;
            }
            finally
            {
                ArrayPool<char>.Shared.Return(buffer);
            }
        }

Usage Example

Exemple #1
0
        private async void StartRequest(object obj)
        {
            WinHttpRequestState state           = (WinHttpRequestState)obj;
            bool secureConnection               = false;
            HttpResponseMessage responseMessage = null;
            Exception           savedException  = null;
            SafeWinHttpHandle   connectHandle   = null;

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

            try
            {
                EnsureSessionHandleExists(state);

                SetSessionHandleOptions();

                // Specify an HTTP server.
                connectHandle = Interop.WinHttp.WinHttpConnect(
                    _sessionHandle,
                    state.RequestMessage.RequestUri.Host,
                    (ushort)state.RequestMessage.RequestUri.Port,
                    0);
                ThrowOnInvalidHandle(connectHandle);
                connectHandle.SetParentHandle(_sessionHandle);

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

                // Create an HTTP request handle.
                state.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);
                ThrowOnInvalidHandle(state.RequestHandle);
                state.RequestHandle.SetParentHandle(connectHandle);

                // Set callback function.
                SetStatusCallback(state.RequestHandle, WinHttpRequestCallback.StaticCallbackDelegate);

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

                bool chunkedModeForSend = IsChunkedModeForSend(state.RequestMessage);

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

                uint proxyAuthScheme  = 0;
                uint serverAuthScheme = 0;
                state.RetryRequest = false;

                // The only way to abort pending async operations in WinHTTP is to close the WinHTTP handle.
                // We will detect a cancellation request on the cancellation token by registering a callback.
                // If the callback is invoked, then we begin the abort process by disposing the handle. This
                // will have the side-effect of WinHTTP cancelling any pending I/O and accelerating its callbacks
                // on the handle and thus releasing the awaiting tasks in the loop below. This helps to provide
                // a more timely, cooperative, cancellation pattern.
                using (state.CancellationToken.Register(s => ((WinHttpRequestState)s).RequestHandle.Dispose(), state))
                {
                    do
                    {
                        _authHelper.PreAuthenticateRequest(state, proxyAuthScheme);

                        await InternalSendRequestAsync(state).ConfigureAwait(false);

                        if (state.RequestMessage.Content != null)
                        {
                            await InternalSendRequestBodyAsync(state, chunkedModeForSend).ConfigureAwait(false);
                        }

                        bool receivedResponse = await InternalReceiveResponseHeadersAsync(state).ConfigureAwait(false);

                        if (receivedResponse)
                        {
                            _authHelper.CheckResponseForAuthentication(
                                state,
                                ref proxyAuthScheme,
                                ref serverAuthScheme);
                        }
                    } while (state.RetryRequest);
                }

                state.CancellationToken.ThrowIfCancellationRequested();

                responseMessage = WinHttpResponseParser.CreateResponseMessage(state, _doManualDecompressionCheck);

                // Since the headers have been read, set the "receive" timeout to be based on each read
                // call of the response body data. WINHTTP_OPTION_RECEIVE_TIMEOUT sets a timeout on each
                // lower layer winsock read.
                uint optionData = (uint)_receiveDataTimeout.TotalMilliseconds;
                SetWinHttpOption(state.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_RECEIVE_TIMEOUT, ref optionData);
            }
            catch (Exception ex)
            {
                if (state.SavedException != null)
                {
                    savedException = state.SavedException;
                }
                else
                {
                    savedException = ex;
                }
            }
            finally
            {
                SafeWinHttpHandle.DisposeAndClearHandle(ref connectHandle);
            }

            // Move the main task to a terminal state. This releases any callers of SendAsync() that are awaiting.
            if (responseMessage != null)
            {
                state.Tcs.TrySetResult(responseMessage);
            }
            else
            {
                HandleAsyncException(state, savedException);
            }
        }