@@ -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