5

I recently wrote a reverse proxy using Titanium-Web-Proxy.

The browser accesses the reverse proxy through IP 127.0.0.1, port 80, and the reverse proxy forwards the browser's request to the IIS server at IP 127.0.0.1, port 2366.

+---------+    Request    +---------------+                 +------------+
|         +-------------> |               |     Request     |            |
|         |               | Reverse Proxy +---------------> | Web Server |
|         |               |               |                 |            |
| Browser |               | 127.0.0.1     |                 | 127.0.0.1  |
|         |               |               |    Response     |            |
|         |    Response   | 80            | <---------------+ 2366       |
|         | <-------------+               |                 |            |
+---------+               +---------------+                 +------------+

When I tested it, the reverse proxy did not work as I expected, and the browser returned an HTTP 400 error.

Bad Request - Invalid Hostname

HTTP Error 400. The request hostname is invalid.

I tried rewriting 127.0.0.1:2366 as localhost:2366 and retesting, and the error was the same.

Later I tried to change modifiedUri to http://example.com but got a 404 Not Found error.

var modifiedUri = new UriBuilder("http://example.com/");

This is my code, please do not mind my poor coding level.

public class Startup
{
    private readonly ProxyServer proxyServer;

    private readonly IDictionary<Guid, HeaderCollection> requestHeaderHistory = new ConcurrentDictionary<Guid, HeaderCollection>();

    private readonly IDictionary<Guid, HeaderCollection> responseHeaderHistory = new ConcurrentDictionary<Guid, HeaderCollection>();

    public Startup()
    {
        proxyServer = new ProxyServer()
        {
            TrustRootCertificate = true,
            ForwardToUpstreamGateway = true,
        };
    }

    public void Start()
    {
        proxyServer.BeforeRequest += OnRequest;
        proxyServer.BeforeResponse += OnResponse;

        var transparentProxyEndPoint = new TransparentProxyEndPoint(IPAddress.Loopback, 80, false)
        {

        };

        proxyServer.AddEndPoint(transparentProxyEndPoint);
        proxyServer.Start();
    }

    public void Stop()
    {
        proxyServer.BeforeRequest -= OnRequest;
        proxyServer.BeforeResponse -= OnResponse;
        proxyServer.Stop();
    }

    public async Task OnRequest(object sender, SessionEventArgs e)
    {
        var requestUri = e.WebSession.Request.RequestUri;
        var modifiedUri = new UriBuilder("http", "127.0.0.1", 2366, requestUri.AbsolutePath);

        e.WebSession.Request.RequestUri = modifiedUri.Uri;

        requestHeaderHistory[e.Id] = e.WebSession.Request.RequestHeaders;

        if (e.WebSession.Request.HasBody)
        {
            var bodyBytes = await e.GetRequestBody();
            await e.SetRequestBody(bodyBytes);

            string bodyString = await e.GetRequestBodyAsString();
            await e.SetRequestBodyString(bodyString);
        }
    }

    public async Task OnResponse(object sender, SessionEventArgs e)
    {
        responseHeaderHistory[e.Id] = e.WebSession.Response.ResponseHeaders;

        if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST")
        {
            if (e.WebSession.Response.ResponseStatusCode == (int)HttpStatusCode.OK)
            {
                if (e.WebSession.Response.ContentType != null && e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
                {
                    var bodyBytes = await e.GetResponseBody();
                    await e.SetResponseBody(bodyBytes);

                    string body = await e.GetResponseBodyAsString();
                    await e.SetResponseBodyString(body);
                }
            }
        }
    }
}
Garfield550
  • 584
  • 1
  • 8
  • 13
  • 1
    For anyone else using this, be careful about reading the request body in OnRequest and the response body in OnResponse. Titanium will send the data on its own, there is no reason to Get & Set, and it will cause problems in some scenarios e.g. 100 Continue requests. – JMH Feb 07 '19 at 21:51

1 Answers1

2

Solved!

I need rewrite the request hostname.

See Titanium-Web-Proxy issues #344.

Garfield550
  • 584
  • 1
  • 8
  • 13