示例#1
0
    public async Task ExecuteAsync(HttpContext context, HttpConnectionDispatcherOptions options, ConnectionDelegate connectionDelegate)
    {
        // Create the log scope and attempt to pass the Connection ID to it so as many logs as possible contain
        // the Connection ID metadata. If this is the negotiate request then the Connection ID for the scope will
        // be set a little later.

        HttpConnectionContext?connectionContext = null;
        var connectionToken = GetConnectionToken(context);

        if (!StringValues.IsNullOrEmpty(connectionToken))
        {
            // Use ToString; IsNullOrEmpty doesn't tell the compiler anything about implicit conversion to string.
            _manager.TryGetConnection(connectionToken.ToString(), out connectionContext);
        }

        var logScope = new ConnectionLogScope(connectionContext?.ConnectionId);

        using (_logger.BeginScope(logScope))
        {
            if (HttpMethods.IsPost(context.Request.Method))
            {
                // POST /{path}
                await ProcessSend(context);
            }
            else if (HttpMethods.IsGet(context.Request.Method))
            {
                // GET /{path}
                await ExecuteAsync(context, connectionDelegate, options, logScope);
            }
            else if (HttpMethods.IsDelete(context.Request.Method))
            {
                // DELETE /{path}
                await ProcessDeleteAsync(context);
            }
            else
            {
                context.Response.ContentType = "text/plain";
                context.Response.StatusCode  = StatusCodes.Status405MethodNotAllowed;
            }
        }
    }
示例#2
0
        public static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, Uri uri)
        {
            var request = context.Request;

            var requestMessage = new HttpRequestMessage();
            var requestMethod  = request.Method;

            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(request.Body);
                requestMessage.Content = streamContent;
            }

            // Copy the request headers
            foreach (var header in request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            // Append request forwarding headers
            requestMessage.Headers.TryAddWithoutValidation("Via", $"{context.Request.Protocol} Tye");
            requestMessage.Headers.TryAddWithoutValidation("X-Forwarded-Proto", request.Scheme);
            requestMessage.Headers.TryAddWithoutValidation("X-Forwarded-Host", request.Host.ToUriComponent());

            if (context.Connection.RemoteIpAddress != null)
            {
                requestMessage.Headers.TryAddWithoutValidation("X-Forwarded-For", context.Connection.RemoteIpAddress.ToString());
            }

            requestMessage.Headers.Host = uri.Authority;
            requestMessage.RequestUri   = uri;
            requestMessage.Method       = new HttpMethod(request.Method);

            return(requestMessage);
        }
        private static void CopyFromOriginalRequestContentAndHeaders(
            HttpContext context
            , HttpRequestMessage requestMessage
            )
        {
            var requestMethod = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            foreach (var(key, value) in context.Request.Headers)
            {
                requestMessage.Content?.Headers.TryAddWithoutValidation(key, value.ToArray());
            }
        }
示例#4
0
        /// <summary>
        /// Copy the http headers and body content from origin request into destination request.
        /// </summary>
        /// <param name="context">The Http Context that contains the origin request</param>
        /// <param name="requestMessage">The destination Http Request Message</param>
        private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
        {
            var requestMethod = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
                requestMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(context.Request.ContentType);
            }

            foreach (var header in context.Request.Headers)
            {
                requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
            }

            requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(StaticValues.AUTHENTICATION_SCHEME, _options.ApiKey);
        }
示例#5
0
        private static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, string uriString)
        {
            var uri     = new Uri(uriString);
            var request = context.Request;

            var requestMessage = new HttpRequestMessage();
            var requestMethod  = request.Method;

            // Copy the request headers.
            foreach (var header in request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()))
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                if (request.HasFormContentType)
                {
                    var formFields = request.Form.ToDictionary(x => x.Key, x => x.Value.ToString());
                    requestMessage.Content = new FormUrlEncodedContent(formFields);
                }
                else
                {
                    var streamContent = new StreamContent(request.Body);
                    requestMessage.Content = streamContent;
                }
            }

            requestMessage.Headers.Host = uri.Authority;
            requestMessage.RequestUri   = uri;
            requestMessage.Method       = new HttpMethod(request.Method);

            return(requestMessage);
        }
示例#6
0
        internal static HttpRequestMessage CreateProxiedHttpRequest(this HttpContext context, string uriString, bool shouldAddForwardedHeaders)
        {
            var uri     = new Uri(uriString);
            var request = context.Request;

            var requestMessage = new HttpRequestMessage();
            var requestMethod  = request.Method;

            // Write to request content, when necessary.
            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(request.Body);
                requestMessage.Content = streamContent;
            }

            // Copy the request headers.
            foreach (var header in context.Request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()))
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            // Add forwarded headers.
            if (shouldAddForwardedHeaders)
            {
                AddForwardedHeadersToRequest(context, requestMessage);
            }

            // Set destination and method.
            requestMessage.Headers.Host = uri.Authority;
            requestMessage.RequestUri   = uri;
            requestMessage.Method       = new HttpMethod(request.Method);

            return(requestMessage);
        }
示例#7
0
        private static Method GetMethod(string method)
        {
            if (HttpMethods.IsDelete(method))
            {
                return(Method.DELETE);
            }

            if (HttpMethods.IsGet(method))
            {
                return(Method.GET);
            }

            if (HttpMethods.IsHead(method))
            {
                return(Method.HEAD);
            }

            if (HttpMethods.IsOptions(method))
            {
                return(Method.OPTIONS);
            }

            if (HttpMethods.IsPatch(method))
            {
                return(Method.PATCH);
            }

            if (HttpMethods.IsPost(method))
            {
                return(Method.POST);
            }

            if (HttpMethods.IsPut(method))
            {
                return(Method.PUT);
            }

            throw new NotSupportedException($"Http Method {method} is not supported in {typeof(Method)}.");
        }
示例#8
0
        private static HttpMethod GetMethod(string method)
        {
            if (HttpMethods.IsDelete(method))
            {
                return(HttpMethod.Delete);
            }
            if (HttpMethods.IsGet(method))
            {
                return(HttpMethod.Get);
            }
            if (HttpMethods.IsPost(method))
            {
                return(HttpMethod.Post);
            }
            if (HttpMethods.IsPut(method))
            {
                return(HttpMethod.Put);
            }

            return(new HttpMethod(method));
            //throw new Exception
        }
        /// <summary>
        /// Gets the required scope.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private string GetRequiredScope(HttpContext context)
        {
            var method             = context.Request.Method;
            var ressourceRequested = context.Request.Path.Value.Split('/')[2];

            if (HttpMethods.IsGet(method))
            {
                return($"read:{ressourceRequested}");
            }
            if (HttpMethods.IsPost(method))
            {
                return($"create:{ressourceRequested}");
            }
            if (HttpMethods.IsPut(method))
            {
                return($"update:{ressourceRequested}");
            }
            if (HttpMethods.IsDelete(method))
            {
                return($"delete:{ressourceRequested}");
            }
            return(String.Empty);
        }
        private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
        {
            var requestMethod = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            foreach (var header in context.Request.Headers)
            {
                if (header.Value.Contains("x-forwarded"))
                {
                    break;
                }

                requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
            }
        }
示例#11
0
 private static HttpMethod GetHttpMethod(string method, out bool?hasBody)
 {
     if (HttpMethods.IsDelete(method))
     {
         hasBody = null; return(HttpMethod.Delete);
     }
     else if (HttpMethods.IsGet(method))
     {
         hasBody = false; return(HttpMethod.Get);
     }
     else if (HttpMethods.IsHead(method))
     {
         hasBody = false; return(HttpMethod.Head);
     }
     else if (HttpMethods.IsOptions(method))
     {
         hasBody = null; return(HttpMethod.Options);
     }
     else if (HttpMethods.IsPost(method))
     {
         hasBody = true; return(HttpMethod.Post);
     }
     else if (HttpMethods.IsPut(method))
     {
         hasBody = true; return(HttpMethod.Put);
     }
     else if (HttpMethods.IsPatch(method))
     {
         hasBody = true; return(HttpMethod.Patch);
     }
     else if (HttpMethods.IsTrace(method))
     {
         hasBody = null; return(HttpMethod.Trace);
     }
     hasBody = null;
     return(new HttpMethod(method));
 }
示例#12
0
        protected virtual HttpVerbs GetVerb(HttpRequest request)
        {
            if (HttpMethods.IsGet(request.Method))
            {
                return(HttpVerbs.Get);
            }

            if (HttpMethods.IsPost(request.Method))
            {
                return(HttpVerbs.Post);
            }

            if (HttpMethods.IsPut(request.Method))
            {
                return(HttpVerbs.Put);
            }

            if (HttpMethods.IsDelete(request.Method))
            {
                return(HttpVerbs.Delete);
            }

            return(HttpVerbs.None);
        }
示例#13
0
        private static HttpRequestMessage CreateProxyHttpRequest(HttpContext context, Uri uri)
        {
            var request = context.Request;

            var requestMessage = new HttpRequestMessage();
            var requestMethod  = request.Method;

            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(request.Body);
                requestMessage.Content = streamContent;
            }

            // Copy the request headers
            foreach (var header in request.Headers)
            {
                if (NotForwardedHttpHeaders.Contains(header.Key, StringComparer.OrdinalIgnoreCase))
                {
                    continue;
                }

                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            requestMessage.Headers.Host = uri.Authority;
            requestMessage.RequestUri   = uri;
            requestMessage.Method       = new HttpMethod(request.Method);

            return(requestMessage);
        }
示例#14
0
        /// <summary>
        /// Creates a device request based on the incoming HTTP request.
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task <DeviceRequest> CreateRequestAsync(string deviceId, HttpRequest request)
        {
            // discard any body that could have been provided when doing GET or DELETE requests
            if (HttpMethods.IsGet(request.Method) || HttpMethods.IsDelete(request.Method))
            {
                return(new DeviceInlineRequest(request));
            }

            // determine whether the request body needs to be written to file storage or sent inline to the device.
            // a more accurate check could be done against the serialized DeviceRequest instead of the current request.ContentLength since additional info is added to the payload later on.
            // that would still not be perfectly accurate since the SDK adds its own data to the final payload.
            if (request.HasFormContentType || request.ContentLength.GetValueOrDefault() > m_DeviceCommunicationAdapter.GetMaximumMessageSize())
            {
                var fileData = new BlobStreamDecorator(request.Body)
                {
                    ContentType = request.ContentType
                };
                string blobSasUrl = await m_FileService.WriteFileAsync(deviceId, fileData);

                return(new DeviceFileRequest(request)
                {
                    BlobUrl = blobSasUrl
                });
            }
            else
            {
                var inlineRequest = new DeviceInlineRequest(request);

                using (StreamReader reader = new StreamReader(request.Body, inlineRequest.Headers.GetEncoding()))
                {
                    inlineRequest.Body = await reader.ReadToEndAsync();
                }

                return(inlineRequest);
            }
        }
示例#15
0
        public async Task ExecuteAsync(HttpContext context, HttpConnectionDispatcherOptions options, ConnectionDelegate connectionDelegate)
        {
            // Create the log scope and attempt to pass the Connection ID to it so as many logs as possible contain
            // the Connection ID metadata. If this is the negotiate request then the Connection ID for the scope will
            // be set a little later.
            var logScope = new ConnectionLogScope(GetConnectionId(context));

            using (_logger.BeginScope(logScope))
            {
                if (!await AuthorizeHelper.AuthorizeAsync(context, options.AuthorizationData))
                {
                    return;
                }

                if (HttpMethods.IsPost(context.Request.Method))
                {
                    // POST /{path}
                    await ProcessSend(context, options);
                }
                else if (HttpMethods.IsGet(context.Request.Method))
                {
                    // GET /{path}
                    await ExecuteAsync(context, connectionDelegate, options, logScope);
                }
                else if (HttpMethods.IsDelete(context.Request.Method))
                {
                    // DELETE /{path}
                    await ProcessDeleteAsync(context);
                }
                else
                {
                    context.Response.ContentType = "text/plain";
                    context.Response.StatusCode  = StatusCodes.Status405MethodNotAllowed;
                }
            }
        }
示例#16
0
        private static void CopyRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
        {
            var requestMethod = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) &&
                !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) &&
                !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            foreach (var header in context.Request.Headers)
            {
                if (!NotForwardedHttpHeaders.Contains(header.Key))
                {
                    if (header.Key != "User-Agent")
                    {
                        if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                        {
                            requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                        }
                    }
                    else
                    {
                        string userAgent = header.Value.Count > 0 ? (header.Value[0] + " " + context.TraceIdentifier) : string.Empty;

                        if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, userAgent) && requestMessage.Content != null)
                        {
                            requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, userAgent);
                        }
                    }
                }
            }
        }
示例#17
0
        public async Task Invoke(HttpContext httpContext)
        {
            Program.GoToLegacy = !Program.GoToLegacy;

            if (Program.GoToLegacy)
            {
                var request = httpContext.Request;

                var path = request.Path;
                var uri  = new Uri($"http://localhost:5555{path.Value}");

                var requestMessage = new HttpRequestMessage();
                var requestMethod  = request.Method;
                if (!HttpMethods.IsGet(requestMethod) &&
                    !HttpMethods.IsHead(requestMethod) &&
                    !HttpMethods.IsDelete(requestMethod) &&
                    !HttpMethods.IsTrace(requestMethod))
                {
                    var streamContent = new StreamContent(request.Body);
                    requestMessage.Content = streamContent;
                }

                // copy headers
                foreach (var header in request.Headers)
                {
                    if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                    {
                        requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                    }
                }

                requestMessage.Headers.Host = uri.Authority;
                requestMessage.RequestUri   = uri;
                requestMessage.Method       = new HttpMethod(request.Method);

                var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, httpContext.RequestAborted);

                var response = httpContext.Response;
                response.StatusCode = (int)responseMessage.StatusCode;
                foreach (var header in responseMessage.Headers)
                {
                    response.Headers[header.Key] = header.Value.ToArray();
                }

                foreach (var header in responseMessage.Content.Headers)
                {
                    response.Headers[header.Key] = header.Value.ToArray();
                }

                // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
                response.Headers.Remove("transfer-encoding");

                await using var responseStream = await responseMessage.Content.ReadAsStreamAsync();

                await responseStream.CopyToAsync(response.Body, 81920, httpContext.RequestAborted);
            }
            else
            {
                await _next(httpContext);
            }
        }
示例#18
0
        public async Task Invoke(HttpContext context, IRedisManager redisManager)
        {
            try
            {
                var requestMessage = new HttpRequestMessage();
                var requestMethod  = context.Request.Method;

                if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod))
                {
                    var streamContent = new StreamContent(context.Request.Body);
                    requestMessage.Content = streamContent;
                }

                // All request headers and cookies must be transferend to remote server. Some headers will be skipped
                foreach (var header in context.Request.Headers)
                {
                    if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                    {
                        requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                    }
                }

                string uriString = GetUri(context, redisManager);

                //recreate remote url
                requestMessage.RequestUri = new Uri(uriString);
                requestMessage.Method     = new HttpMethod(context.Request.Method);
                var responseMessage = await redisManager.GetConnection().SendAsync(requestMessage);


                context.Response.StatusCode = (int)responseMessage.StatusCode;
                foreach (var header in responseMessage.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                foreach (var header in responseMessage.Content.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }


                //tell to the browser that response is not chunked
                //context.Response.Headers.Remove("transfer-encoding");
                await responseMessage.Content.CopyToAsync(context.Response.Body);
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.Message);
            }
        }
示例#19
0
        private StreamCopyHttpContent SetupRequestBodyCopy(HttpRequest request, bool isStreamingRequest, CancellationToken cancellation)
        {
            // If we generate an HttpContent without a Content-Length then for HTTP/1.1 HttpClient will add a Transfer-Encoding: chunked header
            // even if it's a GET request. Some servers reject requests containing a Transfer-Encoding header if they're not expecting a body.
            // Try to be as specific as possible about the client's intent to send a body. The one thing we don't want to do is to start
            // reading the body early because that has side-effects like 100-continue.
            var hasBody       = true;
            var contentLength = request.Headers.ContentLength;
            var method        = request.Method;

#if NET
            var canHaveBodyFeature = request.HttpContext.Features.Get <IHttpRequestBodyDetectionFeature>();
            if (canHaveBodyFeature != null)
            {
                // 5.0 servers provide a definitive answer for us.
                hasBody = canHaveBodyFeature.CanHaveBody;
            }
            else
#endif
            // https://tools.ietf.org/html/rfc7230#section-3.3.3
            // All HTTP/1.1 requests should have Transfer-Encoding or Content-Length.
            // Http.Sys/IIS will even add a Transfer-Encoding header to HTTP/2 requests with bodies for back-compat.
            // HTTP/1.0 Connection: close bodies are only allowed on responses, not requests.
            // https://tools.ietf.org/html/rfc1945#section-7.2.2
            //
            // Transfer-Encoding overrides Content-Length per spec
            if (request.Headers.TryGetValue(HeaderNames.TransferEncoding, out var transferEncoding) &&
                transferEncoding.Count == 1 &&
                string.Equals("chunked", transferEncoding.ToString(), StringComparison.OrdinalIgnoreCase))
            {
                hasBody = true;
            }
            else if (contentLength.HasValue)
            {
                hasBody = contentLength > 0;
            }
            // Kestrel HTTP/2: There are no required headers that indicate if there is a request body so we need to sniff other fields.
            else if (!ProtocolHelper.IsHttp2OrGreater(request.Protocol))
            {
                hasBody = false;
            }
            // https://tools.ietf.org/html/rfc7231#section-4.3.1
            // A payload within a GET/HEAD/DELETE/CONNECT request message has no defined semantics; sending a payload body on a
            // GET/HEAD/DELETE/CONNECT request might cause some existing implementations to reject the request.
            // https://tools.ietf.org/html/rfc7231#section-4.3.8
            // A client MUST NOT send a message body in a TRACE request.
            else if (HttpMethods.IsGet(method) ||
                     HttpMethods.IsHead(method) ||
                     HttpMethods.IsDelete(method) ||
                     HttpMethods.IsConnect(method) ||
                     HttpMethods.IsTrace(method))
            {
                hasBody = false;
            }
            // else hasBody defaults to true

            StreamCopyHttpContent requestContent = null;
            if (hasBody)
            {
                if (isStreamingRequest)
                {
                    DisableMinRequestBodyDataRateAndMaxRequestBodySize(request.HttpContext);
                }

                // Note on `autoFlushHttpClientOutgoingStream: isStreamingRequest`:
                // The.NET Core HttpClient stack keeps its own buffers on top of the underlying outgoing connection socket.
                // We flush those buffers down to the socket on every write when this is set,
                // but it does NOT result in calls to flush on the underlying socket.
                // This is necessary because we proxy http2 transparently,
                // and we are deliberately unaware of packet structure used e.g. in gRPC duplex channels.
                // Because the sockets aren't flushed, the perf impact of this choice is expected to be small.
                // Future: It may be wise to set this to true for *all* http2 incoming requests,
                // but for now, out of an abundance of caution, we only do it for requests that look like gRPC.
                requestContent = new StreamCopyHttpContent(
                    source: request.Body,
                    autoFlushHttpClientOutgoingStream: isStreamingRequest,
                    clock: _clock,
                    cancellation: cancellation);
            }

            return(requestContent);
        }
        protected virtual async Task ProxyRequestAsync(HttpContext context, string serviceHost)
        {
            using (var requestMessage = new HttpRequestMessage())
            {
                var requestMethod = context.Request.Method;
                if (!HttpMethods.IsGet(requestMethod) &&
                    !HttpMethods.IsHead(requestMethod) &&
                    !HttpMethods.IsDelete(requestMethod) &&
                    !HttpMethods.IsTrace(requestMethod))
                {
                    var streamContent = new StreamContent(context.Request.Body);
                    requestMessage.Content = streamContent;
                }

                var xForwardedForHeaderValues = new List <string>();

                // copy the request headers
                foreach (var header in context.Request.Headers)
                {
                    if (string.Equals(header.Key, XForwardedForHeaderKey, StringComparison.OrdinalIgnoreCase))
                    {
                        xForwardedForHeaderValues = header.Value.ToList();
                        continue;
                    }

                    if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()))
                    {
                        requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                    }
                }

                // add remote ip address to x-forwarded-for header
                xForwardedForHeaderValues.Add(context.Connection.RemoteIpAddress.ToString());
                requestMessage.Headers.TryAddWithoutValidation(XForwardedForHeaderKey, xForwardedForHeaderValues);

                var requestUri = new Uri($"{context.Request.Scheme}://{serviceHost}{context.Request.Path}{context.Request.QueryString}");
                requestMessage.Headers.Host = requestUri.Authority;
                requestMessage.RequestUri   = requestUri;
                requestMessage.Method       = new HttpMethod(requestMethod);

                _logger.LogInformation($"ProxyRequestAsync RequestUri: {requestUri}");

                var httpClient = _httpClientFactory.CreateClient(nameof(ReverseProxyMiddleware));
                using (var responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
                {
                    context.Response.StatusCode = (int)responseMessage.StatusCode;

                    foreach (var header in responseMessage.Headers)
                    {
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    foreach (var header in responseMessage.Content.Headers)
                    {
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
                    context.Response.Headers.Remove("transfer-encoding");

                    await responseMessage.Content.CopyToAsync(context.Response.Body);
                }
            }
        }
        private async Task HandleHttpRequest(HttpContext context)
        {
            PathString path = context.Request.Path;

            if (path.ToString().Contains("lfs"))
            {
                await this.next(context);

                return;
            }

            var matchCriteria = new Regex("/api/([0-9]+)/([a-zA-Z0-9-\\.]*/?.*)");

            Match match = matchCriteria.Match(context.Request.Path.ToString());

            if (match.Success == false)
            {
                await this.next(context);

                return;
            }

            var dbContext = context.RequestServices.GetService <ApplicationDbContext>();

            if (int.TryParse(match.Groups[1].Value, out int hostIndex) == false)
            {
                await this.next(context);

                return;
            }

            GitHost gitHost = await dbContext.GitHost.SingleOrDefaultAsync(x => x.Id == hostIndex);

            if (gitHost == null)
            {
                await this.next(context);

                return;
            }

            var    requestMessage = new HttpRequestMessage();
            string requestMethod  = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            // Copy the request headers
            foreach (KeyValuePair <string, StringValues> header in context.Request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) &&
                    requestMessage.Content != null)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            string newPath = match.Groups[2].Value;

            var uri = new Uri($"{gitHost.Href}/{context.Request.PathBase}{newPath}{context.Request.QueryString}");

            requestMessage.Headers.Host = uri.Host;
            requestMessage.RequestUri   = uri;
            requestMessage.Method       = new HttpMethod(context.Request.Method);
            using (HttpResponseMessage responseMessage = await this.httpClient.SendAsync(
                       requestMessage,
                       HttpCompletionOption.ResponseHeadersRead,
                       context.RequestAborted))
            {
                context.Response.StatusCode = (int)responseMessage.StatusCode;
                foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Content.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
                context.Response.Headers.Remove("transfer-encoding");
                await responseMessage.Content.CopyToAsync(context.Response.Body);
            }
        }
示例#22
0
        /// <summary>
        /// Excludes a mapped path, optionally based on the given HTTP method. If HTTP method is not specified, every request to this path will not be used by <see cref="HttpSignatureMiddleware"/>.
        /// </summary>
        /// <param name="pathString">The path to exclude.</param>
        /// <param name="httpMethods">The HTTP methods to exclude for the given path.</param>
        public HttpSignatureOptions IgnorePath(PathString pathString, params string[] httpMethods)
        {
            if (pathString == null)
            {
                throw new ArgumentNullException(nameof(pathString), "Cannot ignore a null path.");
            }
            var path = pathString.Value.EnsureLeadingSlash().ToTemplatedDynamicPath();

            // No HTTP methods specified, so exclude just the path (implies that all HTTP methods will be excluded for this path).
            if (httpMethods?.Length == 0)
            {
                IgnoredPaths.Add(path, "*");
                return(this);
            }
            // Validate HTTP method.
            // There are more of course, but this seems enough for our needs.
            foreach (var method in httpMethods)
            {
                var isValidHttpMethod = HttpMethods.IsGet(method) || HttpMethods.IsPost(method) || HttpMethods.IsPut(method) || HttpMethods.IsDelete(method) || HttpMethods.IsPatch(method);
                if (!isValidHttpMethod)
                {
                    throw new ArgumentException($"HTTP method {method} is not valid.");
                }
            }
            if (!IgnoredPaths.ContainsKey(path))
            {
                IgnoredPaths.Add(path, string.Join('|', httpMethods));
            }
            else
            {
                var methods = IgnoredPaths[path].Split('|').Union(httpMethods);
                IgnoredPaths[path] = string.Join('|', methods);
            }
            return(this);
        }
示例#23
0
        protected override async Task <bool> ProcessInternal(HttpContext context, CancellationToken ct)
        {
            var request = context.Request;

            PathString partialPath;

            if (!request.Path.StartsWithSegments(_options.Value.MountPoint, out partialPath))
            {
                return(false);
            }

            var pathSegments = partialPath.Value?.Split('/').Where(x => !x.Trim().IsNullOrEmpty()).ToArray();

            if (pathSegments == null || pathSegments.Length < 2)
            {
                return(false);
            }

            var model = await MetaService.GetModel(pathSegments[0], ct);

            pathSegments = pathSegments.Skip(1).ToArray();

            var headers            = context.Request.GetTypedHeaders();
            var requestSerializer  = _serializerFactory.GetByMediaType(headers.ContentType?.MediaType);
            var responseSerializer = headers.Accept.IsNullOrEmpty()
                                ? requestSerializer
                                : _serializerFactory.GetByMediaType(headers.Accept.Safe().Select(x => x.MediaType));
            var processParams = new RestProcessParameters(context, headers, pathSegments, model, requestSerializer,
                                                          responseSerializer);

            if (HttpMethods.IsGet(request.Method))
            {
                await ProcessQuery(processParams, ct);

                return(true);
            }

            if (HttpMethods.IsPost(request.Method))
            {
                await ProcessPostCommand(processParams, ct);

                return(true);
            }

            if (HttpMethods.IsPut(request.Method))
            {
                await ProcessPutCommand(processParams, ct);

                return(true);
            }

            if (HttpMethods.IsPatch(request.Method))
            {
                await ProcessPatchCommand(processParams, ct);

                return(true);
            }

            if (HttpMethods.IsDelete(request.Method))
            {
                await ProcessDeleteCommand(processParams, ct);

                return(true);
            }

            throw new NotSupportedException();
        }
示例#24
0
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMiddleware <StrictSameSiteMiddleware>();
            app.UseAuthentication();
            app.UseResponseCompression();

            app.Use(async(context, next) =>
            {
                if (!context.User.Identity.IsAuthenticated)
                {
                    await context.ChallengeAsync();
                    return;
                }

                await next();
            });

            app.Use(async(context, next) =>
            {
                if (HttpMethods.IsPost(context.Request.Method) ||
                    HttpMethods.IsPatch(context.Request.Method) ||
                    HttpMethods.IsPut(context.Request.Method) ||
                    HttpMethods.IsDelete(context.Request.Method))
                {
                    await antiforgery.ValidateRequestAsync(context);
                }

                await next();
            });

            app.Use(next => context =>
            {
                string path = context.Request.Path.Value;

                if (
                    string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
                    string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
                {
                    var tokens = antiforgery.GetAndStoreTokens(context);
                    context.Response.Headers.Append("X-XSRF-TOKEN", tokens.RequestToken);
                }

                return(next(context));
            });

            app.Map("/api", api =>
            {
                api.RunProxy(async context =>
                {
                    var forwardContext = context.ForwardTo(Env.GetString("API_HTTPS_URL"));

                    try
                    {
                        var token = await context.GetUserAccessTokenAsync();
                        forwardContext.UpstreamRequest.SetBearerToken(token);

                        return(await forwardContext.Send());
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                });
            });

            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute().RequireAuthorization();
            });

            app.UseSpaStaticFiles();
            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "Resources";

                if (env.IsDevelopment())
                {
                    spa.UseVueDevelopmentServer(Env.GetString("APP_VUE_DEVELOPMENT_SERVER_URL"));
                }
            });
        }
        private string SelectActionImpl(RouteContext routeContext, SelectControllerResult controllerResult, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            Microsoft.AspNet.OData.Routing.ODataPath odataPath = routeContext.HttpContext.ODataFeature().Path;
            HttpRequest request = routeContext.HttpContext.Request;

            if (odataPath.PathTemplate == "~/entityset")
            {
                EntitySetSegment  entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase entitySet        = entitySetSegment.EntitySet;

                if (HttpMethods.IsGet(request.Method))
                {
                    // e.g. Try GetCustomers first, then fall back to Get action name
                    return(actionDescriptors.FindMatchingAction(
                               "Get" + entitySet.Name,
                               "Get"));
                }
                else if (HttpMethods.IsPost(request.Method))
                {
                    // e.g. Try PostCustomer first, then fall back to Post action name
                    return(actionDescriptors.FindMatchingAction(
                               "Post" + entitySet.EntityType().Name,
                               "Post"));
                }
            }
            else if (odataPath.PathTemplate == "~/entityset/key" ||
                     odataPath.PathTemplate == "~/entityset/key/cast")
            {
                string httpMethodName;

                if (HttpMethods.IsGet(request.Method))
                {
                    httpMethodName = "Get";
                }
                else if (HttpMethods.IsPut(request.Method))
                {
                    httpMethodName = "Put";
                }
                else if (HttpMethods.IsPatch(request.Method))
                {
                    httpMethodName = "Patch";
                }
                else if (HttpMethods.IsDelete(request.Method))
                {
                    httpMethodName = "Delete";
                }
                else
                {
                    return(null);
                }

                Contract.Assert(httpMethodName != null);

                IEdmEntityType entityType = (IEdmEntityType)odataPath.EdmType;

                // e.g. Try GetCustomer first, then fallback on Get action name
                string actionName = actionDescriptors.FindMatchingAction(
                    httpMethodName + entityType.Name,
                    httpMethodName);

                if (actionName != null)
                {
                    KeySegment keySegment = (KeySegment)odataPath.Segments[1];
                    // TODO: Add key/value to RouteData
                    return(actionName);
                }
            }
            else if (odataPath.PathTemplate == "~/entityset/$count" &&
                     HttpMethods.IsGet(request.Method))
            {
                EntitySetSegment  entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase entitySet        = entitySetSegment.EntitySet;

                // e.g. Try GetCustomers first, then fall back to Get action name
                return(actionDescriptors.FindMatchingAction(
                           "Get" + entitySet.Name,
                           "Get"));
            }
            else if (odataPath.PathTemplate == "~/entityset/cast")
            {
                EntitySetSegment   entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase  entitySet        = entitySetSegment.EntitySet;
                IEdmCollectionType collectionType   = (IEdmCollectionType)odataPath.EdmType;
                IEdmEntityType     entityType       = (IEdmEntityType)collectionType.ElementType.Definition;

                if (HttpMethods.IsGet(request.Method))
                {
                    // e.g. Try GetCustomersFromSpecialCustomer first, then fall back to GetFromSpecialCustomer
                    return(actionDescriptors.FindMatchingAction(
                               "Get" + entitySet.Name + "From" + entityType.Name,
                               "GetFrom" + entityType.Name));
                }
                else if (HttpMethods.IsPost(request.Method))
                {
                    // e.g. Try PostCustomerFromSpecialCustomer first, then fall back to PostFromSpecialCustomer
                    return(actionDescriptors.FindMatchingAction(
                               "Post" + entitySet.EntityType().Name + "From" + entityType.Name,
                               "PostFrom" + entityType.Name));
                }
            }
            else if (odataPath.PathTemplate == "~/entityset/cast/$count" &&
                     HttpMethods.IsGet(request.Method))
            {
                EntitySetSegment   entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase  entitySet        = entitySetSegment.EntitySet;
                IEdmCollectionType collectionType   = (IEdmCollectionType)odataPath.Segments[1].EdmType;
                IEdmEntityType     entityType       = (IEdmEntityType)collectionType.ElementType.Definition;

                // e.g. Try GetCustomersFromSpecialCustomer first, then fall back to GetFromSpecialCustomer
                return(actionDescriptors.FindMatchingAction(
                           "Get" + entitySet.Name + "From" + entityType.Name,
                           "GetFrom" + entityType.Name));
            }

            return(null);
        }
        private async Task HandleHttpRequest(HttpContext context, Instance destination, string host, int port, string scheme)
        {
            var requestMessage = new HttpRequestMessage();
            var requestMethod  = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            // All request headers and cookies must be transferend to remote server. Some headers will be skipped
            foreach (var header in context.Request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            requestMessage.Headers.Host = host;
            //recreate remote url
            string uriString = GetUri(context, host, port, scheme);

            requestMessage.RequestUri = new Uri(uriString);
            requestMessage.Method     = new HttpMethod(context.Request.Method);
            try
            {
                using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
                {
                    context.Response.StatusCode = (int)responseMessage.StatusCode;
                    foreach (var header in responseMessage.Headers)
                    {
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    foreach (var header in responseMessage.Content.Headers)
                    {
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    var buffer = new byte[Int32.Parse(context.Response.Headers["Content-Length"])];

                    using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
                    {
                        int len  = 0;
                        int full = 0;
                        while ((len = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                        {
                            await context.Response.Body.WriteAsync(buffer, 0, buffer.Length);

                            full += buffer.Length;
                        }

                        //context.Response.Headers.Remove("transfer-encoding");
                    }

                    Logger.Log(context.Request.GetDisplayUrl(), requestMessage.Method.Method, destination, uriString, context.Response.StatusCode);
                }
            }
            catch (HttpRequestException)
            {
                Logger.Log(context.Request.GetDisplayUrl(), requestMessage.Method.Method, destination, uriString, 500);
                await context.Response.WriteAsync("Target server unavaliable");
            }
        }
        /// <summary>
        /// Handle a simple http request dumping remote content to the client
        /// </summary>
        /// <param name="context"></param>
        /// <param name="_options"></param>
        /// <param name="destination"></param>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <param name="scheme"></param>
        /// <returns></returns>
        private async Task HandleHttpRequest(HttpContext context, InternalProxyOptions _options, Node destination, string host, int port, string scheme)
        {
            var requestMessage = new HttpRequestMessage();
            var requestMethod  = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            // All request headers and cookies must be transferend to remote server. Some headers will be skipped
            foreach (var header in context.Request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }


            requestMessage.Headers.Host = host;
            //recreate remote url
            string uriString = GetUri(context, host, port, scheme);

            requestMessage.RequestUri = new Uri(uriString);
            requestMessage.Method     = new HttpMethod(context.Request.Method);
            using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
            {
                context.Response.StatusCode = (int)responseMessage.StatusCode;
                foreach (var header in responseMessage.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                foreach (var header in responseMessage.Content.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }


                if (!_options.SendChunked)
                {
                    //tell to the browser that response is not chunked
                    context.Response.Headers.Remove("transfer-encoding");
                    await responseMessage.Content.CopyToAsync(context.Response.Body);
                }
                else
                {
                    var buffer = new byte[_options.BufferSize ?? DefaultBufferSize];

                    using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
                    {
                        //long pos = responseStream.Position;
                        //if (pos > 0)
                        //{
                        //    responseStream.Seek(0, SeekOrigin.Begin);
                        //}
                        //context.Response.Body = new MemoryStream();

                        int len  = 0;
                        int full = 0;
                        while ((len = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                        {
                            await context.Response.Body.WriteAsync(buffer, 0, buffer.Length);

                            // await context.Response.Body.FlushAsync();
                            full += buffer.Length;
                        }
                        // context.Response.ContentLength = full;

                        context.Response.Headers.Remove("transfer-encoding");
                    }
                }
            }
        }
示例#28
0
        public override async Task HandleRequest(HttpContext context, Node node, int?bufferSize = null, bool chunked = false, TimeSpan?keepAlive = null)
        {
            var requestMessage = new HttpRequestMessage();
            var requestMethod  = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            // All request headers and cookies must be transferend to remote server. Some headers will be skipped
            foreach (var header in context.Request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            requestMessage.Headers.Host = node.Host;
            //recreate remote url
            string uriString = GetUri(context, node.Host, node.Port, node.Scheme);

            requestMessage.RequestUri = new Uri(uriString);
            requestMessage.Method     = new HttpMethod(context.Request.Method);
            var _httpClient = new HttpClient();

            using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
            {
                context.Response.StatusCode = (int)responseMessage.StatusCode;
                foreach (var header in responseMessage.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                foreach (var header in responseMessage.Content.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                if (!chunked)
                {
                    //tell to the browser that response is not chunked
                    context.Response.Headers.Remove("transfer-encoding");
                    await responseMessage.Content.CopyToAsync(context.Response.Body);
                }
                else
                {
                    var buffer = new byte[bufferSize ?? DefaultBufferSize];

                    using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
                    {
                        int len  = 0;
                        int full = 0;
                        while ((len = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                        {
                            await context.Response.Body.WriteAsync(buffer, 0, buffer.Length);

                            full += buffer.Length;
                        }

                        context.Response.Headers.Remove("transfer-encoding");
                    }
                }
            }
        }
示例#29
0
        /// <summary>
        /// Handles an HTTP request
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task <IResponse> HandleRequest(IRequest request)
        {
            try
            {
                // add access control header first
                request.Response.WithHeader("Access-Control-Allow-Origin", "*");

                Logger.Debug("Handling request to {0} {1}. Parsing resource descriptor from path...", request.Method, request.Path);

                // get the resource descriptor
                var resourceDescriptor = ResourceDescriptorHelper.GetResourceDescriptor(request.Path);
                if (resourceDescriptor == null)
                {
                    return(request.Response.WithStatus(HttpStatusCode.NotFound));
                }

                Logger.Debug("Parsing resource descriptor from path...");

                // if the resource type is not valid for this service, it's an unrecognized route
                if (!ResourceHandlerRegistry.IsSupported(resourceDescriptor.RootType))
                {
                    return(request.Response.WithStatus(HttpStatusCode.NotFound));
                }

                Logger.Debug("Successfully parsed resource descriptor for type {0} from path. Creating resource handler...",
                             resourceDescriptor.Type.FullName);

                // get handler for resource type
                var resourceHandler = ResourceHandlerRegistry.Get(resourceDescriptor.Type);
                if (resourceHandler == null)
                {
                    Logger.Error("Failed to created resource handler for type '{0}' even though its a supported type for this API.",
                                 resourceDescriptor.Type);
                    return(request.Response.WithStatus(HttpStatusCode.InternalServerError));
                }

                Logger.Debug("Successfully created resource handler of type {0} for resource type {1}. Processing {2} request...",
                             resourceHandler.GetType().FullName,
                             resourceDescriptor.Type.Name,
                             request.Method);

                // get or delete do not have a body - just use the route
                if (HttpMethods.IsGet(request.Method))
                {
                    await HandleGet(request, resourceHandler, resourceDescriptor);
                }
                else if (HttpMethods.IsDelete(request.Method))
                {
                    await HandleDelete(request, resourceHandler, resourceDescriptor);
                }
                else
                {
                    // read body of request as JSON
                    var resource = await ResourceSerializer.Deserialize(await request.ReadBodyAsText());

                    // ensure that the provided resource ID matches the ID from the route
                    // in the case of a POST, this should be null
                    if (resource.Id != null && resource.Id != resourceDescriptor.Url)
                    {
                        return(request.Response
                               .WithStatus(HttpStatusCode.BadRequest)
                               .WithPlainTextBody(
                                   $"Resource ID does not match ID in payload ('{resourceDescriptor.Id}' != '{resource.Id}'"));
                    }

                    // create or update based on the POST vs PUT
                    // if we have an ID for a POST or no ID for a PUT, the method is not supported for the route
                    if (HttpMethods.IsPost(request.Method) && resourceDescriptor.Id == null)
                    {
                        await HandlePost(request, resourceHandler, resourceDescriptor, resource);
                    }
                    else if (HttpMethods.IsPut(request.Method) && resourceDescriptor.Id != null)
                    {
                        await HandlePut(request, resourceHandler, resourceDescriptor, resource);
                    }
                    else
                    {
                        return(request.Response.WithStatus(HttpStatusCode.MethodNotAllowed));
                    }
                }

                return(request.Response);
            }
            catch (Exception e)
            {
                return(request.Response.WithStatus(HttpStatusCode.InternalServerError).WithPlainTextBody(e.ToString()));
            }
        }
示例#30
0
        /// <summary>
        /// Crear la petición HTTP.
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="original"></param>
        /// <returns></returns>
        private HttpRequestMessage CreateProxyHttpRequest(Uri uri, HttpRequest original)
        {
            HttpRequestMessage requestMessage = new HttpRequestMessage();
            string             requestMethod  = original.Method;

            if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) && !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod))
            {
                try
                {
                    original.Body.Position = 0;
                    StreamContent streamContent = new StreamContent(original.Body);
                    requestMessage.Content = streamContent;
                }
                catch (Exception)
                {
                }
            }

            // Copy the request headers
            //foreach (var header in original.Headers)
            //{
            //    if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)
            //    {
            //        requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
            //    }
            //}

            requestMessage.Headers.Host = uri.Authority;
            requestMessage.RequestUri   = uri;
            requestMessage.Method       = new HttpMethod(original.Method);

            return(requestMessage);
        }