Repository: electron/electron (language: cpp)

Issue:
[Bug]: protocol.handle fails when filename contains '#'
### 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 bug report that matches the one I want to file, without success.

### Electron Version

30.0.2

### What operating system are you using?

Windows

### Operating System Version

Windows 10 version 22H2

### What arch are you using?

x64

### Last Known Working Electron version

_No response_

### Expected Behavior

The image should display as normal.

### Actual Behavior

When you're handling a file:// protocol request, it's being treated like a regular URL. However, the file:// protocol is different from HTTP or HTTPS URLs in how it handles characters like #. In a file:// URL, the # character is typically part of the file or directory name and is not treated as a fragment identifier like in HTTP URLs.

### Testcase Gist URL

https://gist.github.com/KBriscoe/550df36cd29a4d27a7672f1404a9e990

### Additional Information

If using the gist, the filepaths need to be updated in the renderer.js to actual images. The issue is when the image contains '#' in my case and I looked through the protocol.handle and saw it was treating it like a web request I believe where # usually means to truncate off the rest of the request. So it ends up trying to get an incorrect path item.


Discussion / hints:

Fix patch:
diff --git a/docs/api/protocol.md b/docs/api/protocol.md
index 6d2de18751de4..3f4ce799a1370 100644
--- a/docs/api/protocol.md
+++ b/docs/api/protocol.md
@@ -9,10 +9,14 @@ An example of implementing a protocol that has the same effect as the
 
 ```js
 const { app, protocol, net } = require('electron')
+const path = require('node:path')
+const url = require('node:url')
 
 app.whenReady().then(() => {
-  protocol.handle('atom', (request) =>
-    net.fetch('file://' + request.url.slice('atom://'.length)))
+  protocol.handle('atom', (request) => {
+    const filePath = request.url.slice('atom://'.length)
+    return net.fetch(url.pathToFileURL(path.join(__dirname, filePath)).toString())
+  })
 })
 ```
 
@@ -42,7 +46,7 @@ app.whenReady().then(() => {
 
   ses.protocol.handle('atom', (request) => {
     const filePath = request.url.slice('atom://'.length)
-    return net.fetch(url.pathToFileURL(path.join(__dirname, filePath)).toString())
+    return net.fetch(url.pathToFileURL(path.resolve(__dirname, filePath)).toString())
   })
 
   const mainWindow = new BrowserWindow({ webPreferences: { partition } })


Test patch: