Browse Source

Merge pull request #3701 from deepak1556/protocol_post_data_patch

protocol: provide upload data when available
Cheng Zhao 9 years ago
parent
commit
a05aa81570

+ 10 - 0
atom/browser/net/url_request_fetch_job.cc

@@ -90,12 +90,14 @@ void URLRequestFetchJob::StartAsync(scoped_ptr<base::Value> options) {
 
   std::string url, method, referrer;
   base::Value* session = nullptr;
+  base::DictionaryValue* upload_data = nullptr;
   base::DictionaryValue* dict =
       static_cast<base::DictionaryValue*>(options.get());
   dict->GetString("url", &url);
   dict->GetString("method", &method);
   dict->GetString("referrer", &referrer);
   dict->Get("session", &session);
+  dict->GetDictionary("uploadData", &upload_data);
 
   // Check if URL is valid.
   GURL formated_url(url);
@@ -127,6 +129,14 @@ void URLRequestFetchJob::StartAsync(scoped_ptr<base::Value> options) {
   else
     fetcher_->SetReferrer(referrer);
 
+  // Set the data needed for POSTs.
+  if (upload_data && request_type == net::URLFetcher::POST) {
+    std::string content_type, data;
+    upload_data->GetString("contentType", &content_type);
+    upload_data->GetString("data", &data);
+    fetcher_->SetUploadData(content_type, data);
+  }
+
   // Use |request|'s headers.
   fetcher_->SetExtraRequestHeaders(
       request()->extra_request_headers().ToString());

+ 29 - 0
atom/common/native_mate_converters/net_converter.cc

@@ -5,9 +5,14 @@
 #include "atom/common/native_mate_converters/net_converter.h"
 
 #include <string>
+#include <vector>
 
 #include "atom/common/node_includes.h"
 #include "native_mate/dictionary.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/base/upload_data_stream.h"
+#include "net/base/upload_element_reader.h"
+#include "net/base/upload_file_element_reader.h"
 #include "net/cert/x509_certificate.h"
 #include "net/url_request/url_request.h"
 
@@ -20,6 +25,30 @@ v8::Local<v8::Value> Converter<const net::URLRequest*>::ToV8(
   dict.Set("method", val->method());
   dict.Set("url", val->url().spec());
   dict.Set("referrer", val->referrer());
+  const net::UploadDataStream* upload_data = val->get_upload();
+  if (upload_data) {
+    const ScopedVector<net::UploadElementReader>* readers =
+        upload_data->GetElementReaders();
+    std::vector<mate::Dictionary> upload_data_list;
+    upload_data_list.reserve(readers->size());
+    for (const auto& reader : *readers) {
+      auto upload_data_dict = mate::Dictionary::CreateEmpty(isolate);
+      if (reader->AsBytesReader()) {
+        const net::UploadBytesElementReader* bytes_reader =
+            reader->AsBytesReader();
+        auto bytes =
+            node::Buffer::Copy(isolate, bytes_reader->bytes(),
+                               bytes_reader->length()).ToLocalChecked();
+        upload_data_dict.Set("bytes", bytes);
+      } else if (reader->AsFileReader()) {
+        const net::UploadFileElementReader* file_reader =
+            reader->AsFileReader();
+        upload_data_dict.Set("file", file_reader->path().AsUTF8Unsafe());
+      }
+      upload_data_list.push_back(upload_data_dict);
+    }
+    dict.Set("uploadData", upload_data_list);
+  }
   return mate::ConvertToV8(isolate, dict);
 }
 

+ 6 - 1
docs/api/protocol.md

@@ -107,11 +107,16 @@ Registers a protocol of `scheme` that will send a `String` as a response. The
 
 Registers a protocol of `scheme` that will send an HTTP request as a response.
 The `callback` should be called with an object that has the `url`, `method`,
-`referrer`, and `session` properties.
+`referrer`, `uploadData` and `session` properties.
 
 By default the HTTP request will reuse the current session. If you want the
 request to have a different session you should set `session` to `null`.
 
+POST request should provide an `uploadData` object.
+* `uploadData` object
+  * `contentType` String - MIME type of the content.
+  *  `data` String - Content to be sent.
+
 ### `protocol.unregisterProtocol(scheme[, completion])`
 
 * `scheme` String

+ 69 - 0
spec/api-protocol-spec.coffee

@@ -1,6 +1,7 @@
 assert   = require 'assert'
 http     = require 'http'
 path     = require 'path'
+qs        = require 'querystring'
 
 {remote} = require 'electron'
 {protocol} = remote.require 'electron'
@@ -8,6 +9,9 @@ path     = require 'path'
 describe 'protocol module', ->
   protocolName = 'sp'
   text = 'valar morghulis'
+  postData =
+    name: 'post test'
+    type: 'string'
 
   afterEach (done) ->
     protocol.unregisterProtocol protocolName, ->
@@ -405,6 +409,22 @@ describe 'protocol module', ->
           error: (xhr, errorType, error) ->
             done(error)
 
+    it 'can receive post data', (done) ->
+      handler = (request, callback) ->
+        uploadData = request.uploadData[0].bytes.toString()
+        callback({data: uploadData})
+      protocol.interceptStringProtocol 'http', handler, (error) ->
+        return done(error) if error
+        $.ajax
+          url: "http://fake-host"
+          type: "POST"
+          data: postData
+          success: (data) ->
+            assert.deepEqual qs.parse(data), postData
+            done()
+          error: (xhr, errorType, error) ->
+            done(error)
+
   describe 'protocol.interceptBufferProtocol', ->
     it 'can intercept http protocol', (done) ->
       handler = (request, callback) -> callback(new Buffer(text))
@@ -418,6 +438,55 @@ describe 'protocol module', ->
           error: (xhr, errorType, error) ->
             done(error)
 
+    it 'can receive post data', (done) ->
+      handler = (request, callback) ->
+        uploadData = request.uploadData[0].bytes
+        callback(uploadData)
+      protocol.interceptBufferProtocol 'http', handler, (error) ->
+        return done(error) if error
+        $.ajax
+          url: "http://fake-host"
+          type: "POST"
+          data: postData
+          success: (data) ->
+            assert.equal data, $.param postData
+            done()
+          error: (xhr, errorType, error) ->
+            done(error)
+
+  describe 'protocol.interceptHttpProtocol', ->
+    it 'can send POST request', (done) ->
+      server = http.createServer (req, res) ->
+        body = ''
+        req.on 'data', (chunk) ->
+          body += chunk
+        req.on 'end', ->
+          res.end body
+        server.close()
+      server.listen 0, '127.0.0.1', ->
+        {port} = server.address()
+        url = "http://127.0.0.1:#{port}"
+        handler = (request, callback) ->
+          data =
+            url: url
+            method: 'POST'
+            uploadData:
+              contentType: 'application/x-www-form-urlencoded'
+              data: request.uploadData[0].bytes.toString()
+            session: null
+          callback(data)
+        protocol.interceptHttpProtocol 'http', handler, (error) ->
+          return done(error) if error
+          $.ajax
+            url: "http://fake-host"
+            type: "POST"
+            data: postData
+            success: (data) ->
+              assert.deepEqual qs.parse(data), postData
+              done()
+            error: (xhr, errorType, error) ->
+              done(error)
+
   describe 'protocol.uninterceptProtocol', ->
     it 'returns error when scheme does not exist', (done) ->
       protocol.uninterceptProtocol 'not-exist', (error) ->