[WEBSOCKET_SPEC-170] Add examples to spec to clarify URI-template matching precendence Created: 11/Mar/13  Updated: 21/Mar/13  Resolved: 21/Mar/13

Status: Resolved
Project: websocket-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major
Reporter: dannycoward Assignee: dannycoward
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: final

 Description   

(from Jan)

@ServerEndpoint(value = "/different/

{param1}/{param2}")
public class WS2DifferentPathParamsServer {
@OnMessage
public String param(@PathParam("param1") boolean b1,
@PathParam("param2") char p2, String content) { return String.valueOf(b1) + String.valueOf(p2); }
}

@ServerEndpoint(value = "/{param1}

")
public class WSDirectStringPathParamServer {
@OnMessage
public String param(@PathParam("param1") String p1, String content)

{ return p1; }

}

When I try:
ws://localhost:8080/ws/different/true/0, the second endpoint is matched.



 Comments   
Comment by dannycoward [ 19/Mar/13 ]

This has revealed a number of issues. Here they are with the proposed fixes:-

1) The default container match scheme is not fully defined.

This shows up in cases where an incoming URI may potentially exact match one endpoint and also match another endpoint which uses a URI template. And potentially matches a third endpoint that uses another URI template. Which one gets the match ?

Here's what I propose:-

The container will attempt to match an incoming URI to an endpoint path (URI or level 1 URI-template) as follows:-
The container will recursively try to exact match the longest shared path prefix common to both incoming URI and endpoint path, done by stepping down the paths one segment at a time, using '/' as the separator.
If the shared path prefix is the same as the endpoint path and also the same as the incoming URI, then the paths match (end).
If the shared path prefix is the same as the endpoint path, but shorter than the incoming URI, then the paths do not match (end).
If the shared path prefix is the same as the incoming URI, but shorter than the endpoint path then the paths do not match (end).
Otherwise, there are more segments of both paths to compare, so taking the next segment of both incoming URI and endpoint paths:-
If the next segment of the endpoint path is not a variable, it cannot match the next segment in the incoming URI, otherwise the shared path prefix would have included this path, so in this case, the paths do not match (end).
If the next endpoint directory is a variable, assign the value of the variable in the endpoint path to the value of the segment in the incoming URI, and append the segment to the shared path prefix and call it the new shared path prefix. Now repeat the steps above using the new shared path prefix.

So, here are some examples of that in practice:-

suppose an endpoint has path /a/b/
the only incoming URI that matches this is /a/b/

suppose an endpoint is mapped to /a/

{var}
incoming URIs that do match: /a/b (with var=b), /a/apple (with var=apple)
URIs that do NOT match: /a, /a/b/c (because empty string and strings with reserved characters "/" are not valid URI-template level 1 expansions.)

suppose we have three endpoints and their paths:
endpoint A: /a/{var}

/c
endpoint B: /a/b/c
endpoint C: /a/

{var1}/{var2}
incoming URI: a/b/c matches B, not A or C, because an exact match is preferred.
incoming URI: a/d/c matches A with variable var=d, because like goldlocks, its just right
incoming URI: a/x/y/ matches C, with var1=x, var2=y

endpoint A: /{var1}

/d
endpoint B: /b/

{var2}

incoming URI: /b/d matches B with var2=d, not A with var1=b because the matching process works from left to right.

2) The ServerEndpointConfig.Configurator.matchesURI(URI incoming, String endpointPath) method cannot be supported without further specification changes.

There are two problems: one is, does a developer provided match overrule the default match algorithm ? And, second, if several *Configurator.matchesURI()'s report a match, which one wins ?

As I wrote last week, we could resolve this by saying configurator matchesURI wins over the default algorithm, and also imposing an order on the endpoints, though this latter part would be a bit tricky to specify properly. I suggested ordering what are currently Sets in the returns from the ServerApplicationConfig methods, define the precedence in relation to programmatically deployed endpoints. And use the order of all that to give an order of precendence of the configurators matchesURI results. But then we would still have the problem of how to order any annotated endpoints deployed as a result of a scan when there is no ServerApplicationConfig. Maybe we'd need some global priority ordering scheme...

The issue that's hard to get away from is that for a proper URI matching scheme, the scheme really needs to know ALL the endpoint paths in the application in order to determine a best match out of several candidates. Ordering the paths and picking off the first YES on a binary endpoint-level YES/NO match is a special case of that, and while we could define some kind of ordering, it neither feels especially useful nor simple to put into practice for developers.

So I hate to remove API at this point, but I am proposing removing the ServerEndpointConfig.Configurator.matchesURI() call and deferring the ability to override the matching scheme until the next version when we can define a proper application-level scheme for defining URI matching policies instead of trying to make it work at the endpoint level.

Comment by dannycoward [ 21/Mar/13 ]

resolved as proposed in the spec, examples added.

Generated at Fri Jul 03 17:35:55 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.