Search code examples
javascriptc#.nethttpwebrequest

Why I get only part of the URL from the HttpContext?


I use proxy to get recource from remote server.

Here is proxy class:

public class Proxy : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string url = context.Request["url"];
        var request = (HttpWebRequest)WebRequest.Create(url);
        request.UserAgent = context.Request.UserAgent;
        request.ContentType = context.Request.ContentType;
        request.Method = context.Request.HttpMethod;

        request.ProtocolVersion = HttpVersion.Version11;
        request.KeepAlive = false;
        request.Timeout = 100000;
        request.ReadWriteTimeout = 100000;
        using (var response = request.GetResponse())
        {
            context.Response.ContentType = response.ContentType;
            using (var responseStream = response.GetResponseStream())
            {
                if (responseStream == null) return;

                responseStream.CopyTo(context.Response.OutputStream);
                context.Response.OutputStream.Flush();
            }
        }
    }
}

And here is my ajax call to remote service:

function wfs(layer) {

    let dest_url = "https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS&MAXFEATURES=500&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=ns216630453:WW_MONITOR";
    let proxy_url = "/localhost/Proxy.ashx?url=";
    let url = proxy_url + dest_url;

    var xhr = new XMLHttpRequest();
    xhr.open('GET', url); // depricated-'/proxy.ashx?url='+

    xhr.onload = function () {
        if (xhr.status === 200) {
            console.log("loader success");
        } else {
            console.log("loader fail");
        }
    },
        xhr.send();
}

when wfs function is fired the ProcessRequest function in proxy class is triggered and value of the url variable is:

https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS

While I expect the value of url to be:

https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS&MAXFEATURES=500&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=ns216630453:WW_MONITOR

It seems that context.Request["url"] returns cuted value until first '&'.

Any idea why I get from context.Request["url"] only part of the url?


Solution

  • You need to encode your query param, because it doesn't contain characters that are safe for query parameters:

    let url = "/localhost/Proxy.ashx?url=" + encodeURIComponent(dest_url);
    

    To further explain, let's pretend we're a URL parser. Without the encoding, you'll see this string:

    /localhost/Proxy.ashx?url=https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS&MAXFEATURES=500&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=ns216630453:WW_MONITOR
    

    The parser will go through these steps as it visits the characters:

    URL path:              /localhost/Proxy.ashx 
    Query params starting: ?
    Param name:            url
    Starting param value:  =
    (some of these next chars aren't valid, but I'll try my best!)
    Param value:        
       https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS
    Starting next param:   &
    Param name:            MAXFEATURES
    Starting param value:  =
    Param value:           500
    ...etc
    

    So because it's encountering the & while scanning your string, it thinks parameters like MAXFEATURES are query parameters for your proxy request, not part of the url parameter passed to the proxy request. Therefore, when your proxy code runs, it's seeing only things up to that &.

    Encoding the URL parameter will give you:

    /localhost/Proxy.ashx?url=https%3A%2F%2Fwww.mysited.com%2Fgeodata2055%2Fservice%2Fmapagent.fcgi%3FSERVICE%3DWFS%26MAXFEATURES%3D500%26VERSION%3D1.0.0%26REQUEST%3DGetFeature%26TYPENAME%3Dns216630453%3AWW_MONITOR
    

    With this, the parser now only see a url parameter passed to the proxy handler. When the proxy handler now parses the url parameter, it will decode it, giving you back your original dest_url

    As a general rule of thumb, never just use string concatenation to build URLs; URLs aren't made up of strings, they're made up of URL-encoded strings.