private ProxyInfo GetProxyInfo(Host host) { var proxyInfo = (ProxyInfo)host.Cache.Get(ProxyInfoCacheKey); if (proxyInfo == null) { var x = _rest .GetEndpointXml(host,2, "remoting/proxyinfo.xml", false); proxyInfo = new ProxyInfo(); var e = x.Descendants("UrlPattern").FirstOrDefault(); if (e != null) proxyInfo.ShouldProxy = new Regex(e.Value, RegexOptions.Singleline | RegexOptions.IgnoreCase); e = x.Descendants("HttpRequestHeaders").FirstOrDefault(); if (e != null) proxyInfo.RequestHeaders = e.Descendants("string").Select(y => y.Value).ToArray(); else proxyInfo.RequestHeaders = new string[0]; e = x.Descendants("HttpResponseHeaders").FirstOrDefault(); if (e != null) proxyInfo.ResponseHeaders = e.Descendants("string").Select(y => y.Value).ToArray(); else proxyInfo.ResponseHeaders = new string[0]; host.Cache.Put(ProxyInfoCacheKey, proxyInfo, 60 * 10); } return proxyInfo; }
private void ProcessProxiedResponse(Host host, System.Web.HttpContextBase context, ProxyInfo proxyInfo, HttpWebRequest request, HttpWebResponse response, string cacheKey) { var buffer = new byte[8 * 1024]; int read; CachedProxyResponse cachedResponse = null; var cacheInfo = (request.Method != "GET") ? null : GetCacheInfo(response); MemoryStream cachedOutput = null; if (cacheInfo != null && ((cacheInfo.IsPublic && response.ContentLength < 256 * 1024 && ((int)response.StatusCode) - 200 < 100) || response.ContentLength < 64 * 1024)) { cachedResponse = new CachedProxyResponse { Headers = new Dictionary<string, string>(), Status = ((int)response.StatusCode), StatusDescription = response.StatusDescription }; cachedOutput = new MemoryStream(); } context.Response.StatusCode = (int)response.StatusCode; context.Response.StatusDescription = response.StatusDescription; context.Response.TrySkipIisCustomErrors = true; foreach (string name in proxyInfo.ResponseHeaders) { if (!string.IsNullOrEmpty(response.Headers[name])) { if (RestrictedResponseHeaders.ContainsKey(name)) AttemptSetRestrictedHeader(context.Response, name, response.Headers[name]); else context.Response.Headers[name] = response.Headers[name]; if (cachedResponse != null) cachedResponse.Headers[name] = response.Headers[name]; } } using (var outStream = context.Response.OutputStream) { using (var inStream = response.GetResponseStream()) { while ((read = inStream.Read(buffer, 0, buffer.Length)) > 0) { outStream.Write(buffer, 0, read); outStream.Flush(); if (cachedOutput != null) cachedOutput.Write(buffer, 0, read); } inStream.Close(); } outStream.Close(); } if (cacheInfo != null && cachedResponse != null && cachedOutput != null && cachedOutput.Length < 256000) { cachedResponse.Content = cachedOutput.ToArray(); if (cacheInfo.IsPublic) host.Cache.Put(cacheKey, cachedResponse, cacheInfo.CacheDurationSeconds); else System.Web.HttpContext.Current.Items[cacheKey] = cachedResponse; } }
private void Proxy(Host host, System.Web.HttpContextBase context, string url, ProxyInfo proxyInfo) { CachedProxyResponse cachedResponse = null; string cacheKey = null; if (context.Request.HttpMethod == "GET") { cacheKey = string.Concat(host.Name, url); cachedResponse = (CachedProxyResponse)System.Web.HttpContext.Current.Items[cacheKey]; if (cachedResponse == null) cachedResponse = (CachedProxyResponse)host.Cache.Get(cacheKey); if (cachedResponse != null) { context.Response.StatusCode = cachedResponse.Status; context.Response.StatusDescription = cachedResponse.StatusDescription; context.Response.TrySkipIisCustomErrors = true; foreach (string name in cachedResponse.Headers.Keys) { if (RestrictedResponseHeaders.ContainsKey(name)) AttemptSetRestrictedHeader(context.Response, name, cachedResponse.Headers[name]); else context.Response.Headers[name] = cachedResponse.Headers[name]; } using (var outputStream = context.Response.OutputStream) { outputStream.Write(cachedResponse.Content, 0, cachedResponse.Content.Length); outputStream.Close(); } return; } } bool retry = true; HttpWebRequest request = null; while (retry) { retry = false; try { request = (HttpWebRequest)WebRequest.Create(MakeFullUrl(host, url)); request.Method = context.Request.HttpMethod; request.Timeout = context.Request.HttpMethod == "GET" ? host.GetTimeout : host.PostTimeout; host.ApplyAuthenticationToHostRequest(request, true); host.ApplyRemoteHeadersToRequest(request); foreach (string name in proxyInfo.RequestHeaders) { if (name.StartsWith("Cookie:")) { var cookieName = name.Substring(7); var cookie = context.Request.Cookies[cookieName]; if (cookie != null) { if (request.CookieContainer == null) request.CookieContainer = new CookieContainer(); request.CookieContainer.Add(new Cookie(cookieName, cookie.Value, "/", request.RequestUri.Host)); } } else { var value = context.Request.Headers[name]; if (!string.IsNullOrEmpty(value)) { if (WebHeaderCollection.IsRestricted(name)) AttemptSetRestrictedHeader(request, name, value); else request.Headers[name] = value; } } } if (request.Method == "POST") { // assume the content type is x-www-form-urlencoded if it isn't set (not great, but this occurs in the wild) if (string.IsNullOrEmpty(request.ContentType) || request.ContentType.StartsWith("application/x-www-form-urlencoded")) { var buffer = new byte[(int)context.Request.ContentLength]; using (var inStream = context.Request.InputStream) { inStream.Read(buffer, 0, buffer.Length); inStream.Close(); } try { buffer = Encoding.UTF8.GetBytes(host.ResolveRemoteUrlsToHostUrls(Encoding.UTF8.GetString(buffer))); } catch { // this is likely because the content type wasn't set correctly, ignore. } request.ContentLength = buffer.Length; using (var outStream = request.GetRequestStream()) { outStream.Write(buffer, 0, buffer.Length); outStream.Close(); } } else { request.ContentLength = context.Request.ContentLength; var buffer = new byte[8 * 1024]; int read; using (var inStream = context.Request.InputStream) { using (var outStream = request.GetRequestStream()) { while ((read = inStream.Read(buffer, 0, buffer.Length)) > 0) { outStream.Write(buffer, 0, read); } outStream.Close(); } inStream.Close(); } } } using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { ProcessProxiedResponse(host, context, proxyInfo, request, response, cacheKey); } } catch (WebException ex) { var errorResponse = ex.Response as HttpWebResponse; if (errorResponse != null) { if (errorResponse.StatusCode == HttpStatusCode.Forbidden && host.RetryFailedRemoteRequest(request)) retry = true; if (!retry) ProcessProxiedResponse(host, context, proxyInfo, request, errorResponse, cacheKey); } else throw; } } }