Click here to Skip to main content
Click here to Skip to main content

Simple HTTP Reverse Proxy with ASP.NET and IIS

By , 22 May 2004
 

Introduction

Sample Image - reverse-proxy.png

A reverse proxy is the same as a proxy except instead of delivering pages for internal users, it delivers them for external users. It can be used to take some load off web servers and provide an additional layer of protection. If you have a content server that has sensitive information that must remain secure, you can set up a proxy outside the firewall as a stand-in for your content server. When outside clients try to access the content server, they are sent to the proxy server instead. The real content resides on your content server, safely inside the firewall. The proxy server resides outside the firewall, and appears to the client to be the content server.

Where to use?

If you have an intranet with IP filtered security, you can offer the functionality of external consultation. You must just add the authentication system of your choice.

Functionality

This reverse proxy can run in two modes:

  • Mode 0: all web sites can be requested by clients with an URL like http://RevrseProxyURL/http//www.site.com/
  • Mode 1: only one web site can be requested. When the user requests the web application address, the proxy returns the content of this web site.

You can setup this mode in the web configuration file of you web application:

<appSettings>
    <!-- PROXY Mode
  0 : all web site can be requested by a client with 
      an url like <A href="http://reverseproxyurl/http//www.site.com/">http://ReverseProxyURL/http//www.site.com/</A>
  1 : Only on web site can be resuested by clients, \
      In this case Web Application uses RemoteWebSite variable 
      to deliver the content of the web site.
    -->
   <add key="ProxyMode" value="1" />
   <add key="RemoteWebSite" value="<A href="http://www.codeproject.com/">http://www.codeproject.com/</A>" />
</appSettings>

The code

Create an HttpHandler to intercept all requests:

using System;
using System.Configuration;
using System.Web;
using System.Net;
using System.Text;
using System.IO; 
namespace ReverseProxy
{
  /// <summary>
  /// Handler that intercept Client's request and deliver the web site
  /// </summary>

  public class ReverseProxy: IHttpHandler
  {
    /// <summary>
    /// Method calls when client request the server
    /// </summary>
    /// &;lt;param name="context">HTTP context for client</param>

    public void ProcessRequest(HttpContext context)
    {
      //read values from configuration 
      fileint proxyMode = 
        Convert.ToInt32(ConfigurationSettings.AppSettings["ProxyMode"]);
      string remoteWebSite = 
        ConfigurationSettings.AppSettings["RemoteWebSite"];
      string remoteUrl;
      if (proxyMode==0)
        remoteUrl= ParseURL(context.Request.Url.AbsoluteUri);
      //all site 
      acceptedelseremoteUrl= 
        context.Request.Url.AbsoluteUri.Replace("http://"+
        context.Request.Url.Host+
        context.Request.ApplicationPath,remoteWebSite);
      //only one site accepted
      //create the web request to get the remote stream
      HttpWebRequest request = 
        (HttpWebRequest)WebRequest.Create(remoteUrl);
      //TODO : you can add your own credentials system
      //request.Credentials = CredentialCache.DefaultCredentials;
      HttpWebResponse response;
      try
      {
        response = (HttpWebResponse)request.GetResponse ();
      }
      catch(System.Net.WebException we)
      {
        //remote url not found, send 404 to client 
        context.Response.StatusCode = 404;
        context.Response.StatusDescription = "Not Found";
        context.Response.Write("<h2>Page not found</h2>");
        context.Response.End();
        return;
      }
      Stream receiveStream = response.GetResponseStream();

      if ((response.ContentType.ToLower().IndexOf("html")>=0) 
        ||(response.ContentType.ToLower().IndexOf("javascript")>=0))
      {
        //this response is HTML Content, so we must parse it
        StreamReader readStream = 
          new StreamReader (receiveStream, Encoding.Default);
        Uri test = new Uri(remoteUrl);
        string content;
        if (proxyMode==0)
          content= ParseHtmlResponse(readStream.ReadToEnd(), 
            context.Request.ApplicationPath+"/http//"+test.Host);
        else
          content= ParseHtmlResponse(readStream.ReadToEnd(),
            context.Request.ApplicationPath);
        //write the updated HTML to the client
        context.Response.Write(content);
        //close streamsreadStream.Close();
        response.Close();
        context.Response.End();
      }
      else
      {
        //the response is not HTML 
        Contentbyte[] buff = new byte[1024];
        int bytes = 0;
        while( ( bytes = receiveStream.Read( buff, 0, 1024 ) ) > 0 )
        {
          //Write the stream directly to the client 
          context.Response.OutputStream.Write (buff, 0, bytes );
        }
        //close streams
        response.Close();
        context.Response.End();
      }
    }

    /// <summary>
    /// Get the remote URL to call
    /// </summary>
    /// <param name="url">URL get by client</param>
    /// <returns>Remote URL to return to the client</returns>

    public string ParseURL(string url)
    {
      if (url.IndexOf("http/")>=0)
      {
        string externalUrl=url.Substring(url.IndexOf("http/"));
        return externalUrl.Replace("http/","http://") ;
      }
      else
        return url;
    }

    /// <summary>
    /// Parse HTML response for update links and images sources
    /// </summary>
    /// <param name="html">HTML response</param>
    /// <param name="appPath">Path of application for replacement</param>
    /// <returns>HTML updated</returns>
    public string ParseHtmlResponse(string html,string appPath)
    {
      html=html.Replace("\"/","\""+appPath+"/");
      html=html.Replace("'/","'"+appPath+"/");
      html=html.Replace("=/","="+appPath+"/");
      return html;
    }
    ///
    /// Specifies whether this instance is reusable by other Http requests
    ///
    public bool IsReusable
    {
      get
      {
        return true;
      }
    }
  }
}

Configure the handler in web.config

You must add these lines in web.config file to redirect all user queries to the HTTPHandler:

<httpHandlers>
   <add verb="*" path="*" type="ReverseProxy.ReverseProxy, ReverseProxy" />
</httpHandlers>

Configure IIS

If you want to process a request with any file extension, then you need to change IIS to pass all requests through to the ASP.NET ISAPI extension. Add the HEAD, GET and POST verbs to all files with .* file extension and map those to the ASP.NET ISAPI extension - aspnet_isapi.dll (in your .NET framework directory). The complete range of mappings, includes the new .* mapping.

TODO's

Now, you can develop your own security system, based on form, Windows or passport authentication.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Vincent Brossier
Web Developer
France France
Member
Vincent Brossier is a software engineer from Paris, FRANCE, specializing in .Net.
Vincent is in charge of development of the Parisian university's Intranet, I take part in a nationnal project of numerical campus.
His role is to seek best technicals solutions to satisfy the 35000 users of this Intranet. Specialized in the development of distributed applications, vincent work primarily with technologies microsoft .NET (C#, ASP.NET, Webservices, SQLServer) even if he have also work with java technologies (Peer-to-peer sharing documents tool).
Vincent have also set up Open-Source solutions such as SPIP in nursery schools.
When he's not programming, he enjoys playing Guitar.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionNot Work in internetmemberDothanhhai2 Nov '12 - 9:57 
QuestionWhen size of page to display too big, hangs briefly, renders incomplete pagememberJim Cross23 Nov '11 - 8:53 
QuestionSpurious null character added to end of stream?memberSteven Hirschorn25 Aug '11 - 1:46 
Questionreverse proxy and WCF-Servicememberwalter.anna24 Jan '10 - 1:56 
Questionhow can i bypass the processrequest method?membervitiris4 Jan '10 - 18:11 
QuestionHow to set it up?membermaria_mir7 Jul '09 - 20:48 
AnswerRe: How to set it up?membermaria_mir12 Jul '09 - 22:18 
AnswerRe: How to set it up?membereric_ruck4 Aug '11 - 5:44 
GeneralSome changesmemberrickleb21 Mar '09 - 6:16 
GeneralRe: Some changesmemberMunirS30 Aug '09 - 2:04 
GeneralPour InfosmemberMember 210144124 Sep '08 - 3:34 
GeneralInstallation InstructionsmemberChris Spencer15 Jul '08 - 3:17 
GeneralRegarding Host Headermemberpmselvan_20005 Jul '08 - 8:29 
GeneralRe: Regarding Host HeadermemberMunirS30 Aug '09 - 1:56 
GeneralRe: Regarding Host HeadermemberStimphy21 Dec '09 - 15:03 
GeneralErrormemberVJLaks16 Jun '08 - 20:39 
GeneralDerivative WorkmemberPaul Johnston4 May '08 - 4:35 
GeneralErrorsmemberhanisacsouka13 Apr '08 - 2:32 
Generalhttp://www.site.com:8080/memberhanisacsouka12 Apr '08 - 8:05 
GeneralIIS 7.0memberbrice2nice13 Nov '07 - 10:50 
Generalenabling file downloadmembertarak4v5 Sep '07 - 19:49 
GeneralVery usefull for me. View my project for download files from rapidshare.com based on this sample [modified]memberW.M. Spon29 Jun '07 - 22:54 
GeneralI couldnt get it workmemberjeanmoura12 Apr '07 - 5:01 
Sorry Vincent, but I couldnt get the reverse proxy work. I tried install the demo in my IIS but it didnt work.
I have IIS 6 and I couldnt configure IIS, that file extension you mentioned.
What about the reverseproxy.dll? Should I configure it anywhere to get it run?
Should I create an virtual directory to this app?
Please help
 
best regards from Brazil
 
Jean
Questionimage path doesnt workmembernolovelust5 Apr '07 - 10:45 
AnswerRe: image path doesnt workmemberMySuperName11 Jan '09 - 21:51 
GeneralBisuitsmembersafari7501223 Mar '07 - 4:52 
GeneralHTTPS supportmemberDeason21 Nov '06 - 18:11 
GeneralReverse proxy apache and IISmemberharinath28 Oct '06 - 2:29 
General401 errormembermredlon14 Sep '06 - 2:18 
GeneralReverse proxy with .css and .aspx files.memberyashchawhan3 Aug '06 - 19:40 
GeneralRe: Reverse proxy with .css and .aspx files.memberMunirS30 Aug '09 - 1:39 
GeneralRe: Reverse proxy with .css and .aspx files.memberStimphy21 Dec '09 - 15:06 
QuestionReverse Proxymemberyashchawhan24 Jul '06 - 2:45 
GeneralTrailing slashmembereggsovereasy17 Apr '06 - 3:49 
GeneralRe: Trailing slashmemberRitchie Carroll13 Jun '06 - 10:11 
AnswerRe: Trailing slashmemberUL-Tomten16 Jan '08 - 7:54 
Generaljavascript and postbackmembertomanyquestions19 Mar '06 - 23:30 
GeneralCaching imagesmemberpratz1722 Feb '06 - 19:03 
Question..what about conversion to VS 2005??membernikolair16 Nov '05 - 4:27 
GeneralPass values from .aspx page to remote URL that contains an asp pagesussAnonymous18 Oct '05 - 20:10 
GeneralW2k3 / IIS 6memberDavid Llamas15 Jul '05 - 17:44 
AnswerRe: W2k3 / IIS 6membertarak4v9 Sep '07 - 22:10 
GeneralAccess Denied...memberRitchie Carroll28 Jun '05 - 4:03 
GeneralRe: Access Denied...memberRitchie Carroll29 Jun '05 - 10:59 
GeneralUnit Testing ReverseProxymemberbtakita25 May '05 - 11:49 
GeneralCant see imagesmemberpratz1728 Apr '05 - 3:08 
GeneralRe: Cant see imagesmemberRitchie Carroll28 Jun '05 - 3:57 
JokeRe: Cant see imagesmemberUL-Tomten16 Jan '08 - 7:56 
GeneralAdding Session HandlingmemberDavid Osbourn10 Mar '05 - 6:01 
GeneralRe: Adding Session HandlingmemberVincent Brossier10 Mar '05 - 8:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 23 May 2004
Article Copyright 2004 by Vincent Brossier
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid