Browse Source

fix: Don't sort the headers of ClientRequest (#26134)

LuoJinghua 4 years ago
parent
commit
0fc5f18b63

+ 1 - 1
shell/browser/api/electron_api_url_loader.cc

@@ -378,7 +378,7 @@ gin::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
   opts.Get("referrer", &request->referrer);
   bool credentials_specified =
       opts.Get("credentials", &request->credentials_mode);
-  std::map<std::string, std::string> extra_headers;
+  std::vector<std::pair<std::string, std::string>> extra_headers;
   if (opts.Get("extraHeaders", &extra_headers)) {
     for (const auto& it : extra_headers) {
       if (!net::HttpUtil::IsValidHeaderName(it.first) ||

+ 31 - 0
shell/common/gin_converters/net_converter.h

@@ -6,6 +6,8 @@
 #define SHELL_COMMON_GIN_CONVERTERS_NET_CONVERTER_H_
 
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "gin/converter.h"
 #include "services/network/public/mojom/fetch_api.mojom.h"
@@ -112,6 +114,35 @@ struct Converter<net::RedirectInfo> {
                                    const net::RedirectInfo& val);
 };
 
+template <typename K, typename V>
+struct Converter<std::vector<std::pair<K, V>>> {
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> value,
+                     std::vector<std::pair<K, V>>* out) {
+    if (!value->IsObject())
+      return false;
+    out->clear();
+    v8::Local<v8::Context> context = isolate->GetCurrentContext();
+    v8::Local<v8::Object> obj = value.As<v8::Object>();
+    v8::Local<v8::Array> keys = obj->GetPropertyNames(context).ToLocalChecked();
+    for (uint32_t i = 0; i < keys->Length(); ++i) {
+      v8::Local<v8::Value> v8key;
+      if (!keys->Get(context, i).ToLocal(&v8key))
+        return false;
+      v8::Local<v8::Value> v8value;
+      if (!obj->Get(context, v8key).ToLocal(&v8value))
+        return false;
+      K key;
+      V value;
+      if (!ConvertFromV8(isolate, v8key, &key) ||
+          !ConvertFromV8(isolate, v8value, &value))
+        return false;
+      (*out).emplace_back(std::move(key), std::move(value));
+    }
+    return true;
+  }
+};
+
 }  // namespace gin
 
 #endif  // SHELL_COMMON_GIN_CONVERTERS_NET_CONVERTER_H_

+ 21 - 0
spec-main/api-net-spec.ts

@@ -537,6 +537,27 @@ describe('net module', () => {
       await collectStreamBody(response);
     });
 
+    it('should keep the order of headers', async () => {
+      const customHeaderNameA = 'X-Header-100';
+      const customHeaderNameB = 'X-Header-200';
+      const serverUrl = await respondOnce.toSingleURL((request, response) => {
+        const headerNames = Array.from(Object.keys(request.headers));
+        const headerAIndex = headerNames.indexOf(customHeaderNameA.toLowerCase());
+        const headerBIndex = headerNames.indexOf(customHeaderNameB.toLowerCase());
+        expect(headerBIndex).to.be.below(headerAIndex);
+        response.statusCode = 200;
+        response.statusMessage = 'OK';
+        response.end();
+      });
+
+      const urlRequest = net.request(serverUrl);
+      urlRequest.setHeader(customHeaderNameB, 'b');
+      urlRequest.setHeader(customHeaderNameA, 'a');
+      const response = await getResponse(urlRequest);
+      expect(response.statusCode).to.equal(200);
+      await collectStreamBody(response);
+    });
+
     it('should be able to set cookie header line', async () => {
       const cookieHeaderName = 'Cookie';
       const cookieHeaderValue = 'test=12345';