public string MakeFullUrl(Host host, string url) { if (string.IsNullOrEmpty(url) || url.StartsWith("#")) return url; // support app-relative urls mapped to the Evolution Root if (url.StartsWith("~/")) url = url.Substring(2); Uri baseUrl = new Uri(host.EvolutionRootUrl); Uri combinedUrl = new Uri(baseUrl, url); string[] components = combinedUrl.AbsoluteUri.Split(new char[] { '?' }, 2); if (components.Length == 2) components[1] = host.ResolveRemoteUrlsToHostUrls(components[1]); return string.Join("?", components); }
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; } } }