Beispiel #1
0
            public async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                // TODO: ISSUE 31310: Cancellation support

                HttpConnectionResponseContent responseContent = new HttpConnectionResponseContent();

                _response = new HttpResponseMessage()
                {
                    Version = HttpVersion.Version20, RequestMessage = request, Content = responseContent
                };

                // TODO: ISSUE 31312: Expect: 100-continue and early response handling
                // Note that in an "early response" scenario, where we get a response before we've finished sending the request body
                // (either with a 100-continue that timed out, or without 100-continue),
                // we can stop send a RST_STREAM on the request stream and stop sending the request without tearing down the entire connection.

                // TODO: ISSUE 31313: Avoid allocating a TaskCompletionSource repeatedly by using a resettable ValueTaskSource.
                // See: https://github.com/dotnet/corefx/blob/master/src/Common/tests/System/Threading/Tasks/Sources/ManualResetValueTaskSource.cs
                Debug.Assert(_responseDataAvailable == null);
                _responseDataAvailable = new TaskCompletionSource <bool>();
                Task readDataAvailableTask = _responseDataAvailable.Task;

                // Send headers
                await _connection.SendHeadersAsync(_streamId, request).ConfigureAwait(false);

                // Send request body, if any
                if (request.Content != null)
                {
                    using (Http2WriteStream writeStream = new Http2WriteStream(this))
                    {
                        await request.Content.CopyToAsync(writeStream).ConfigureAwait(false);
                    }
                }

                // Wait for response headers to be read.
                await readDataAvailableTask.ConfigureAwait(false);

                // Start to process the response body.
                bool emptyResponse = false;

                lock (_syncObject)
                {
                    if (_responseComplete && _responseBuffer.ActiveSpan.Length == 0)
                    {
                        if (_responseAborted)
                        {
                            throw new IOException(SR.net_http_invalid_response);
                        }

                        emptyResponse = true;
                    }
                }

                if (emptyResponse)
                {
                    responseContent.SetStream(EmptyReadStream.Instance);
                }
                else
                {
                    responseContent.SetStream(new Http2ReadStream(this));
                }

                // Process Set-Cookie headers.
                if (_connection._pool.Settings._useCookies)
                {
                    CookieHelper.ProcessReceivedCookies(_response, _connection._pool.Settings._cookieContainer);
                }

                return(_response);
            }
Beispiel #2
0
        private static HttpResponseMessage ConvertResponse(RTHttpResponseMessage rtResponse)
        {
            HttpResponseMessage response = new HttpResponseMessage((HttpStatusCode)rtResponse.StatusCode);

            response.ReasonPhrase = rtResponse.ReasonPhrase;

            // Version
            if (rtResponse.Version == RTHttpVersion.Http11)
            {
                response.Version = HttpVersionInternal.Version11;
            }
            else if (rtResponse.Version == RTHttpVersion.Http10)
            {
                response.Version = HttpVersionInternal.Version10;
            }
            else if (rtResponse.Version == RTHttpVersion.Http20)
            {
                response.Version = HttpVersionInternal.Version20;
            }
            else
            {
                response.Version = new Version(0, 0);
            }

            bool success;

            // Headers
            foreach (KeyValuePair <string, string> headerPair in rtResponse.Headers)
            {
                if (headerPair.Key.Equals(HttpKnownHeaderNames.SetCookie, StringComparison.OrdinalIgnoreCase))
                {
                    // The Set-Cookie header always comes back with all of the cookies concatenated together.
                    // For example if the response contains the following:
                    //     Set-Cookie A=1
                    //     Set-Cookie B=2
                    // Then we will have a single header KeyValuePair of Key=Set-Cookie, Value=A=1, B=2.
                    // However clients expect these headers to be separated(i.e.
                    // httpResponseMessage.Headers.GetValues("Set-Cookie") should return two cookies not one
                    // concatenated together).
                    success = response.Headers.TryAddWithoutValidation(headerPair.Key, CookieHelper.GetCookiesFromHeader(headerPair.Value));
                }
                else
                {
                    success = response.Headers.TryAddWithoutValidation(headerPair.Key, headerPair.Value);
                }

                Debug.Assert(success);
            }

            // Content
            if (rtResponse.Content != null)
            {
                var rtResponseStream = rtResponse.Content.ReadAsInputStreamAsync().AsTask().Result;
                response.Content = new StreamContent(rtResponseStream.AsStreamForRead());

                foreach (KeyValuePair <string, string> headerPair in rtResponse.Content.Headers)
                {
                    success = response.Content.Headers.TryAddWithoutValidation(headerPair.Key, headerPair.Value);
                    Debug.Assert(success);
                }
            }

            return(response);
        }