Skip to content
This repository has been archived by the owner on Jul 17, 2018. It is now read-only.

Adjusting absolute URLs in services

Christian Weiss edited this page Feb 20, 2016 · 1 revision

The gateway doesn't rewrite absolute URLs which are returned by the target service. Your services therefore must adjust them according to the sent proxy headers.

Typical examples for absolute URLs in APIs are API descriptions like Swagger. If you use "Swashbuckle" (Swagger for ASP.NET) you can overwrite the base url by setting c.RootUrl(req => GetRootUrl(req)); with the following implementation:

private static string GetRootUrl(HttpRequestMessage request)
{
    string scheme = null;
    string host = null;

    // Is there a "Forwarded" header?
    string forwarded = GetHeaderValue(request, "Forwarded");
    if (forwarded != null)
    {
        string[] parts = forwarded.Replace(" ", "").Split(';');

        foreach (var part in parts)
        {
            if (part != null && part.StartsWith("host=", StringComparison.OrdinalIgnoreCase))
            {
                host = part.Substring("host=".Length);
                if (host == string.Empty) host = null;
            }
            if (part != null && part.StartsWith("proto=", StringComparison.OrdinalIgnoreCase))
            {
                scheme = part.Substring("proto=".Length);
                if (scheme == string.Empty) scheme = null;
            }
        }
    }

    // Fallback to non-standard "X-Forwarded-Host"/"Port"
    string xForwardedHost = GetHeaderValue(request, "X-Forwarded-Host");
    if (host == null && xForwardedHost != null)
    {
        host = xForwardedHost;

        // in case there was no port in the host
        string xForwardedPort = GetHeaderValue(request, "X-Forwarded-Port");
        if (host.IndexOf(':') < 0 && xForwardedPort != null)
        {
            host += ":" + xForwardedPort;
        }
    }

    // take the current URI if there was no header
    scheme = scheme ?? GetHeaderValue(request, "X-Forwarded-Proto") ?? request.RequestUri.Scheme;
    host = host ?? (request.RequestUri.Host + ":" + request.RequestUri.Port.ToString());

    // relative path (Swashbuckle doesn't allow a trailing '/')
    string path = GetHeaderValue(request, "X-Forwarded-PathBase") ?? request.GetRequestContext().VirtualPathRoot.ToString();
    path = "/" + path.TrimStart('/');
    path = path.TrimEnd('/');

    return $"{scheme}://{host}{path}";
}

private static string GetHeaderValue(HttpRequestMessage request, string headerName)
{
    IEnumerable<string> list;
    return request.Headers.TryGetValues(headerName, out list) ? list.FirstOrDefault() : null;
}
Clone this wiki locally