Relaying a request in asp.net (Forwarding a request)
Solution 1
Actually, something like this worked well
HttpRequest original = context.Request;
HttpWebRequest newRequest = (HttpWebRequest)WebRequest.Create(newUrl);
newRequest .ContentType = original.ContentType;
newRequest .Method = original.HttpMethod;
newRequest .UserAgent = original.UserAgent;
byte[] originalStream = ReadToByteArray(original.InputStream, 1024);
Stream reqStream = newRequest .GetRequestStream();
reqStream.Write(originalStream, 0, originalStream.Length);
reqStream.Close();
newRequest .GetResponse();
edit: ReadToByteArray method just makes a byte array from the stream
Solution 2
I have an extension method on HttpResponseBase
to copy an incoming request to an outgoing request.
Usage:
var externalRequest = (HttpWebRequest)WebRequest.Create("http://stackoverflow.com");
this.Request.CopyTo(externalRequest);
var externalResponse = (HttpWebResponse)externalRequest.GetResponse();
Source:
/// <summary>
/// Copies all headers and content (except the URL) from an incoming to an outgoing
/// request.
/// </summary>
/// <param name="source">The request to copy from</param>
/// <param name="destination">The request to copy to</param>
public static void CopyTo(this HttpRequestBase source, HttpWebRequest destination)
{
destination.Method = source.HttpMethod;
// Copy unrestricted headers (including cookies, if any)
foreach (var headerKey in source.Headers.AllKeys)
{
switch (headerKey)
{
case "Connection":
case "Content-Length":
case "Date":
case "Expect":
case "Host":
case "If-Modified-Since":
case "Range":
case "Transfer-Encoding":
case "Proxy-Connection":
// Let IIS handle these
break;
case "Accept":
case "Content-Type":
case "Referer":
case "User-Agent":
// Restricted - copied below
break;
default:
destination.Headers[headerKey] = source.Headers[headerKey];
break;
}
}
// Copy restricted headers
if (source.AcceptTypes.Any())
{
destination.Accept = string.Join(",", source.AcceptTypes);
}
destination.ContentType = source.ContentType;
destination.Referer = source.UrlReferrer.AbsoluteUri;
destination.UserAgent = source.UserAgent;
// Copy content (if content body is allowed)
if (source.HttpMethod != "GET"
&& source.HttpMethod != "HEAD"
&& source.ContentLength > 0)
{
var destinationStream = destination.GetRequestStream();
source.InputStream.CopyTo(destinationStream);
destinationStream.Close();
}
}
Solution 3
Here's some good relay code in VB.NET using MVC.
GLOBAL.ASAX.VB
Public Class MvcApplication
Inherits System.Web.HttpApplication
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.MapRoute("Default", "{*s}", New With {.controller = "Home", .action = "Index"})
End Sub
Sub Application_Start()
RegisterRoutes(RouteTable.Routes)
End Sub
End Class
HomeController.vb
Option Explicit On
Option Strict On
Imports System.Net
<HandleError()> _
Public Class HomeController
Inherits System.Web.Mvc.Controller
Function Index(ByVal s As String) As ActionResult
Server.ScriptTimeout = 60 * 60
If Request.QueryString.ToString <> "" Then s = s + "?" + Request.QueryString.ToString
Dim req As HttpWebRequest = CType(WebRequest.Create("http://stackoverflow.com/" + s), HttpWebRequest)
req.AllowAutoRedirect = False
req.Method = Request.HttpMethod
req.Accept = Request.Headers("Accept")
req.Referer = Request.Headers("Referer")
req.UserAgent = Request.UserAgent
For Each h In Request.Headers.AllKeys
If Not (New String() {"Connection", "Accept", "Host", "User-Agent", "Referer"}).Contains(h) Then
req.Headers.Add(h, Request.Headers(h))
End If
Next
If Request.HttpMethod <> "GET" Then
Using st = req.GetRequestStream
StreamCopy(Request.InputStream, st)
End Using
End If
Dim resp As WebResponse = Nothing
Try
Try
resp = req.GetResponse()
Catch ex As WebException
resp = ex.Response
End Try
If resp IsNot Nothing Then
Response.StatusCode = CType(resp, HttpWebResponse).StatusCode
For Each h In resp.Headers.AllKeys
If Not (New String() {"Content-Type"}).Contains(h) Then
Response.AddHeader(h, resp.Headers(h))
End If
Next
Response.ContentType = resp.ContentType
Using st = resp.GetResponseStream
StreamCopy(st, Response.OutputStream)
End Using
End If
Finally
If resp IsNot Nothing Then resp.Close()
End Try
Return Nothing
End Function
Sub StreamCopy(ByVal input As IO.Stream, ByVal output As IO.Stream)
Dim buf(0 To 16383) As Byte
Using br = New IO.BinaryReader(input)
Using bw = New IO.BinaryWriter(output)
Do
Dim rb = br.Read(buf, 0, buf.Length)
If rb = 0 Then Exit Do
bw.Write(buf, 0, rb)
Loop
End Using
End Using
End Sub
End Class
Solution 4
HttpContext includes the Request property, which in turn contains the Headers collection. It should be all the information you need.
Comments
-
El Che over 1 year
I have a web application that communicates between two different web applications (one receiver and one sender, the sender communicates with my application, and my application communicates with both).
A regular scenario is that the sender sends a HttpRequest to my application, and I receive it in an HttpHandler. This in turn sends the HttpContext to some businesslogic to do some plumbing.
After my business classes are finished storing data (some logging etc), I want to relay the same request with all the headers, form data etc to the receiver application. This must be sent from the class, and not the HttpHandler.
The question is really - how can I take a HttpContext object, and forward/relay the exact same request only modifying the URL from http://myserver.com/ to http://receiver.com.
Any code examples in preferable c# would be great!
-
El Che almost 15 yearsHttpWebRequest relayingRequest = (HttpWebRequest)WebRequest.Create(relayUrl); relayingRequest.Headers.Add(context.Request.Headers); This does not work - I also need params, httpmethod etc. The request should be identical...
-
John Saunders almost 15 yearsIt's all there, in HttpContext.Request, almost "by definition". Consider that this is how a page or other handler knows what to do. There's a QueryString and Form property to Context.Request as well. Look up the properties, and you'll see.
-
El Che almost 15 yearsYeah I know they're all there, but remember that context.Request is not a System.Net.HttpWebRequest, but a System.Web.HttpRequest. I'm not sure it it's as easy as just looking up the props and getting them into the new request.
-
John Saunders almost 15 yearsI am sure. Why are you looking for something more complicated? Take a look, try it out, and see.
-
El Che almost 15 yearsI'll check more tomorrow. It seems I need to read the inputstream from the original request and write it to the new one. Also I need to copy some of the properties like you say. Weird that there are no method to duplicate a request without this much hassle.
-
John Saunders almost 15 yearsIt's not something people have to do very often. This is something more often done at a lower level of the network infrastructure.
-
El Che almost 15 yearsUnable to cast object of type 'System.Web.HttpHeaderCollection' to type 'System.Net.WebHeaderCollection'.
-
Adrian Grigore about 13 yearsWhat about request header parameters and cookies?
-
El Che about 13 yearsNot needed for my context, but yes that could be done as well
-
diachedelic over 11 yearsI've generalised this answer below as an extension method to copy all headers & cookies
-
bfi over 9 yearssource.InputStream.Position = 0; is needed before source.InputStream.CopyTo
-
Nuno Rodrigues almost 9 yearsJust a small change, for the Headers part is safer and more complete this way: foreach (var headerKey in source.Headers.AllKeys) { if (!WebHeaderCollection.IsRestricted(headerKey)) { target.Headers[headerKey] = source.Headers[headerKey]; } }
-
Donald.Record over 8 yearsWhat's the big difference between this approach and using "Server.Transfer()"?
-
user1069816 over 8 years@Donald.Record Server.transfer can work only for sites running on the server in the same app pool; you can't use Server.Transfer to send the user to an external site.
-
johni over 7 yearsCoping a cookie using the headers like you suggest does not includes the cookie in the forwarded request.
-
vinodh over 7 yearsnewRequest .ContentType = original.ContentType; its giving header manipulation security vulnarability issue in scanners.