Browse Source

fix: restore POST forms that open a new window with target=_blank (#21469)

* fix: restore parts of original ResourceRequestBody V8 conversion

Restore some of the original conversion logic in order to fix target=_blank post form submissions.

* test: add test for POST form submission
loc 5 years ago
parent
commit
5cecc230fb

+ 8 - 0
shell/common/gin_converters/net_converter.cc

@@ -256,14 +256,22 @@ v8::Local<v8::Value> Converter<network::ResourceRequestBody>::ToV8(
     gin::Dictionary upload_data(isolate, v8::Object::New(isolate));
     switch (element.type()) {
       case network::mojom::DataElementType::kFile:
+        upload_data.Set("type", "file");
         upload_data.Set("file", element.path().value());
+        upload_data.Set("filePath", base::Value(element.path().AsUTF8Unsafe()));
+        upload_data.Set("offset", static_cast<int>(element.offset()));
+        upload_data.Set("length", static_cast<int>(element.length()));
+        upload_data.Set("modificationTime",
+                        element.expected_modification_time().ToDoubleT());
         break;
       case network::mojom::DataElementType::kBytes:
+        upload_data.Set("type", "rawData");
         upload_data.Set("bytes", node::Buffer::Copy(isolate, element.bytes(),
                                                     element.length())
                                      .ToLocalChecked());
         break;
       case network::mojom::DataElementType::kDataPipe: {
+        upload_data.Set("type", "blob");
         // TODO(zcbenz): After the NetworkService refactor, the old blobUUID API
         // becomes unecessarily complex, we should deprecate the getBlobData API
         // and return the DataPipeHolder wrapper directly.

+ 79 - 0
spec-main/chromium-spec.ts

@@ -423,6 +423,85 @@ describe('chromium features', () => {
     })
   })
 
+  describe('form submit', () => {
+    let server: http.Server
+    let serverUrl: string
+
+    before(async () => {
+      server = http.createServer((req, res) => {
+        let body = ''
+        req.on('data', (chunk) => {
+          body += chunk
+        })
+        res.setHeader('Content-Type', 'application/json')
+        req.on('end', () => {
+          res.end(`body:${body}`)
+        })
+      })
+      await new Promise(resolve => server.listen(0, '127.0.0.1', resolve))
+      serverUrl = `http://localhost:${(server.address() as any).port}`
+    })
+    after(async () => {
+      server.close()
+      await closeAllWindows()
+    });
+
+    [true, false].forEach((isSandboxEnabled) =>
+      describe(`sandbox=${isSandboxEnabled}`, () => {
+        it('posts data in the same window', () => {
+          const w = new BrowserWindow({
+            show: false,
+            webPreferences: {
+              sandbox: isSandboxEnabled
+            }
+          })
+
+          return new Promise(async (resolve) => {
+            await w.loadFile(path.join(fixturesPath, 'pages', 'form-with-data.html'))
+
+            w.webContents.once('did-finish-load', async () => {
+              const res = await w.webContents.executeJavaScript('document.body.innerText')
+              expect(res).to.equal('body:greeting=hello')
+              resolve()
+            })
+
+            w.webContents.executeJavaScript(`
+              const form = document.querySelector('form')
+              form.action = '${serverUrl}';
+              form.submit();
+            `)
+          })
+        })
+
+        it('posts data to a new window with target=_blank', () => {
+          const w = new BrowserWindow({
+            show: false,
+            webPreferences: {
+              sandbox: isSandboxEnabled
+            }
+          })
+
+          return new Promise(async (resolve) => {
+            await w.loadFile(path.join(fixturesPath, 'pages', 'form-with-data.html'))
+
+            app.once('browser-window-created', async (event, newWin) => {
+              const res = await newWin.webContents.executeJavaScript('document.body.innerText')
+              expect(res).to.equal('body:greeting=hello')
+              resolve()
+            })
+
+            w.webContents.executeJavaScript(`
+              const form = document.querySelector('form')
+              form.action = '${serverUrl}';
+              form.target = '_blank';
+              form.submit();
+            `)
+          })
+        })
+      })
+    )
+  })
+
   describe('window.open', () => {
     for (const show of [true, false]) {
       it(`inherits parent visibility over parent {show=${show}} option`, (done) => {

+ 8 - 0
spec/fixtures/pages/form-with-data.html

@@ -0,0 +1,8 @@
+<html>
+<body>
+  <form id="form" method="post">
+    <input name="greeting" value="hello">
+    <input type="submit" value="submit">
+  </form>
+</body>
+</html>