Skip to content

Commit 0fc5f18

Browse files
authored
fix: Don't sort the headers of ClientRequest (electron#26134)
1 parent 2d1bbd2 commit 0fc5f18

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

shell/browser/api/electron_api_url_loader.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ gin::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
378378
opts.Get("referrer", &request->referrer);
379379
bool credentials_specified =
380380
opts.Get("credentials", &request->credentials_mode);
381-
std::map<std::string, std::string> extra_headers;
381+
std::vector<std::pair<std::string, std::string>> extra_headers;
382382
if (opts.Get("extraHeaders", &extra_headers)) {
383383
for (const auto& it : extra_headers) {
384384
if (!net::HttpUtil::IsValidHeaderName(it.first) ||

shell/common/gin_converters/net_converter.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#define SHELL_COMMON_GIN_CONVERTERS_NET_CONVERTER_H_
77

88
#include <string>
9+
#include <utility>
10+
#include <vector>
911

1012
#include "gin/converter.h"
1113
#include "services/network/public/mojom/fetch_api.mojom.h"
@@ -112,6 +114,35 @@ struct Converter<net::RedirectInfo> {
112114
const net::RedirectInfo& val);
113115
};
114116

117+
template <typename K, typename V>
118+
struct Converter<std::vector<std::pair<K, V>>> {
119+
static bool FromV8(v8::Isolate* isolate,
120+
v8::Local<v8::Value> value,
121+
std::vector<std::pair<K, V>>* out) {
122+
if (!value->IsObject())
123+
return false;
124+
out->clear();
125+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
126+
v8::Local<v8::Object> obj = value.As<v8::Object>();
127+
v8::Local<v8::Array> keys = obj->GetPropertyNames(context).ToLocalChecked();
128+
for (uint32_t i = 0; i < keys->Length(); ++i) {
129+
v8::Local<v8::Value> v8key;
130+
if (!keys->Get(context, i).ToLocal(&v8key))
131+
return false;
132+
v8::Local<v8::Value> v8value;
133+
if (!obj->Get(context, v8key).ToLocal(&v8value))
134+
return false;
135+
K key;
136+
V value;
137+
if (!ConvertFromV8(isolate, v8key, &key) ||
138+
!ConvertFromV8(isolate, v8value, &value))
139+
return false;
140+
(*out).emplace_back(std::move(key), std::move(value));
141+
}
142+
return true;
143+
}
144+
};
145+
115146
} // namespace gin
116147

117148
#endif // SHELL_COMMON_GIN_CONVERTERS_NET_CONVERTER_H_

spec-main/api-net-spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,27 @@ describe('net module', () => {
537537
await collectStreamBody(response);
538538
});
539539

540+
it('should keep the order of headers', async () => {
541+
const customHeaderNameA = 'X-Header-100';
542+
const customHeaderNameB = 'X-Header-200';
543+
const serverUrl = await respondOnce.toSingleURL((request, response) => {
544+
const headerNames = Array.from(Object.keys(request.headers));
545+
const headerAIndex = headerNames.indexOf(customHeaderNameA.toLowerCase());
546+
const headerBIndex = headerNames.indexOf(customHeaderNameB.toLowerCase());
547+
expect(headerBIndex).to.be.below(headerAIndex);
548+
response.statusCode = 200;
549+
response.statusMessage = 'OK';
550+
response.end();
551+
});
552+
553+
const urlRequest = net.request(serverUrl);
554+
urlRequest.setHeader(customHeaderNameB, 'b');
555+
urlRequest.setHeader(customHeaderNameA, 'a');
556+
const response = await getResponse(urlRequest);
557+
expect(response.statusCode).to.equal(200);
558+
await collectStreamBody(response);
559+
});
560+
540561
it('should be able to set cookie header line', async () => {
541562
const cookieHeaderName = 'Cookie';
542563
const cookieHeaderValue = 'test=12345';

0 commit comments

Comments
 (0)