websocket-spec
  1. websocket-spec
  2. WEBSOCKET_SPEC-170

Add examples to spec to clarify URI-template matching precendence

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Labels:
      None

      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.

        Activity

        Hide
        dannycoward added a comment -

        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.

        Show
        dannycoward added a comment - 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.
        Hide
        dannycoward added a comment -

        resolved as proposed in the spec, examples added.

        Show
        dannycoward added a comment - resolved as proposed in the spec, examples added.

          People

          • Assignee:
            dannycoward
            Reporter:
            dannycoward
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: