Example #1
0
        private async Task BuildResponseAsync(IHttpResponse response, HttpResponse responseOut, HttpRequest requestIn)
        {
            // Forward the HTTP status code
            this.log.Debug("Status code", () => new { response.StatusCode });
            responseOut.StatusCode = (int)response.StatusCode;

            // The Headers property can be null in case of errors
            if (response.Headers != null)
            {
                // Forward the HTTP headers
                foreach (var header in response.Headers)
                {
                    if (ExcludedResponseHeaders.Contains(header.Key.ToLowerInvariant()))
                    {
                        this.log.Debug("Ignoring response header", () => new { header.Key, header.Value });
                        continue;
                    }

                    this.log.Debug("Adding response header", () => new { header.Key, header.Value });
                    foreach (var value in header.Value)
                    {
                        if (!responseOut.Headers.ContainsKey(header.Key))
                        {
                            responseOut.Headers[header.Key] = value;
                        }
                        else
                        {
                            // `.Append()` doesn't work on responseOut.Headers, this is
                            // a workaround to support multiple instances of the same header
                            var headers = responseOut.Headers[header.Key].ToList();
                            headers.Add(value);
                            responseOut.Headers[header.Key] = new StringValues(headers.ToArray());
                        }
                    }
                }
            }

            // HSTS support
            // See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
            // Note: The Strict-Transport-Security header is ignored by the browser when your
            // site is accessed using HTTP; this is because an attacker may intercept HTTP
            // connections and inject the header or remove it.
            if (requestIn.IsHttps && this.config.StrictTransportSecurityEnabled)
            {
                responseOut.Headers[HSTS_HEADER] = "max-age=" + this.config.StrictTransportSecurityPeriod;
            }

            // Last header before writing to the socket
            ApplicationRequestRouting.DisableInstanceAffinity(responseOut);

            // Some status codes like 204 and 304 can't have a body
            if (response.CanHaveBody && response.Content.Length > 0)
            {
                await responseOut.Body.WriteAsync(response.Content, 0, response.Content.Length);
            }
        }
Example #2
0
        public async Task ProcessAsync(
            string remoteEndpoint,
            HttpRequest requestIn,
            HttpResponse responseOut)
        {
            IHttpRequest request;

            try
            {
                this.RedirectToHttpsIfNeeded(requestIn);
                request = this.BuildRequest(requestIn, remoteEndpoint);
            }
            catch (RequestPayloadTooLargeException)
            {
                responseOut.StatusCode = (int)HttpStatusCode.RequestEntityTooLarge;
                ApplicationRequestRouting.DisableInstanceAffinity(responseOut);
                return;
            }
            catch (RedirectException e)
            {
                responseOut.StatusCode = (int)e.StatusCode;
                responseOut.Headers[LOCATION_HEADER] = e.Location;
                ApplicationRequestRouting.DisableInstanceAffinity(responseOut);
                return;
            }

            IHttpResponse response;
            var           method = requestIn.Method.ToUpperInvariant();

            this.log.Debug("Request method", () => new { method });
            switch (method)
            {
            case "GET":
                response = await this.client.GetAsync(request);

                break;

            case "DELETE":
                response = await this.client.DeleteAsync(request);

                break;

            case "OPTIONS":
                response = await this.client.OptionsAsync(request);

                break;

            case "HEAD":
                response = await this.client.HeadAsync(request);

                break;

            case "POST":
                response = await this.client.PostAsync(request);

                break;

            case "PUT":
                response = await this.client.PutAsync(request);

                break;

            case "PATCH":
                response = await this.client.PatchAsync(request);

                break;

            default:
                // Note: this could flood the logs due to spiders...
                this.log.Info("Request method not supported", () => new { method });
                responseOut.StatusCode = (int)HttpStatusCode.NotImplemented;
                ApplicationRequestRouting.DisableInstanceAffinity(responseOut);
                return;
            }

            await this.BuildResponseAsync(response, responseOut, requestIn);
        }