jcubic / wayne

Service Worker Routing library for in browser HTTP requests
https://jcubic.github.io/wayne
MIT License
556 stars 29 forks source link

Add route capture handler in fetch listener #32

Closed jonsam-ng closed 6 months ago

jonsam-ng commented 7 months ago

What is it

There is a need for me to not proxy all routes by fetch listener, if a route capture handler is provided outside event.respondWith, that could be helpful.

self.addEventListener("fetch", (event) => {
  if(routeCapture(event.request)) {
    event.respondWith(promise.catch(() => {}));
  }
});

routeCapture could be like this:

({ request }) => isMatch(request)

In workbox, a capture is like:

RegExp | string | RouteMatchCallback | Route

Why I want this

In current case, a normal route of request that not registered by app could resolve by fetch as following:

fetch(event.request).then(resolve).catch(reject);

In my experience, a fetch proxy by service worker could lead to some unknown problems that's what concerns me. For example, the referer header of request could be modified to sw.js if it's proxy by fetch.

jcubic commented 7 months ago

Can you provide an example where this is a problem?

jonsam-ng commented 7 months ago

Yes, what I want to see is a like a whitelist for fetch listener for the reason as service worker may incorrectly set some request headers for the request, especially Referrer, User-Agent headers that I known from IOS safari and Firefox.

Request header behaviors for browsers

In Safari, when fetching resources via a service worker, the Referer header appears as "sw.js." This behavior has been reported and discussed in various contexts, indicating that Safari may handle certain requests with service workers in this manner. Additionally, users have raised concerns about the handling of headers like Referer and Origin in service worker-related requests in different browsers such as Firefox and Chrome. This behavior can impact cross-site requests and potentially affect the security of web applications leveraging service workers for data fetching and other functionalities.

For me, navigation request is very important that I don't want it to be affected by service worker because server may read header infomation from request and some functionalities maybe affected by service worker.

What a capture handler do

If I register a service worker as following code:

importScripts('https://cdn.jsdelivr.net/npm/@jcubic/wayne/index.umd.min.js')
const app = new wayne.Wayne()

You can see all request will fetched by sw:

image

If I modify content like this:

const isDocumentRequest = request =>
  request.mode === 'navigate' ||
  request.destination === 'document' ||
  request.headers.get('Content-Type')?.includes('text/html')

self.addEventListener('fetch', event => {
  const { request } = event
  const { url, headers } = request
  if (!url.startsWith('chrome-extension') && !isDocumentRequest(request)) {
    event.responseWith(fetch(request))
  }
})

Only requests that are allowed will fetched by sw:

image
jcubic commented 6 months ago

In version 0.16.0 there is a new API, the Wayne constructor accepts an object with filter option that receive request object and should return false when the request should not be proxied through Service Worker.

jonsam-ng commented 6 months ago

thx a lot