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

Commit 3112776

Browse files
authored
Merge pull request #433 from gavinr/original-http-request-headers
Copy original HTTP request headers
2 parents 7381558 + 29da88d commit 3112776

File tree

1 file changed

+99
-24
lines changed

1 file changed

+99
-24
lines changed

DotNet/proxy.ashx

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -279,15 +279,15 @@ public class proxy : IHttpHandler {
279279
//forwarding original request
280280
System.Net.WebResponse serverResponse = null;
281281
try {
282-
serverResponse = forwardToServer(context, addTokenToUri(requestUri, token, tokenParamName), postBody, credentials);
282+
serverResponse = forwardToServer(context.Request, addTokenToUri(requestUri, token, tokenParamName), postBody, credentials);
283283
} catch (System.Net.WebException webExc) {
284284

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

288288
if (webExc.Response != null)
289289
{
290-
copyHeaders(webExc.Response as System.Net.HttpWebResponse, context.Response);
290+
copyResponseHeaders(webExc.Response as System.Net.HttpWebResponse, context.Response);
291291

292292
using (Stream responseStream = webExc.Response.GetResponseStream())
293293
{
@@ -328,7 +328,7 @@ public class proxy : IHttpHandler {
328328
//server returned error - potential cause: token has expired.
329329
//we'll do second attempt to call the server with renewed token:
330330
token = getNewTokenIfCredentialsAreSpecified(serverUrl, requestUri);
331-
serverResponse = forwardToServer(context, addTokenToUri(requestUri, token, tokenParamName), postBody);
331+
serverResponse = forwardToServer(context.Request, addTokenToUri(requestUri, token, tokenParamName), postBody);
332332

333333
//storing the token in Application scope, to do not waste time on requesting new one untill it expires or the app is restarted.
334334
context.Application.Lock();
@@ -367,20 +367,33 @@ public class proxy : IHttpHandler {
367367
return new byte[0];
368368
}
369369

370-
private System.Net.WebResponse forwardToServer(HttpContext context, string uri, byte[] postBody, System.Net.NetworkCredential credentials = null)
370+
private void writeRequestPostBody(System.Net.HttpWebRequest req, byte[] bytes)
371371
{
372-
return
373-
postBody.Length > 0?
374-
doHTTPRequest(uri, postBody, "POST", context.Request.Headers["referer"], context.Request.ContentType, credentials):
375-
doHTTPRequest(uri, context.Request.HttpMethod, credentials);
372+
if (bytes != null && bytes.Length > 0)
373+
{
374+
req.ContentLength = bytes.Length;
375+
using (Stream outputStream = req.GetRequestStream())
376+
{
377+
outputStream.Write(bytes, 0, bytes.Length);
378+
}
379+
}
380+
}
381+
382+
private System.Net.WebResponse forwardToServer(HttpRequest req, string uri, byte[] postBody, System.Net.NetworkCredential credentials = null)
383+
{
384+
string method = postBody.Length > 0 ? "POST" : req.HttpMethod;
385+
System.Net.HttpWebRequest forwardReq = createHTTPRequest(uri, method, req.ContentType, credentials);
386+
copyRequestHeaders(req, forwardReq);
387+
writeRequestPostBody(forwardReq, postBody);
388+
return forwardReq.GetResponse();
376389
}
377390

378391
/// <summary>
379392
/// Attempts to copy all headers from the fromResponse to the the toResponse.
380393
/// </summary>
381394
/// <param name="fromResponse">The response that we are copying the headers from</param>
382395
/// <param name="toResponse">The response that we are copying the headers to</param>
383-
private void copyHeaders(System.Net.WebResponse fromResponse, HttpResponse toResponse)
396+
private void copyResponseHeaders(System.Net.WebResponse fromResponse, HttpResponse toResponse)
384397
{
385398
foreach (var headerKey in fromResponse.Headers.AllKeys)
386399
{
@@ -410,6 +423,73 @@ public class proxy : IHttpHandler {
410423
}
411424
}
412425

426+
private void copyRequestHeaders(HttpRequest fromRequest, System.Net.HttpWebRequest toRequest)
427+
{
428+
foreach (var headerKey in fromRequest.Headers.AllKeys)
429+
{
430+
string headerValue = fromRequest.Headers[headerKey];
431+
string headerKeyLower = headerKey.ToLower();
432+
433+
switch (headerKeyLower)
434+
{
435+
case "accept-encoding":
436+
case "proxy-connection":
437+
continue;
438+
case "range":
439+
setRangeHeader(toRequest, headerValue);
440+
break;
441+
case "accept":
442+
toRequest.Accept = headerValue;
443+
break;
444+
case "if-modified-since":
445+
DateTime modDT;
446+
if (DateTime.TryParse(headerValue, out modDT))
447+
toRequest.IfModifiedSince = modDT;
448+
break;
449+
case "referer":
450+
toRequest.Referer = headerValue;
451+
break;
452+
case "user-agent":
453+
toRequest.UserAgent = headerValue;
454+
break;
455+
default:
456+
// Some headers are restricted and would throw an exception:
457+
// http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.headers(v=vs.100).aspx
458+
// Also check for our custom list of headers that should not be sent (https://github.com/Esri/resource-proxy/issues/362)
459+
if (!System.Net.WebHeaderCollection.IsRestricted(headerKey) &&
460+
headerKeyLower != "accept-encoding" &&
461+
headerKeyLower != "proxy-connection" &&
462+
headerKeyLower != "connection" &&
463+
headerKeyLower != "keep-alive" &&
464+
headerKeyLower != "proxy-authenticate" &&
465+
headerKeyLower != "proxy-authorization" &&
466+
headerKeyLower != "transfer-encoding" &&
467+
headerKeyLower != "te" &&
468+
headerKeyLower != "trailer" &&
469+
headerKeyLower != "upgrade" &&
470+
toRequest.Headers[headerKey] == null)
471+
toRequest.Headers[headerKey] = headerValue;
472+
break;
473+
}
474+
}
475+
}
476+
477+
private void setRangeHeader(System.Net.HttpWebRequest req, string range)
478+
{
479+
string[] specifierAndRange = range.Split('=');
480+
if (specifierAndRange.Length == 2)
481+
{
482+
string specifier = specifierAndRange[0];
483+
string[] fromAndTo = specifierAndRange[1].Split('-');
484+
if (fromAndTo.Length == 2)
485+
{
486+
int from, to;
487+
if (int.TryParse(fromAndTo[0], out from) && int.TryParse(fromAndTo[1], out to))
488+
req.AddRange(specifier, from, to);
489+
}
490+
}
491+
}
492+
413493
private bool fetchAndPassBackToClient(System.Net.WebResponse serverResponse, HttpResponse clientResponse, bool ignoreAuthenticationErrors) {
414494
if (serverResponse != null) {
415495
using (Stream byteStream = serverResponse.GetResponseStream()) {
@@ -427,14 +507,14 @@ public class proxy : IHttpHandler {
427507
return true;
428508

429509
//Copy the header info and the content to the reponse to client
430-
copyHeaders(serverResponse, clientResponse);
510+
copyResponseHeaders(serverResponse, clientResponse);
431511
clientResponse.Write(strResponse);
432512
}
433513
} else {
434514
// Binary response (image, lyr file, other binary file)
435515

436516
//Copy the header info to the reponse to client
437-
copyHeaders(serverResponse, clientResponse);
517+
copyResponseHeaders(serverResponse, clientResponse);
438518
// Tell client not to cache the image since it's dynamic
439519
clientResponse.CacheControl = "no-cache";
440520
byte[] buffer = new byte[32768];
@@ -470,33 +550,28 @@ public class proxy : IHttpHandler {
470550
}
471551
}
472552

473-
return doHTTPRequest(uri, bytes, method, PROXY_REFERER, contentType, credentials);
553+
System.Net.HttpWebRequest req = createHTTPRequest(uri, method, contentType, credentials);
554+
req.Referer = PROXY_REFERER;
555+
writeRequestPostBody(req, bytes);
556+
return req.GetResponse();
474557
}
475558

476-
private System.Net.WebResponse doHTTPRequest(string uri, byte[] bytes, string method, string referer, string contentType, System.Net.NetworkCredential credentials = null)
559+
private System.Net.HttpWebRequest createHTTPRequest(string uri, string method, string contentType, System.Net.NetworkCredential credentials = null)
477560
{
478561
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
479562
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(uri);
480563
req.ServicePoint.Expect100Continue = false;
481-
req.Referer = referer;
482564
req.Method = method;
565+
if (method == "POST")
566+
req.ContentType = string.IsNullOrEmpty(contentType) ? "application/x-www-form-urlencoded" : contentType;
483567

484568
// Use the default system proxy
485569
req.Proxy = SYSTEM_PROXY;
486570

487571
if (credentials != null)
488572
req.Credentials = credentials;
489573

490-
if (bytes != null && bytes.Length > 0 || method == "POST") {
491-
req.Method = "POST";
492-
req.ContentType = string.IsNullOrEmpty(contentType) ? "application/x-www-form-urlencoded" : contentType;
493-
if (bytes != null && bytes.Length > 0)
494-
req.ContentLength = bytes.Length;
495-
using (Stream outputStream = req.GetRequestStream()) {
496-
outputStream.Write(bytes, 0, bytes.Length);
497-
}
498-
}
499-
return req.GetResponse();
574+
return req;
500575
}
501576

502577
private string webResponseToString(System.Net.WebResponse serverResponse) {

0 commit comments

Comments
 (0)