Repository: electron
Issue: [Feature Request]: Improve the usability of the protocol.handle api.
Labels: enhancement :sparkles:

### Preflight Checklist

- [X] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
- [X] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
- [X] I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.

### Problem Description

You have to be responsible for the request to the end if you have the code of 
```javascript
protocol.handle('https', handler)
```
You can't just return nothing to trigger the browser's default behavior. You've got to return a response. But you may get into trouble in some scenarios.

1. Losing progress events
```javascript
// onprogress will never be called.
xhr.upload.onprogress = onprogress;
xhr.onprogress = onprogress;
```
2. Losing request.body if the body of resquest is a blob.
```javascript
// from lib/browser/api/protocol.ts
function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): RequestInit['body'] {
  if (!uploadData) return null;
  // Optimization: skip creating a stream if the request is just a single buffer.
  if (uploadData.length === 1 && (uploadData[0] as any).type === 'rawData') return uploadData[0].bytes;

  const chunks = [...uploadData] as any[]; // TODO: types are wrong
  let current: ReadableStreamDefaultReader | null = null;
  return new ReadableStream({
    pull (controller) {
      if (current) {
        current.read().then(({ done, value }) => {
          controller.enqueue(value);
          if (done) current = null;
        }, (err) => {
          controller.error(err);
        });
      } else {
        if (!chunks.length) { return controller.close(); }
        const chunk = chunks.shift()!;
        if (chunk.type === 'rawData') { controller.enqueue(chunk.bytes); } else if (chunk.type === 'file') {
          current = Readable.toWeb(createReadStream(chunk.filePath, { start: chunk.offset ?? 0, end: chunk.length >= 0 ? chunk.offset + chunk.length : undefined })).getReader();
          this.pull!(controller);
        } else if (chunk.type === 'stream') {
          current = makeStreamFromPipe(chunk.body).getReader();
          this.pull!(controller);
        }
      }
    }
  }) as RequestInit['body'];
}
```
The above function doesn't process if the chunk's type is blob. You can add blow to resolve but the large file blob will be loaded into memery completely.
```
else if (chunk.type === 'blob') {
                // 增加对blob的处理，如果不处理，发出的http body会缺少数据
                // 将blob对象引用转成arraybuffer，不确定是否进程共享内存（blob本身是共享内存）
                // 如有性能问题再做打算
                return session.getBlobData(chunk.blobUUID).then((buf) => {
                    controller.enqueue(buf);
                });
            }
```
3. redirect
```javascript
protocol.handle('https', (req) => net.fetch(req, {
bypassCustomProtocolHandlers: true
});
```
if the req is a request of a html page, you have to be interested in the request redirect. You must not want to load the website A with the source ccode of website B.

You must not want to write code this way.
```javascript
        const req = new Request(preq.url, reqInit);
        // 这里需要从内部调用获得request对象，监听页面跳转，所以patch了net的request方法
        // patch后和unpatch前，需要确保没有其他人可以调用，所以必须立即同步unpatch
        const monkey = patch(net, 'request');
        let presp: Promise<Response>;
        try {
            presp = localSession.fetch(req, {
                redirect: 'manual',
                // @ts-ignore
                bypassCustomProtocolHandlers: true,
            });
        } finally {
            // 一定要确保unpatch
            monkey.unpatch();
        }

        const { ret: oReq } = monkey.calls[0] as {ret: Electron.ClientRequest};

        let redirectCtx: any = undefined;
        oReq.on('redirect', (statusCode, newMethod, newUrl, _headers) => {
            redirectCtx = {
                url: newUrl,
                statusCode,
            };
        });
        let res: Response | undefined;
        try {
            res = await presp;
        } catch (er) {
            if (redirectCtx) {
                res = Response.redirect(redirectCtx.url, redirectCtx.statusCode);
            }
        }

```

The point 2. and 3. I can find a solution after reading your source code. But the point 1 I think it cannot be solved in JavaScript.

Why I intercepted all the https request?
I want to use electron to build a app which can use without network access proxing the https online resource to local resource if the resource query is matched. I was expected to be able to access the cors, cookie, localstorage function, etc. 
All of those can't work normally with file scheme.


### Proposed Solution

To add a way not to have to give the reponse object in protocol.handle api. After all, in most case we does't want to be responsible for the request to the end. We just want trigger the default behavior of browser.

Add support to code like blow to use the default behavior of chrome.
```
protocol.handle('https', (req) => {
    return
    // or
    return {
        session,
    }
})
```

I think the process of electron sending request which hits the protocol intercepted_handlers  is
```
ProxyingURLLoaderFactory
  bypass_custom_protocol_handlers No
      ElectronURLLoaderFactory
``` 
ElectronURLLoaderFactory will clone a request and call the handler in javascript layer and be expected a kfree type of callback args.

Could you, the electron maintainer, call browserContext's urlLoader with bypass_custom_protocol_handlers in options to trigger the default behavior of chome if the handler's return is undefined?



### Alternatives Considered

I'm not a real developer. I just pretend to know code and trust my boss. It's to hard for me to find a solution. 😂😂😂😂😂😂

### Additional Information

_No response_