Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Certain URLPatterns don't work; missing 'not' condition #21

Closed
screenspan opened this issue Feb 16, 2024 · 8 comments
Closed

Certain URLPatterns don't work; missing 'not' condition #21

screenspan opened this issue Feb 16, 2024 · 8 comments

Comments

@screenspan
Copy link

SHORT DESCRIPTION

We'd like to be able to

  • a) bypass the Service Worker for multiple URL patterns; or
  • b) use the Service Worker to fetch all URLs except certain URL patterns

CURRENT BEHAVIOR

Google Version 123.0.6289.0 (Developer Build) (arm64) on Mac OS 14.3.1
Date: 2024-02-16

The URL Pattern API does allow for alternates using |, e.g.
image

But using alternates doesn't currently work in the Service Worker Static Routing API. The following code results in an error:

self.addEventListener('install', event => {
  if (event.addRoutes) {
    event.addRoutes([
      {
        condition: {
          urlPattern: new URLPattern({ pathname: "/(collections|search|621532|account|pages|cart|checkout)/*" })
        },
        source: "network"
      },
    ]);
  }
});

image

We therefore have to resort to a verbose way of declaring multiple patterns that does let us bypass the Service Worker:

self.addEventListener('install', event => {
  if (event.addRoutes) {
    event.addRoutes([
      {
        condition: {
          urlPattern: new URLPattern({pathname: "/collections*"})
        },
        source: "network"
      },

      {
        condition: {
          urlPattern: new URLPattern({pathname: "/search*"})
        },
        source: "network"
      },
      {
        condition: {
          urlPattern: new URLPattern({pathname: "/621532*"})
        },
        source: "network"
      },
      {
        condition: {
          urlPattern: new URLPattern({pathname: "/account*"})
        },
        source: "network"
      },
      {
        condition: {
          urlPattern: new URLPattern({pathname: "/pages*"})
        },
        source: "network"
      },
      {
        condition: {
          urlPattern: new URLPattern({pathname: "/cart*"})
        },
        source: "network"
      },
      {
        condition: {
          urlPattern: new URLPattern({pathname: "/checkouts*"})
        },
        source: "network"
      },
      {
        condition: {
          urlPattern: new URLPattern({pathname: "/"})
        },
        source: "network"
      }]);
  }
});

Result: A matched URL is fetched from the network as per Service Worker Static Routing API.
image

DESIRED BEHAVIOR

Pattern alternatives

Use pattern alternatives separated by a pipe character, e.g.

self.addEventListener('install', event => {
  if (event.addRoutes) {
    event.addRoutes([
      {
        condition: {
          urlPattern: new URLPattern({ pathname: "/(collections|search|621532|account|pages|cart|checkout)/*" })
        },
        source: "network"
      },
    ]);
  }
});

Exclude URL patterns using 'not' condition

Add all routes except for certain patterns by using a not condition, as the URL Pattern API apparently doesn't have a way to exclude patterns.

self.addEventListener('install', event => {
  if (event.addRoutes) {
    event.addRoutes([
      {
        condition: {
          not: [{ // This would be helpful!
            urlPattern: new URLPattern({ pathname: "/(collections|search|621532|account|pages|cart|checkout)/*" })
          }]
        },
        source: "fetch-event"
      },
    ]);
  }
});

Show 'Source' in Network Panel

Currently routed via Service Worker Static Routing API are annotated by (ServiceWorker router) in the Network panel.
image

Ideally, the source would also be displayed, e.g.
(ServiceWorker: routed to network)

@sisidovski
Copy link
Collaborator

Thank you @screenspan for reporting this!

Currently the API intentionally prohibits the URLPattern input with having regular expressions because from security concerns. Although it's not merged yet, we have a mention in the proposed spec.
https://github.com/w3c/ServiceWorker/pull/1701/files#diff-7bdebf23eab87aaf2676a41586076394031b6b98fde24e35d1672aa65a1cc0feR3373-R3375

You can check if your URLPattern input has a regexp or not, by using hasRegExpGroups.

new URLPattern({pathname: '/(collections|search|621532|account|pages|cart|checkout)/*'}).hasRegExpGroups
=> true

We therefore have to resort to a verbose way of declaring multiple patterns that does let us bypass the Service Worker:

Agree, that's not a smart solution, but currently having multiple patterns is the right approach.

Show 'Source' in Network Panel

I understand this is important for the debug, but this is more like a chrome DevTools feature. If possible, could you file a bug to https://crbug.com/ ?

@yoshisatoyanagisawa
Copy link
Collaborator

Thank you for the report,

As @sisidovski mentioned, using regexp is intentionally prohibited. hasRegExpGroups has been introduced for checking that.

For the pattern you wrote, I suppose you can also use the or condition.

self.addEventListener('install', event => {
  if (event.addRoutes) {
    event.addRoutes([
      {
        condition: {
          or: [
            {urlPattern: new URLPattern({pathname: "/collections*"})},
            {urlPattern: new URLPattern({pathname: "/search*"})},
            {urlPattern: new URLPattern({pathname: "/621532*"})},
            {urlPattern: new URLPattern({pathname: "/account*"})},
            {urlPattern: new URLPattern({pathname: "/pages*"})},
            {urlPattern: new URLPattern({pathname: "/cart*"})},
            {urlPattern: new URLPattern({pathname: "/checkouts*"})},
            {urlPattern: new URLPattern({pathname: "/"})}
         ]
        },
        source: "network"
      }]);
  }
});

Unfortunately, Chromium only implements the or condition, and other conjunctive conditions are not implemented yet.

When you hover the network panel entry, router ID will be shown. You can find an associated source by checking the ID in the routes section shown in the Application panel. However, I understand it is not so convenient.

As @sisidovski mentioned, please feel free to file a crbug.

@screenspan
Copy link
Author

Hi @sisidovski and @yoshisatoyanagisawa , thanks for the additional information.

Using the or condition, as @yoshisatoyanagisawa suggested, did work for me.

If I understand the proposal for the final form of the API, a not condition will be added:

dictionary RouterNotCondition : RouterCondition {
  RouterCondition not;
};

I think that'll be helpful once implemented.

Are there any other restrictions on using the URL Pattern API with Static Routing besides custom RegExp groups?

I've filed a crbug for the DevTools feature request, so feel free to close this issue if you want.

@yoshisatoyanagisawa
Copy link
Collaborator

yoshisatoyanagisawa commented Feb 20, 2024

Are there any other restrictions on using the URL Pattern API with Static Routing besides custom RegExp groups?

Except for prohibiting use of a regular expression (or, what URLPattern think as a regular expression), there should not be any restrictions.

One thing you may need an attention to use URLPattern is that an implicit base URL configuration for short-hands. However, since you use the URLPattern object, you should not be affected.
It is discussed in whatwg/urlpattern#182, and the static routing API follows:
https://urlpattern.spec.whatwg.org/#other-specs-javascript

I do not come up with anything else.

@yoshisatoyanagisawa
Copy link
Collaborator

FYI, the "not" condition implementation is tracked in https://issues.chromium.org/issues/328565554.

@yoshisatoyanagisawa
Copy link
Collaborator

Note that the not condition has been implemented behind the flag (ServiceWorkerStaticRouterNotConditionEnabled).

@yoshisatoyanagisawa
Copy link
Collaborator

@yoshisatoyanagisawa
Copy link
Collaborator

Let me mark this resolved.

  • a regular expression pattern is not supported in ServiceWorker static routing API because the pattern is executed in the browser process, and there is a security concern to support executing arbitrary regular expressions there.
  • the "not" condition has been available since M127.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants