redbird icon indicating copy to clipboard operation
redbird copied to clipboard

Custom resolver, host and url rewriting

Open ArnaudParant opened this issue 9 years ago • 6 comments

Hello,

I would like to defined a custom resolver to wildcard domain routing and do some redirection.

Configuration

{
    "proxy": {
        "redirections": [
            {"from":"/foo","to":"something:9100"},
            {"from":"/bar","to":"anotherapi:9102"},
        ]
    }
}

Code

function custom_resolver(host, url)
{
  var redirections = conf.proxy.redirections

  for (var i in redirections)
  {
    var red = redirections[i];
    var start = new RegExp("^"+ red.from)
    if (start.test(url))
    {
      var rhost = "http://"+ red.to;
      var rurl = url.replace(start, "")
      return rhost + rurl;
    }
  }

};

But custom revoler only return host i guess ? So I can not "rewrite" the url. The above code does not work as expected: 10.0.0.42/foo/folder -> http://something:9100/folder/foo/folder Because I it return http://something:9100/folder and the original url is added at the end /foo/folder

However it is possible to "rewrite" the url with proxy.register, but not the host. proxy.register("10.0.0.42/foo", "http://something:9100") It do the url "rewriting" but only works when we access to 10.0.0.42, if there is another ip to connect the server, like 172.17.0.5, it does not works.

Is there any way to do this ? Did I miss something ? May be I have to return from custom_resolver another type, like an object, (an array does not works) ? Is there a maner to combine the both solution ?

King regards, Arnaud

ArnaudParant avatar Aug 02 '16 09:08 ArnaudParant

Did you try to return an object with url (the target host), and path 'folder' ?

manast avatar Aug 02 '16 22:08 manast

Hi, Actually, no, I didn't.

original return rhost + rurl new return {url:rhost, path:rurl}

request url 10.0.0.60/foo/collections resolved url (by my custom resolver) host http://something:9100 url /collections

I getting the following message from the proxy

{"name":"redbird","hostname":"38b1c9cc8e81","pid":1,"level":40,"src":"10.0.0.60","url":"/foo/collections","msg":"no valid route found for given source","time":"2016-08-04T13:42:11.543Z","v":0}
  • I m not sure if the url field (the target host), must start with protocol, such "http://". I tried with and without, it changed nothing.
  • Same for the path, I tried, starting by / and not, it changed nothing as well.

ArnaudParant avatar Aug 04 '16 14:08 ArnaudParant

After a quick look to the code: https://github.com/OptimalBits/redbird/blob/master/lib/proxy.js

The error came from _getTarget, line 448: this.log && this.log.warn({src: src, url: req.url}, 'no valid route found for given source');

Which is due, I think, of the return condition from resolve, line 401: startsWith(url, route.path) I don't really understand this condition, the request url must start with the routing path ?

There is also in line 472 and 475 from _getTarget function:

// Fix request url if targetname specified.
req.url = path.join(target.pathname, req.url);

Which I think, does not allow to do what I want any way, rewrite the url and the path in the same time ?

ArnaudParant avatar Aug 04 '16 14:08 ArnaudParant

I will have to look deeper into it, but if it is not possible to do it then we need to rethink the custom resolvers design.

manast avatar Aug 05 '16 20:08 manast

Is this limitation still valid? I'm evaluating reverse proxies and that's something I would need. Overall, GREAT project!

guilhermeaiolfi avatar May 09 '19 18:05 guilhermeaiolfi

https://github.com/backrunner/redbird/commit/7ae14a95ddf131dc6ce369e2446d7d669e2f5219 ↑ I just made this commit in my fork.

In the _getTarget method, req.url will always be added after target.pathname when req.url exists, so if you want to rewrite a URL, you can add a specific flag to the route object (i.e. the object returned in the buildRoute method) like my modification.

In my modification, if the custom resolver return a object that contains a property named rewriteTo, in the buildRoute method, the value will be passed to route.url, and a flag named isRewrite will be added to the routeObject. Then in the _getTarget method, when the flag exists, I use the target.pathname directly. The modification can perform a URL Rewriting well.

backrunner avatar Apr 19 '21 18:04 backrunner