Пример #1
0
        public async override Task ProcessRequestAsync(HttpContext context)
        {
            Manager.Log("**********************************************************************************");

            var client  = new HttpClient();
            var request = await GetRequestFromClient(context);

            // send the request to the target
            Manager.Log("Request: " + RequestUrl, "Proxy");
            var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

            if (response == null)
            {
                Manager.Log("No response was received, returning a '400 Bad Request' to the client.", "Proxy");
                throw new HttpException((int)HttpStatusCode.BadRequest, String.Format("The requested url, <{0}>, could not be found.", RequestUrl));
            }

            Manager.Log(String.Format("Received '{0}'", ((int)response.StatusCode)), "Proxy");

            // send the response to the client
            Manager.Log("Response: " + ResponseUrl, "Proxy");
            await SendResponseToClient(context, response);

            Manager.Log("**********************************************************************************");
        }
Пример #2
0
        public async override Task ProcessRequestAsync(HttpContext context)
        {
            Manager.Log("**********************************************************************************");

            var client = new HttpClient(new HttpClientHandler
            {
                AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip,
                AllowAutoRedirect      = false,
                UseCookies             = false // allows us to set the Cookie header
            });
            var request = await GetRequestFromClient(context);

            // send the request to the target
            Manager.Log("Request: " + RequestUrl, "Proxy");
            var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

            if (response == null)
            {
                Manager.Log("No response was received, returning a '400 Bad Request' to the client.", "Proxy");
                throw new HttpException((int)HttpStatusCode.BadRequest, String.Format("The requested url, <{0}>, could not be found.", RequestUrl));
            }

            Manager.Log(String.Format("Received '{0}'", ((int)response.StatusCode)), "Proxy");

            // send the response to the client
            Manager.Log("Response: " + ResponseUrl, "Proxy");
            await SendResponseToClient(context, response);

            Manager.Log("**********************************************************************************");
        }
Пример #3
0
 /// <summary>
 /// Trys to add the response header.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <param name="name">The name.</param>
 /// <param name="value">The value.</param>
 /// <remarks>This was added to protect against the <c>Server cannot append header after HTTP headers have been sent.</c> exception that occurs occationally
 /// when a module before the rewriter preforms a <see cref="HttpResponse.Flush"/> forcing all the headers to be written before other modules have had a chance.</remarks>
 /// <returns></returns>
 internal static bool TryAddResponseHeader(HttpContextBase context, string name, string value)
 {
     try
     {
         AddResponseHeader(context, name, value);
         return(true);
     }
     catch (Exception exc)
     {
         Manager.Log(exc.Message, "Error");
         return(false);
     }
 }
Пример #4
0
        /// <summary>
        /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
        public void ProcessRequest(HttpContext context)
        {
            Manager.Log("**********************************************************************************");

            // send the request to the target
            Manager.Log("Request: " + RequestUrl, "Proxy");
            var response = SendRequestToTarget(context);

            // send the response to the client
            Manager.Log("Response: " + ResponseUrl, "Proxy");
            SendResponseToClient(context, response);

            Manager.Log("**********************************************************************************");
        }
        public virtual void WriteStreamResponseToTarget(HttpContextBase context, WebResponse response)
        {
            int bufferSize = Manager.Configuration.Proxy.ResponseSize;

            // push the content out to through the stream
            using (var responseStream = response.GetResponseStream())
                using (var bufferStream = new BufferedStream(responseStream, Manager.Configuration.Proxy.BufferSize))
                {
                    byte[] buffer = new byte[bufferSize];

                    try
                    {
                        while (true)
                        {
                            // make sure that the stream can be read from
                            if (!bufferStream.CanRead)
                            {
                                break;
                            }

                            int bytesReturned = bufferStream.Read(buffer, 0, bufferSize);

                            // if not bytes were returned the end of the stream has been reached
                            // and the loop should exit
                            if (bytesReturned == 0)
                            {
                                break;
                            }

                            // write bytes to the response
                            context.Response.OutputStream.Write(buffer, 0, bytesReturned);
                        }
                    }
                    catch (Exception exc)
                    {
                        Manager.Log("Error on response: " + exc.Message, "Proxy");
                    }
                }
        }
Пример #6
0
        private void RequestAccepted(IAsyncResult result)
        {
            IReplyChannel replyChannel = (IReplyChannel)result.AsyncState;

            try
            {
                var requestContext = replyChannel.EndReceiveRequest(result);

                if (requestContext != null)
                {
                    var context = new AzureServiceBusHttpContext(requestContext);

                    context.Items["ReplyChannel"] = replyChannel;

                    ProcessRequest(context);
                }
            }
            catch (Exception exc)
            {
                Manager.Log("Request Accepted: " + exc.Message, "Proxy");
                replyChannel.Abort();
            }
        }
Пример #7
0
        /// <summary>
        /// Sends the response to client.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="response">The response.</param>
        private async Task SendResponseToClient(HttpContext context, HttpResponseMessage response)
        {
            var hostHeader = context.Request.Headers.Get("Host");

            context.Response.ClearHeaders();
            context.Response.ClearContent();

            /* You cannot set any cache headers through the API, because it will prevent the use of the cache headers
             * added through the AppendHeader method.
             */

            // add all the headers from the other proxied session to this request
            foreach (var header in response.Headers)
            {
                var name = header.Key;

                // don't add any of these headers
                // don't check for restricted response headers because HttpContext doesn't seem to care
                if (name == "Server" ||
                    name == "X-Powered-By" ||
                    name == "Date" ||
                    name == "Host")
                {
                    continue;
                }

                string[] values = header.Value.ToArray();
                if (values.Length == 0)
                {
                    continue;
                }

                if (name == "Location")
                {
                    try
                    {
                        string location = values[0];

                        // make sure location is not empty before creating the URL
                        if (!String.IsNullOrEmpty(location))
                        {
                            // reminder: If location is an absolute URL, the Uri instance is created using only location.
                            var requestLocationUrl  = new Uri(RequestUrl, location);
                            var responseLocationUrl = new UriBuilder(requestLocationUrl);

                            // if the requested location for the host and port is the same as the requested URL we need to update them to the response
                            if (Uri.Compare(requestLocationUrl, RequestUrl, UriComponents.SchemeAndServer, UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                responseLocationUrl.Port   = ResponseUrl.Port;
                                responseLocationUrl.Host   = ResponseUrl.Host;
                                responseLocationUrl.Scheme = ResponseUrl.Scheme;

                                string path      = responseLocationUrl.Path;
                                int    pathIndex = path.IndexOf(RequestUrl.AbsolutePath, StringComparison.OrdinalIgnoreCase);

                                // since this is not redirecting to a different server try to replease the path
                                if (pathIndex > -1)
                                {
                                    path = path.Remove(pathIndex, RequestUrl.AbsolutePath.Length);
                                    path = path.Insert(pathIndex, ResponseUrl.AbsolutePath);

                                    responseLocationUrl.Path = path;
                                }
                            }

                            context.Response.AppendHeader(name, responseLocationUrl.Uri.OriginalString);
                        }
                    }
                    catch { /* do nothing on purpose */ }

                    // nothing else can occure just continue processing from next header
                    continue;
                }

                // if this is a chuncked response then we should send it correctly
                if (name == "Transfer-Encoding")
                {
                    /* http://www.go-mono.com/docs/index.aspx?link=P%3aSystem.Web.HttpResponse.Buffer
                     *
                     * This controls whether HttpResponse should buffer the output before it is delivered to a
                     * client. The default is true.
                     *
                     * The buffering can be changed during the execution back and forth if needed. Notice that
                     * changing the buffering state will not flush the current contents held in the output buffer,
                     * the contents will only be flushed out on the next write operation or by manually calling
                     * System.Web.HttpResponse.Flush
                     */
                    context.Response.BufferOutput = false;
                    continue;
                }

                if (name == "Content-Type")
                {
                    /* http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
                     * http://en.wikipedia.org/wiki/Motion_JPEG#M-JPEG_over_HTTP
                     *
                     * The multipart/x-mixed-replace content-type should be treated as a streaming content and shouldn't be buffered.
                     */
                    if (values[0].StartsWith("multipart/x-mixed-replace"))
                    {
                        context.Response.BufferOutput = false;
                    }
                }

                // it is nessisary to get the values for headers that are allowed to specifiy
                // multiple values in an instance (i.e. Set-Cookie)
                foreach (string value in values)
                {
                    context.Response.AppendHeader(name, value);
                }
            }

            context.Response.AppendHeader("Host", hostHeader);

            Manager.Log(String.Format("Response is {0}being buffered", (context.Response.BufferOutput ? "" : "not ")), "Proxy");

            // add the vanity url to the header
            Manager.TryToAddVanityHeader(new HttpContextWrapper(context));

            // set all HTTP specific protocol stuff
            context.Response.StatusCode = (int)response.StatusCode;

            // for not-modified responses the content type will not be returned so don't try and set it.
            if (response.Content.Headers.ContentType != null)
            {
                context.Response.ContentType = response.Content.Headers.ContentType.MediaType;
            }

            Manager.Log(String.Format("Responding '{0}'", ((int)response.StatusCode)), "Proxy");

            await OnResponseToClient(context, response);

            await response.Content.CopyToAsync(context.Response.OutputStream);
        }
Пример #8
0
        /// <summary>
        /// Sends the request to server.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private WebResponse SendRequestToTarget(HttpContext context)
        {
            // get the request
            var request = WebRequest.CreateDefault(RequestUrl);

            if (request == null)
            {
                throw new HttpException((int)HttpStatusCode.BadRequest, String.Format("The requested url, <{0}>, could not be found.", RequestUrl));
            }

            // keep the same HTTP request method
            request.Method = context.Request.HttpMethod;
            var knownVerb = KnownHttpVerb.Parse(request.Method);

            // depending on the type of this request specific values for an HTTP request
            if (request is HttpWebRequest)
            {
                var httpRequest = request as HttpWebRequest;
                httpRequest.AllowAutoRedirect = false;
                httpRequest.ServicePoint.Expect100Continue = false;
                httpRequest.Host = ResponseUrl.Host;
                // add all the headers from the other proxied session to this request
                foreach (string name in context.Request.Headers.AllKeys)
                {
                    // add the headers that are restricted in their supported manor
                    switch (name)
                    {
                    case "User-Agent":
                        httpRequest.UserAgent = context.Request.UserAgent;
                        break;

                    case "Connection":
                        string connection = context.Request.Headers[name];
                        if (connection.IndexOf("Keep-Alive", StringComparison.OrdinalIgnoreCase) > 0)
                        {
                            httpRequest.KeepAlive = true;
                        }

                        var list = new List <string>();
                        foreach (string conn in connection.Split(','))
                        {
                            string c = conn.Trim();
                            if (!c.Equals("Keep-Alive", StringComparison.OrdinalIgnoreCase) && !c.Equals("Close", StringComparison.OrdinalIgnoreCase))
                            {
                                list.Add(c);
                            }
                        }

                        if (list.Count > 0)
                        {
                            httpRequest.Connection = String.Join(", ", list.ToArray());
                        }
                        break;

                    case "Transfer-Encoding":
                        httpRequest.SendChunked      = true;
                        httpRequest.TransferEncoding = context.Request.Headers[name];
                        break;

                    case "Expect":
                        httpRequest.ServicePoint.Expect100Continue = true;
                        break;

                    case "If-Modified-Since":
                        DateTime ifModifiedSince;
                        if (DateTime.TryParse(context.Request.Headers[name], out ifModifiedSince))
                        {
                            httpRequest.IfModifiedSince = ifModifiedSince;
                        }
                        break;

                    case "Content-Length":
                        httpRequest.ContentLength = context.Request.ContentLength;
                        break;

                    case "Content-Type":
                        httpRequest.ContentType = context.Request.ContentType;
                        break;

                    case "Accept":
                        httpRequest.Accept = String.Join(", ", context.Request.AcceptTypes);
                        break;

                    case "Referer":
                        httpRequest.Referer = context.Request.UrlReferrer.OriginalString;
                        break;
                    }

                    // add to header if not restricted
                    if (!WebHeaderCollection.IsRestricted(name, false))
                    {
                        // it is nessisary to get the values for headers that are allowed to specifiy
                        // multiple values in an instance (i.e. Cookie)
                        string[] values = context.Request.Headers.GetValues(name);
                        foreach (string value in values)
                        {
                            request.Headers.Add(name, value);
                        }
                    }
                }
            }

            // add the vanity url to the header
            if (Manager.Configuration.Rewriter.AllowVanityHeader)
            {
                request.Headers.Add("X-Reverse-Proxied-By", Manager.RewriterUserAgent);
                request.Headers.Add("X-ManagedFusion-Rewriter-Version", Manager.RewriterVersion.ToString(2));
            }

            /*
             * Add Proxy Standard Protocol Headers
             */

            // http://en.wikipedia.org/wiki/X-Forwarded-For
            request.Headers.Add("X-Forwarded-For", context.Request.UserHostAddress);

            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.45
            string currentServerName     = context.Request.ServerVariables["SERVER_NAME"];
            string currentServerPort     = context.Request.ServerVariables["SERVER_PORT"];
            string currentServerProtocol = context.Request.ServerVariables["SERVER_PROTOCOL"];

            if (currentServerProtocol.IndexOf("/") >= 0)
            {
                currentServerProtocol = currentServerProtocol.Substring(currentServerProtocol.IndexOf("/") + 1);
            }

            string currentVia = String.Format("{0} {1}:{2} ({3})", currentServerProtocol, currentServerName, currentServerPort, Manager.RewriterNameAndVersion);

            request.Headers.Add("Via", currentVia);

            /*
             * End - Add Proxy Standard Protocol Headers
             */

            request.Headers.Add("Host", context.Request.Headers.Get("host"));

            OnRequestToTarget(context, request);

            // ContentLength is set to -1 if their is no data to send
            if (request.ContentLength >= 0 && !knownVerb.ContentBodyNotAllowed)
            {
                int bufferSize = Manager.Configuration.Rewriter.Proxy.RequestSize;
                using (Stream requestStream = request.GetRequestStream(), bufferStream = new BufferedStream(context.Request.InputStream, Manager.Configuration.Rewriter.Proxy.BufferSize))
                {
                    byte[] buffer = new byte[bufferSize];

                    try
                    {
                        while (true)
                        {
                            // make sure that the stream can be read from
                            if (!bufferStream.CanRead)
                            {
                                break;
                            }

                            int bytesReturned = bufferStream.Read(buffer, 0, bufferSize);

                            // if not bytes were returned the end of the stream has been reached
                            // and the loop should exit
                            if (bytesReturned == 0)
                            {
                                break;
                            }

                            // write bytes to the response
                            requestStream.Write(buffer, 0, bytesReturned);
                        }
                    }
                    catch (Exception exc)
                    {
                        Manager.Log("Error on request: " + exc.Message, "Proxy");
                    }
                }
            }

            // get the response
            WebResponse response;

            try { response = request.GetResponse(); }
            catch (WebException exc)
            {
                Manager.Log(String.Format("Error received from {0}: {1}", request.RequestUri, exc.Message), "Proxy");
                response = exc.Response;
            }

            if (response == null)
            {
                Manager.Log("No response was received, returning a '400 Bad Request' to the client.", "Proxy");
                throw new HttpException((int)HttpStatusCode.BadRequest, String.Format("The requested url, <{0}>, could not be found.", RequestUrl));
            }

            Manager.Log(response.GetType().ToString(), "Proxy");
            if (response is HttpWebResponse)
            {
                var httpResponse = response as HttpWebResponse;
                Manager.Log(String.Format("Received '{0} {1}'", ((int)httpResponse.StatusCode), httpResponse.StatusDescription), "Proxy");
            }

            return(response);
        }
Пример #9
0
        /// <summary>
        /// Sends the response to client.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="response">The response.</param>
        private void SendResponseToClient(HttpContext context, WebResponse response)
        {
            context.Response.ClearHeaders();
            context.Response.ClearContent();

            /* You cannot set any cache headers through the API, because it will prevent the use of the cache headers
             * added through the AppendHeader method.
             */

            // add all the headers from the other proxied session to this request
            for (int i = 0; i < response.Headers.Count; i++)
            {
                string name = response.Headers.GetKey(i);

                // don't add any of these headers
                // don't check for restricted response headers because HttpContext doesn't seem to care
                if (name == "Server" ||
                    name == "X-Powered-By" ||
                    name == "Date" ||
                    name == "Host")
                {
                    continue;
                }

                string[] values = response.Headers.GetValues(i);
                if (values.Length == 0)
                {
                    continue;
                }

                if (name == "Location")
                {
                    try
                    {
                        string location = values[0];

                        // make sure location is not empty before creating the URL
                        if (!String.IsNullOrEmpty(location))
                        {
                            // reminder: If location is an absolute URL, the Uri instance is created using only location.
                            var requestLocationUrl  = new Uri(RequestUrl, location);
                            var responseLocationUrl = new UriBuilder(requestLocationUrl);

                            // if the requested location for the host and port is the same as the requested URL we need to update them to the response
                            if (Uri.Compare(requestLocationUrl, RequestUrl, UriComponents.SchemeAndServer, UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                responseLocationUrl.Port   = ResponseUrl.Port;
                                responseLocationUrl.Host   = ResponseUrl.Host;
                                responseLocationUrl.Scheme = ResponseUrl.Scheme;

                                string path      = responseLocationUrl.Path;
                                int    pathIndex = path.IndexOf(RequestUrl.AbsolutePath, StringComparison.OrdinalIgnoreCase);

                                // since this is not redirecting to a different server try to replease the path
                                if (pathIndex > -1)
                                {
                                    path = path.Remove(pathIndex, RequestUrl.AbsolutePath.Length);
                                    path = path.Insert(pathIndex, ResponseUrl.AbsolutePath);

                                    responseLocationUrl.Path = path;
                                }
                            }

                            context.Response.AppendHeader(name, responseLocationUrl.Uri.OriginalString);
                        }
                    }
                    catch { /* do nothing on purpose */ }

                    // nothing else can occure just continue processing from next header
                    continue;
                }

                // if this is a chuncked response then we should send it correctly
                if (name == "Transfer-Encoding")
                {
                    /* http://www.go-mono.com/docs/index.aspx?link=P%3aSystem.Web.HttpResponse.Buffer
                     *
                     * This controls whether HttpResponse should buffer the output before it is delivered to a
                     * client. The default is true.
                     *
                     * The buffering can be changed during the execution back and forth if needed. Notice that
                     * changing the buffering state will not flush the current contents held in the output buffer,
                     * the contents will only be flushed out on the next write operation or by manually calling
                     * System.Web.HttpResponse.Flush
                     */
                    context.Response.BufferOutput = false;
                    continue;
                }

                if (name == "Content-Type")
                {
                    /* http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
                     * http://en.wikipedia.org/wiki/Motion_JPEG#M-JPEG_over_HTTP
                     *
                     * The multipart/x-mixed-replace content-type should be treated as a streaming content and shouldn't be buffered.
                     */
                    if (values[0].StartsWith("multipart/x-mixed-replace"))
                    {
                        context.Response.BufferOutput = false;
                    }
                }

                // it is nessisary to get the values for headers that are allowed to specifiy
                // multiple values in an instance (i.e. Set-Cookie)
                foreach (string value in values)
                {
                    context.Response.AppendHeader(name, value);
                }
            }

            Manager.Log(String.Format("Response is {0}being buffered", (context.Response.BufferOutput ? "" : "not ")), "Proxy");

            // add the vanity url to the header
            Manager.TryToAddVanityHeader(new HttpContextWrapper(context));

            // set all HTTP specific protocol stuff
            if (response is HttpWebResponse)
            {
                var httpResponse = response as HttpWebResponse;
                context.Response.StatusCode        = (int)httpResponse.StatusCode;
                context.Response.StatusDescription = httpResponse.StatusDescription;

                Manager.Log(String.Format("Responding '{0} {1}'", ((int)httpResponse.StatusCode), httpResponse.StatusDescription), "Proxy");
            }

            OnResponseToClient(context, response);

            int bufferSize = Manager.Configuration.Rewriter.Proxy.ResponseSize;

            // push the content out to through the stream
            using (var responseStream = response.GetResponseStream())
                using (var bufferStream = new BufferedStream(responseStream, Manager.Configuration.Rewriter.Proxy.BufferSize))
                {
                    byte[] buffer = new byte[bufferSize];

                    try
                    {
                        while (true)
                        {
                            // make sure that the stream can be read from
                            if (!bufferStream.CanRead)
                            {
                                break;
                            }

                            int bytesReturned = bufferStream.Read(buffer, 0, bufferSize);

                            // if not bytes were returned the end of the stream has been reached
                            // and the loop should exit
                            if (bytesReturned == 0)
                            {
                                break;
                            }

                            // write bytes to the response
                            context.Response.OutputStream.Write(buffer, 0, bytesReturned);
                        }
                    }
                    catch (Exception exc)
                    {
                        Manager.Log("Error on response: " + exc.Message, "Proxy");
                    }
                }
        }