librelist archives

« back to archive

routing breaks any sub paths of a route

routing breaks any sub paths of a route

From:
Mathijs Kwik
Date:
2011-08-12 @ 15:26
Hi,

I have some trouble getting routes working the way I want.
I have this config:

proxy_to_rails = Proxy(addr="10.2.1.23", port=3000)
proxy_to_node = Proxy(addr="10.2.1.23", port=3500)

my_host = Host(name="localhost", routes={
  "/": proxy_to_rails,
  "/socket.io/(.+)": proxy_to_node
})

Now, issuing request to most urls, get routed to rails.
/socket.io/blah gets routed to node

but /sock gives me a 404 Not Found, while the log gives
[ERROR] (src/connection.c:108: errno: Resource temporarily
unavailable) Handler not found: /sock

Now, reading the documentation tells me this is the expected
behaviour, since it will have the longest match with the /socket.io
prefix, but then fail the pattern and return 404. So I see mongrel2 is
just working as advertised, however, this is not at all what I want!
I want a route that only matches /socket.io in full, a partial match
should just be routed to the default route. In other words, I don't
mind that it matches the socket.io prefix best, however after failing
the pattern, it should pick the next-best route.
Otherwise, mongrel's routing behaviour will break all substring routes
for every route configured.

In my case, the default (rails) app has a nice 404 handler, doing a
search and trying to approximate what you were after.
So if people wanted to search for "sock" by using /sock it breaks.
Also, if I want to chip out user-management/profiles to a new, handler
based app, available on /users, it will break the /us path (default
path for US visitors). So it forces me to think about all possible
substring paths affected for all routes I put into mongrel's config.

So, my question is: Is this really the correct behaviour here? If so,
why was this chosen, what advantages does it provide?
And: how can I work around this behaviour to get full matches only
without breaking sub-matches?

Thanks,
Mathijs

Re: [mongrel2] routing breaks any sub paths of a route

From:
Zed A. Shaw
Date:
2011-08-12 @ 17:10
On Fri, Aug 12, 2011 at 05:26:30PM +0200, Mathijs Kwik wrote:
> Hi,
> 
> I have some trouble getting routes working the way I want.
> I have this config:
> 
> proxy_to_rails = Proxy(addr="10.2.1.23", port=3000)
> proxy_to_node = Proxy(addr="10.2.1.23", port=3500)
> 
> my_host = Host(name="localhost", routes={
>   "/": proxy_to_rails,
>   "/socket.io/(.+)": proxy_to_node
> })
> 
> Now, issuing request to most urls, get routed to rails.
> /socket.io/blah gets routed to node

This *may* be part of the bug I just fixed in development.  The routing
was a bit screwed up.  Can you try this with the github/develop branch
and let me know if it does or does not work.

> So, my question is: Is this really the correct behaviour here? If so,
> why was this chosen, what advantages does it provide?
> And: how can I work around this behaviour to get full matches only
> without breaking sub-matches?

As for figuring out sub pattern matches, there's kind of a problem with
how you want it vs. how someone else wants it.  In other words, defining
"best" is subjective and depends on the route.  In your case you want
"best" to mean:

* No matter what, match at least one of these.

Other people think of best as:

* Match the shortest one you can find with the best full pattern.

Still others think best is:

* Match the longest one you can find with the best full pattern.

So I went with this last one mostly for efficiency.  To do the "no
matter what match soemthing" I'd have to pull up *all* possible matches,
in order, and try one until I found something.  It's not hard, but it's
definitely less efficient.

I think in the develop branch your specific problem is solved, but
double check it and then report back.  I can try to tease out a setting
that might make the routes work the way you want and solve a couple
other edge cases.

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] routing breaks any sub paths of a route

From:
Mathijs Kwik
Date:
2011-08-12 @ 18:11
On Fri, Aug 12, 2011 at 7:10 PM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
> On Fri, Aug 12, 2011 at 05:26:30PM +0200, Mathijs Kwik wrote:
>> Hi,
>>
>> I have some trouble getting routes working the way I want.
>> I have this config:
>>
>> proxy_to_rails = Proxy(addr="10.2.1.23", port=3000)
>> proxy_to_node = Proxy(addr="10.2.1.23", port=3500)
>>
>> my_host = Host(name="localhost", routes={
>>   "/": proxy_to_rails,
>>   "/socket.io/(.+)": proxy_to_node
>> })
>>
>> Now, issuing request to most urls, get routed to rails.
>> /socket.io/blah gets routed to node
>
> This *may* be part of the bug I just fixed in development.  The routing
> was a bit screwed up.  Can you try this with the github/develop branch
> and let me know if it does or does not work.

It seems I was on the development branch, pulled this morning, but
it's up to date (I checked just now).

>
>> So, my question is: Is this really the correct behaviour here? If so,
>> why was this chosen, what advantages does it provide?
>> And: how can I work around this behaviour to get full matches only
>> without breaking sub-matches?
>
> As for figuring out sub pattern matches, there's kind of a problem with
> how you want it vs. how someone else wants it.  In other words, defining
> "best" is subjective and depends on the route.  In your case you want
> "best" to mean:
>
> * No matter what, match at least one of these.
>
> Other people think of best as:
>
> * Match the shortest one you can find with the best full pattern.
>
> Still others think best is:
>
> * Match the longest one you can find with the best full pattern.
>
> So I went with this last one mostly for efficiency.  To do the "no
> matter what match soemthing" I'd have to pull up *all* possible matches,
> in order, and try one until I found something.  It's not hard, but it's
> definitely less efficient.

Well, I can see there's different definitions of "best", but the way
it currently works, it just masks entire paths, if a longer match
exists.
So the documentation is at least a bit misleading when talking about
PREfixes, because /blah is not a prefix for /bla, because /bla doesn't
start with /blah.

Right now, if I want to have a handler on /users, I need to make sure
there are no legitimate uses of "/user", "/use" or "/us", in case
there are legitimate cases, I'm screwed because the handler for /users
will either eat them (and choke), or have it fail on a pattern.

It gets worse. If I have my site administration on /admin, and have a
special handler for payments and want to stick that on
/admin/payments, /admin gets blocked out. Although the manual
describes that this is the way it works, I would argue it doesn't feel
natural.

Even trying to work around it seems hard.
When using "/admin()" -> handler1 and "/admin/(payments)" -> handler2,
which will get chosen for "/admin" ? they both match the same length.
Worse, "/admin/accounts" will use the second prefix (because of the /
after admin) and fail because of pattern matching.
So the only solution is to tell mongrel2 about all paths below /admin
for this backend.
That sounds like a lot of duplication, especially since mongrel
doesn't want to do the handler's work as you answered to my earlier
question.

So it seems the only "safe" solution that doesn't need a ton of routes
is to just stick handlers on short paths at the root like '/x' to make
sure there are no clashes :)

Maybe this is a bit exaggerated, but it would be nice if this behavior
could be adjustable.
Taking the longest match is fine, but for me, it would make more sense
to only accept full matches (that's why it's called PREfix right?), I
don't even need the pattern matching second phase (just a $ to specify
"no characters after this" will be enough).

So with this config:
/ -> handler1
/users -> handler2
/users/special -> handler3

this output:
/ -> handler1
/us -> handler1
/users -> handler2
/users/spec -> handler2
/users/john -> handler2
/users/special -> handler3

Is that really such a strange thing to wish for?
Or a performance killer?

Thanks,
Mathijs

>
> I think in the develop branch your specific problem is solved, but
> double check it and then report back.  I can try to tease out a setting
> that might make the routes work the way you want and solve a couple
> other edge cases.
>
> --
> Zed A. Shaw
> http://zedshaw.com/
>

Re: [mongrel2] routing breaks any sub paths of a route

From:
Zed A. Shaw
Date:
2011-08-13 @ 16:01
On Fri, Aug 12, 2011 at 08:11:14PM +0200, Mathijs Kwik wrote:
> Well, I can see there's different definitions of "best", but the way
> it currently works, it just masks entire paths, if a longer match
> exists.
> ...

Too many words.  How about you do this:

given: Write two (or more) routes.
when: Write one request.
then: Write which route should win.

Do up 5-6 of these, I'll put them in the test case for routing and make
them work, or I'll tell you how to make it work (or I'll tell you to
quit trying to cram rails' routing into Mongrel2).

Here's an example:

given:  / -> A, /people/(.*) -> B
when: /perfect.txt
then: returns A

Deal?

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] routing breaks any sub paths of a route

From:
Mathijs Kwik
Date:
2011-08-13 @ 17:02
given:  / -> A, /users -> B, /users/special -> C, /users/admin$ -> D
when: /
then: A
when: /us
then: A
when: /users
then: B
when: /users/spec
then: B
when: /users/john
then: B
when: /users/special
then: C
when: /users/admi
then: B
when: /users/admin
then: D
when: /users/admin/index
then: B

Thanks


On Sat, Aug 13, 2011 at 6:01 PM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
> On Fri, Aug 12, 2011 at 08:11:14PM +0200, Mathijs Kwik wrote:
>> Well, I can see there's different definitions of "best", but the way
>> it currently works, it just masks entire paths, if a longer match
>> exists.
>> ...
>
> Too many words.  How about you do this:
>
> given: Write two (or more) routes.
> when: Write one request.
> then: Write which route should win.
>
> Do up 5-6 of these, I'll put them in the test case for routing and make
> them work, or I'll tell you how to make it work (or I'll tell you to
> quit trying to cram rails' routing into Mongrel2).
>
> Here's an example:
>
> given:  / -> A, /people/(.*) -> B
> when: /perfect.txt
> then: returns A
>
> Deal?
>
> --
> Zed A. Shaw
> http://zedshaw.com/
>

Re: [mongrel2] routing breaks any sub paths of a route

From:
Zed A. Shaw
Date:
2011-08-14 @ 19:10
On Sat, Aug 13, 2011 at 07:02:25PM +0200, Mathijs Kwik wrote:
> given:  / -> A, /users -> B, /users/special -> C, /users/admin$ -> D
> when: /
> then: A
> when: /us
> then: A
> when: /users
> then: B
> when: /users/spec
> then: B
> when: /users/john
> then: B
> when: /users/special
> then: C
> when: /users/admi
> then: B
> when: /users/admin
> then: D
> when: /users/admin/index
> then: B

Ok, I'll work out what this is and make it work and show you how to do
it.  Remember, Mongrel2 isn't supposed to be the Big Super Rails Router
In The Sky.  So, in the above example I'd have /users/(.*)/ -> X, and X
is an app that handles users.

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] routing breaks any sub paths of a route

From:
Mathijs Kwik
Date:
2011-08-14 @ 20:17
On Sun, Aug 14, 2011 at 9:10 PM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
> On Sat, Aug 13, 2011 at 07:02:25PM +0200, Mathijs Kwik wrote:
>> given:  / -> A, /users -> B, /users/special -> C, /users/admin$ -> D
>> when: /
>> then: A
>> when: /us
>> then: A
>> when: /users
>> then: B
>> when: /users/spec
>> then: B
>> when: /users/john
>> then: B
>> when: /users/special
>> then: C
>> when: /users/admi
>> then: B
>> when: /users/admin
>> then: D
>> when: /users/admin/index
>> then: B
>
> Ok, I'll work out what this is and make it work and show you how to do
> it.  Remember, Mongrel2 isn't supposed to be the Big Super Rails Router
> In The Sky.  So, in the above example I'd have /users/(.*)/ -> X, and X
> is an app that handles users.

I understand, and I don't want it to be the big router thing.
Most of the time I think I'll just have / to a proxy and one or 2
routes for handlers.
But I don't want to add all kinds of extra routes to the default
proxy, just because they would otherwise be "masked out" (like /us for
us customers when /users is another handler)

But I'll see what you come up with :)
Thanks

>
> --
> Zed A. Shaw
> http://zedshaw.com/
>

Re: [mongrel2] routing breaks any sub paths of a route

From:
Zed A. Shaw
Date:
2011-08-14 @ 20:28
On Sun, Aug 14, 2011 at 10:17:13PM +0200, Mathijs Kwik wrote:
> > Ok, I'll work out what this is and make it work and show you how to do
> > it.  Remember, Mongrel2 isn't supposed to be the Big Super Rails Router
> > In The Sky.  So, in the above example I'd have /users/(.*)/ -> X, and X
> > is an app that handles users.
> 
> But I don't want to add all kinds of extra routes to the default
> proxy, just because they would otherwise be "masked out" (like /us for
> us customers when /users is another handler)

Yeah, I'll look at fixing that, and report back what I got.

-- 
Zed A. Shaw
http://zedshaw.com/