Skip to content
This repository has been archived by the owner on Apr 26, 2023. It is now read-only.

Copy original HTTP request headers, #175 #186

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 90 additions & 29 deletions DotNet/proxy.ashx
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,15 @@ public class proxy : IHttpHandler {
//forwarding original request
System.Net.WebResponse serverResponse = null;
try {
serverResponse = forwardToServer(context, requestUri, postBody, credentials);
serverResponse = forwardToServer(context.Request, requestUri, postBody, credentials);
} catch (System.Net.WebException webExc) {

string errorMsg = webExc.Message + " " + uri;
log(TraceLevel.Error, errorMsg);

if (webExc.Response != null)
{
copyHeaders(webExc.Response as System.Net.HttpWebResponse, context.Response);
copyResponseHeaders(webExc.Response as System.Net.HttpWebResponse, context.Response);

using (Stream responseStream = webExc.Response.GetResponseStream())
{
Expand Down Expand Up @@ -299,7 +299,7 @@ public class proxy : IHttpHandler {
//server returned error - potential cause: token has expired.
//we'll do second attempt to call the server with renewed token:
token = getNewTokenIfCredentialsAreSpecified(serverUrl, uri);
serverResponse = forwardToServer(context, addTokenToUri(uri, token, tokenParamName), postBody);
serverResponse = forwardToServer(context.Request, addTokenToUri(uri, token, tokenParamName), postBody);

//storing the token in Application scope, to do not waste time on requesting new one untill it expires or the app is restarted.
context.Application.Lock();
Expand Down Expand Up @@ -328,28 +328,40 @@ public class proxy : IHttpHandler {
return new byte[0];
}

private System.Net.WebResponse forwardToServer(HttpContext context, string uri, byte[] postBody, System.Net.NetworkCredential credentials = null)
private void writeRequestPostBody(System.Net.HttpWebRequest req, byte[] bytes)
{
return
postBody.Length > 0?
doHTTPRequest(uri, postBody, "POST", context.Request.Headers["referer"], context.Request.ContentType, credentials):
doHTTPRequest(uri, context.Request.HttpMethod, credentials);
if (bytes != null && bytes.Length > 0)
{
req.ContentLength = bytes.Length;
using (Stream outputStream = req.GetRequestStream())
{
outputStream.Write(bytes, 0, bytes.Length);
}
}
}

private System.Net.WebResponse forwardToServer(HttpRequest req, string uri, byte[] postBody, System.Net.NetworkCredential credentials = null)
{
string method = postBody.Length > 0 ? "POST" : req.HttpMethod;
System.Net.HttpWebRequest forwardReq = createHTTPRequest(uri, method, req.ContentType, credentials);
copyRequestHeaders(req, forwardReq);
writeRequestPostBody(forwardReq, postBody);
return forwardReq.GetResponse();
}

/// <summary>
/// Attempts to copy all headers from the fromResponse to the the toResponse.
/// </summary>
/// <param name="fromResponse">The response that we are copying the headers from</param>
/// <param name="toResponse">The response that we are copying the headers to</param>
private void copyHeaders(System.Net.WebResponse fromResponse, HttpResponse toResponse)
private void copyResponseHeaders(System.Net.WebResponse fromResponse, HttpResponse toResponse)
{
foreach (var headerKey in fromResponse.Headers.AllKeys)
{
switch (headerKey.ToLower())
{
case "content-type":
case "transfer-encoding":
case "accept-ranges": // Prevent requests for partial content
continue;
default:
toResponse.AddHeader(headerKey, fromResponse.Headers[headerKey]);
Expand All @@ -358,10 +370,64 @@ public class proxy : IHttpHandler {
}
toResponse.ContentType = fromResponse.ContentType;
}


private void copyRequestHeaders(HttpRequest fromRequest, System.Net.HttpWebRequest toRequest)
{
foreach (var headerKey in fromRequest.Headers.AllKeys)
{
string headerValue = fromRequest.Headers[headerKey];
switch (headerKey.ToLower())
{
case "accept-encoding":
case "proxy-connection":
continue;
case "range":
setRangeHeader(toRequest, headerValue);
break;
case "accept":
toRequest.Accept = headerValue;
break;
case "if-modified-since":
DateTime modDT;
if (DateTime.TryParse(headerValue, out modDT))
toRequest.IfModifiedSince = modDT;
break;
case "referer":
toRequest.Referer = headerValue;
break;
case "user-agent":
toRequest.UserAgent = headerValue;
break;
default:
// Some headers are restricted and would throw an exception:
// http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.headers(v=vs.100).aspx
if (!System.Net.WebHeaderCollection.IsRestricted(headerKey) &&
toRequest.Headers[headerKey] == null)
toRequest.Headers[headerKey] = headerValue;
break;
}
}
}

private void setRangeHeader(System.Net.HttpWebRequest req, string range)
{
string[] specifierAndRange = range.Split('=');
if (specifierAndRange.Length == 2)
{
string specifier = specifierAndRange[0];
string[] fromAndTo = specifierAndRange[1].Split('-');
if (fromAndTo.Length == 2)
{
int from, to;
if (int.TryParse(fromAndTo[0], out from) && int.TryParse(fromAndTo[1], out to))
req.AddRange(specifier, from, to);
}
}
}

private bool fetchAndPassBackToClient(System.Net.WebResponse serverResponse, HttpResponse clientResponse, bool ignoreAuthenticationErrors) {
if (serverResponse != null) {
copyHeaders(serverResponse, clientResponse);
copyResponseHeaders(serverResponse, clientResponse);
using (Stream byteStream = serverResponse.GetResponseStream()) {
// Text response
if (serverResponse.ContentType.Contains("text") ||
Expand Down Expand Up @@ -392,6 +458,7 @@ public class proxy : IHttpHandler {
}
serverResponse.Close();
}
clientResponse.StatusCode = (int)(serverResponse as System.Net.HttpWebResponse).StatusCode;
}
return false;
}
Expand All @@ -410,39 +477,33 @@ public class proxy : IHttpHandler {
{
contentType = "application/x-www-form-urlencoded";
String queryString = uriArray[1];

bytes = System.Text.Encoding.UTF8.GetBytes(queryString);
}
}

return doHTTPRequest(uri, bytes, method, PROXY_REFERER, contentType, credentials);
System.Net.HttpWebRequest req = createHTTPRequest(uri, method, contentType, credentials);
req.Referer = PROXY_REFERER;
writeRequestPostBody(req, bytes);
return req.GetResponse();
}

private System.Net.WebResponse doHTTPRequest(string uri, byte[] bytes, string method, string referer, string contentType, System.Net.NetworkCredential credentials = null)
private System.Net.HttpWebRequest createHTTPRequest(string uri, string method, string contentType, System.Net.NetworkCredential credentials = null)
{
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(uri);
req.ServicePoint.Expect100Continue = false;
req.Referer = referer;
req.Method = method;
if (method == "POST")
req.ContentType = string.IsNullOrEmpty(contentType) ? "application/x-www-form-urlencoded" : contentType;

// Use the default system proxy
req.Proxy = System.Net.HttpWebRequest.GetSystemWebProxy();

if (credentials != null)
req.Credentials = credentials;

if (bytes != null && bytes.Length > 0 || method == "POST") {
req.Method = "POST";
req.ContentType = string.IsNullOrEmpty(contentType) ? "application/x-www-form-urlencoded" : contentType;
if (bytes != null && bytes.Length > 0)
req.ContentLength = bytes.Length;
using (Stream outputStream = req.GetRequestStream()) {
outputStream.Write(bytes, 0, bytes.Length);
}
}
return req.GetResponse();
}

return req;
}

private string webResponseToString(System.Net.WebResponse serverResponse) {
using (Stream byteStream = serverResponse.GetResponseStream()) {
using (StreamReader sr = new StreamReader(byteStream)) {
Expand Down