Ejemplo n.º 1
0
        /// <summary>
        /// Fills the buffer with the header value and returns the length, or returns 0 if the header isn't found.
        /// </summary>
        private unsafe static int GetResponseHeader(SafeWinHttpHandle requestHandle, uint infoLevel, char[] buffer)
        {
            Debug.Assert(buffer != null, "buffer must not be null.");
            Debug.Assert(buffer.Length > 0, "buffer must not be empty.");

            int  bufferLength = buffer.Length;
            uint index        = 0;

            fixed(char *pBuffer = buffer)
            {
                if (!QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index))
                {
                    int lastError = Marshal.GetLastWin32Error();

                    if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
                    {
                        return(0);
                    }

                    Debug.Assert(lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER, "buffer must be of sufficient size.");

                    throw WinHttpException.CreateExceptionUsingError(lastError);
                }
            }

            return(bufferLength);
        }
Ejemplo n.º 2
0
        public unsafe static bool GetResponseHeader(
            SafeWinHttpHandle requestHandle,
            uint infoLevel,
            ref char[] buffer,
            ref uint index,
            out string headerValue)
        {
            const int StackLimit = 128;

            Debug.Assert(buffer == null || (buffer != null && buffer.Length > StackLimit));

            int  bufferLength;
            uint originalIndex = index;

            if (buffer == null)
            {
                bufferLength = StackLimit;
                char *pBuffer = stackalloc char[bufferLength];
                if (QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index))
                {
                    headerValue = new string(pBuffer, 0, bufferLength);
                    return(true);
                }
            }
            else
            {
                bufferLength = buffer.Length;
                fixed(char *pBuffer = buffer)
                {
                    if (QueryHeaders(requestHandle, infoLevel, pBuffer, ref bufferLength, ref index))
                    {
                        headerValue = new string(pBuffer, 0, bufferLength);
                        return(true);
                    }
                }
            }

            int lastError = Marshal.GetLastWin32Error();

            if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
            {
                headerValue = null;
                return(false);
            }

            if (lastError == Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
            {
                // WinHttpQueryHeaders may advance the index even when it fails due to insufficient buffer,
                // so we set the index back to its original value so we can retry retrieving the same
                // index again with a larger buffer.
                index = originalIndex;

                buffer = new char[bufferLength];
                return(GetResponseHeader(requestHandle, infoLevel, ref buffer, ref index, out headerValue));
            }

            throw WinHttpException.CreateExceptionUsingError(lastError);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns the size of the char array buffer.
        /// </summary>
        private unsafe static int GetResponseHeaderCharBufferLength(SafeWinHttpHandle requestHandle, uint infoLevel)
        {
            char *buffer       = null;
            int   bufferLength = 0;
            uint  index        = 0;

            if (!QueryHeaders(requestHandle, infoLevel, buffer, ref bufferLength, ref index))
            {
                int lastError = Marshal.GetLastWin32Error();

                Debug.Assert(lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND);

                if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
                {
                    throw WinHttpException.CreateExceptionUsingError(lastError);
                }
            }

            return(bufferLength);
        }
Ejemplo n.º 4
0
        public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redirectUri)
        {
            SafeWinHttpHandle requestHandle = state.RequestHandle;

            Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer);

            // Clear cookies.
            if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                    requestHandle,
                    CookieHeaderNameWithColon,
                    (uint)CookieHeaderNameWithColon.Length,
                    Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE))
            {
                int lastError = Marshal.GetLastWin32Error();
                if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
                {
                    throw WinHttpException.CreateExceptionUsingError(lastError);
                }
            }

            // Re-add cookies. The GetCookieHeader() method will return the correct set of
            // cookies based on the redirectUri.
            string cookieHeader = GetCookieHeader(redirectUri, state.Handler.CookieContainer);

            if (!string.IsNullOrEmpty(cookieHeader))
            {
                if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                        requestHandle,
                        cookieHeader,
                        (uint)cookieHeader.Length,
                        Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
                {
                    WinHttpException.ThrowExceptionUsingLastError();
                }
            }
        }
Ejemplo n.º 5
0
        private static void OnRequestError(WinHttpRequestState state, Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult)
        {
            WinHttpTraceHelper.TraceAsyncError("OnRequestError", asyncResult);

            Debug.Assert(state != null, "OnRequestError: state is null");

            Exception innerException = WinHttpException.CreateExceptionUsingError(unchecked ((int)asyncResult.dwError));

            switch (unchecked ((uint)asyncResult.dwResult.ToInt32()))
            {
            case Interop.WinHttp.API_SEND_REQUEST:
                state.TcsSendRequest.TrySetException(innerException);
                break;

            case Interop.WinHttp.API_RECEIVE_RESPONSE:
                if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_RESEND_REQUEST)
                {
                    state.RetryRequest = true;
                    state.TcsReceiveResponseHeaders.TrySetResult(false);
                }
                else if (asyncResult.dwError == 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 including the NULL certificate
                    // (which means we have no certs to send). For security reasons, we don't
                    // allow the certificate to be re-applied. But we need to tell WinHttp
                    // explicitly that we don't have any certificate to send.
                    Debug.Assert(state.RequestHandle != null, "OnRequestError: state.RequestHandle is null");
                    WinHttpHandler.SetNoClientCertificate(state.RequestHandle);
                    state.RetryRequest = true;
                    state.TcsReceiveResponseHeaders.TrySetResult(false);
                }
                else if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
                {
                    state.TcsReceiveResponseHeaders.TrySetCanceled(state.CancellationToken);
                }
                else
                {
                    state.TcsReceiveResponseHeaders.TrySetException(innerException);
                }
                break;

            case Interop.WinHttp.API_QUERY_DATA_AVAILABLE:
                if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
                {
                    // TODO: Issue #2165. We need to pass in the cancellation token from the
                    // user's ReadAsync() call into the TrySetCanceled().
                    Debug.WriteLine("RequestCallback: QUERY_DATA_AVAILABLE - ERROR_WINHTTP_OPERATION_CANCELLED");
                    state.TcsQueryDataAvailable.TrySetCanceled();
                }
                else
                {
                    state.TcsQueryDataAvailable.TrySetException(
                        new IOException("net_http_io_read", innerException));
                }
                break;

            case Interop.WinHttp.API_READ_DATA:
                state.DisposeCtrReadFromResponseStream();

                if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
                {
                    // TODO: Issue #2165. We need to pass in the cancellation token from the
                    // user's ReadAsync() call into the TrySetCanceled().
                    Debug.WriteLine("RequestCallback: API_READ_DATA - ERROR_WINHTTP_OPERATION_CANCELLED");
                    state.TcsReadFromResponseStream.TrySetCanceled();
                }
                else
                {
                    state.TcsReadFromResponseStream.TrySetException(
                        new IOException("net_http_io_read", innerException));
                }
                break;

            case Interop.WinHttp.API_WRITE_DATA:
                if (asyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
                {
                    // TODO: Issue #2165. We need to pass in the cancellation token from the
                    // user's WriteAsync() call into the TrySetCanceled().
                    Debug.WriteLine("RequestCallback: API_WRITE_DATA - ERROR_WINHTTP_OPERATION_CANCELLED");
                    state.TcsInternalWriteDataToRequestStream.TrySetCanceled();
                }
                else
                {
                    state.TcsInternalWriteDataToRequestStream.TrySetException(
                        new IOException("net_http_io_write", innerException));
                }
                break;

            default:
                Debug.Fail(
                    "OnRequestError: Result (" + asyncResult.dwResult + ") is not expected.",
                    "Error code: " + asyncResult.dwError + " (" + innerException.Message + ")");
                break;
            }
        }
Ejemplo n.º 6
0
        private static void OnRequestSendingRequest(WinHttpRequestState state)
        {
            Debug.Assert(state != null, "OnRequestSendingRequest: state is null");
            Debug.Assert(state.RequestHandle != null, "OnRequestSendingRequest: state.RequestHandle is null");

            if (state.RequestMessage.RequestUri.Scheme != UriScheme.Https)
            {
                // Not SSL/TLS.
                return;
            }

            // Grab the channel binding token (CBT) information from the request handle and put it into
            // the TransportContext object.
            state.TransportContext.SetChannelBinding(state.RequestHandle);

            if (state.ServerCertificateValidationCallback != null)
            {
                IntPtr certHandle     = IntPtr.Zero;
                uint   certHandleSize = (uint)IntPtr.Size;

                if (!Interop.WinHttp.WinHttpQueryOption(
                        state.RequestHandle,
                        Interop.WinHttp.WINHTTP_OPTION_SERVER_CERT_CONTEXT,
                        ref certHandle,
                        ref certHandleSize))
                {
                    int lastError = Marshal.GetLastWin32Error();
                    throw WinHttpException.CreateExceptionUsingError(lastError);
                }

                // Create a managed wrapper around the certificate handle. Since this results in duplicating
                // the handle, we will close the original handle after creating the wrapper.
                var serverCertificate = new X509Certificate2(certHandle);
                Interop.Crypt32.CertFreeCertificateContext(certHandle);

                X509Chain       chain = null;
                SslPolicyErrors sslPolicyErrors;

                try
                {
                    WinHttpCertificateHelper.BuildChain(
                        serverCertificate,
                        state.RequestMessage.RequestUri.Host,
                        state.CheckCertificateRevocationList,
                        out chain,
                        out sslPolicyErrors);

                    bool result = state.ServerCertificateValidationCallback(
                        state.RequestMessage,
                        serverCertificate,
                        chain,
                        sslPolicyErrors);
                    if (!result)
                    {
                        throw WinHttpException.CreateExceptionUsingError(
                                  (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE);
                    }
                }
                finally
                {
                    if (chain != null)
                    {
                        chain.Dispose();
                    }

                    serverCertificate.Dispose();
                }
            }
        }