feat: add support for net requests to use the session cookie store (#22704)
This commit is contained in:
parent
07a049ef1b
commit
60bd52880f
4 changed files with 137 additions and 1 deletions
|
@ -22,6 +22,9 @@ which the request is associated.
|
||||||
with which the request is associated. Defaults to the empty string. The
|
with which the request is associated. Defaults to the empty string. The
|
||||||
`session` option prevails on `partition`. Thus if a `session` is explicitly
|
`session` option prevails on `partition`. Thus if a `session` is explicitly
|
||||||
specified, `partition` is ignored.
|
specified, `partition` is ignored.
|
||||||
|
* `useSessionCookies` Boolean (optional) - Whether to send cookies with this
|
||||||
|
request from the provided session. This will make the `net` request's
|
||||||
|
cookie behavior match a `fetch` request. Default is `false`.
|
||||||
* `protocol` String (optional) - The protocol scheme in the form 'scheme:'.
|
* `protocol` String (optional) - The protocol scheme in the form 'scheme:'.
|
||||||
Currently supported values are 'http:' or 'https:'. Defaults to 'http:'.
|
Currently supported values are 'http:' or 'https:'. Defaults to 'http:'.
|
||||||
* `host` String (optional) - The server host provided as a concatenation of
|
* `host` String (optional) - The server host provided as a concatenation of
|
||||||
|
|
|
@ -236,7 +236,8 @@ function parseOptions (options) {
|
||||||
method: method,
|
method: method,
|
||||||
url: urlStr,
|
url: urlStr,
|
||||||
redirectPolicy,
|
redirectPolicy,
|
||||||
extraHeaders: options.headers || {}
|
extraHeaders: options.headers || {},
|
||||||
|
useSessionCookies: options.useSessionCookies || false
|
||||||
};
|
};
|
||||||
for (const [name, value] of Object.entries(urlLoaderOptions.extraHeaders)) {
|
for (const [name, value] of Object.entries(urlLoaderOptions.extraHeaders)) {
|
||||||
if (!_isValidHeaderName(name)) {
|
if (!_isValidHeaderName(name)) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "gin/wrappable.h"
|
#include "gin/wrappable.h"
|
||||||
#include "mojo/public/cpp/bindings/remote.h"
|
#include "mojo/public/cpp/bindings/remote.h"
|
||||||
#include "mojo/public/cpp/system/data_pipe_producer.h"
|
#include "mojo/public/cpp/system/data_pipe_producer.h"
|
||||||
|
#include "net/base/load_flags.h"
|
||||||
#include "services/network/public/cpp/resource_request.h"
|
#include "services/network/public/cpp/resource_request.h"
|
||||||
#include "services/network/public/cpp/simple_url_loader.h"
|
#include "services/network/public/cpp/simple_url_loader.h"
|
||||||
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
|
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
|
||||||
|
@ -358,6 +359,12 @@ gin_helper::WrappableBase* SimpleURLLoaderWrapper::New(gin::Arguments* args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool use_session_cookies = false;
|
||||||
|
opts.Get("useSessionCookies", &use_session_cookies);
|
||||||
|
if (!use_session_cookies) {
|
||||||
|
request->load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
|
||||||
|
}
|
||||||
|
|
||||||
// Chromium filters headers using browser rules, while for net module we have
|
// Chromium filters headers using browser rules, while for net module we have
|
||||||
// every header passed.
|
// every header passed.
|
||||||
request->report_raw_headers = true;
|
request->report_raw_headers = true;
|
||||||
|
|
|
@ -511,6 +511,131 @@ describe('net module', () => {
|
||||||
expect(response.headers['set-cookie']).to.have.same.members(cookie);
|
expect(response.headers['set-cookie']).to.have.same.members(cookie);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not use the sessions cookie store by default', async () => {
|
||||||
|
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
||||||
|
response.statusCode = 200;
|
||||||
|
response.statusMessage = 'OK';
|
||||||
|
response.setHeader('x-cookie', `${request.headers.cookie!}`);
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
const sess = session.fromPartition('cookie-tests-1');
|
||||||
|
const cookieVal = `${Date.now()}`;
|
||||||
|
await sess.cookies.set({
|
||||||
|
url: serverUrl,
|
||||||
|
name: 'wild_cookie',
|
||||||
|
value: cookieVal
|
||||||
|
});
|
||||||
|
const urlRequest = net.request({
|
||||||
|
url: serverUrl,
|
||||||
|
session: sess
|
||||||
|
});
|
||||||
|
const response = await getResponse(urlRequest);
|
||||||
|
expect(response.headers['x-cookie']).to.equal(`undefined`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to use the sessions cookie store', async () => {
|
||||||
|
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
||||||
|
response.statusCode = 200;
|
||||||
|
response.statusMessage = 'OK';
|
||||||
|
response.setHeader('x-cookie', request.headers.cookie!);
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
const sess = session.fromPartition('cookie-tests-2');
|
||||||
|
const cookieVal = `${Date.now()}`;
|
||||||
|
await sess.cookies.set({
|
||||||
|
url: serverUrl,
|
||||||
|
name: 'wild_cookie',
|
||||||
|
value: cookieVal
|
||||||
|
});
|
||||||
|
const urlRequest = net.request({
|
||||||
|
url: serverUrl,
|
||||||
|
session: sess,
|
||||||
|
useSessionCookies: true
|
||||||
|
});
|
||||||
|
const response = await getResponse(urlRequest);
|
||||||
|
expect(response.headers['x-cookie']).to.equal(`wild_cookie=${cookieVal}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to use the sessions cookie store with set-cookie', async () => {
|
||||||
|
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
||||||
|
response.statusCode = 200;
|
||||||
|
response.statusMessage = 'OK';
|
||||||
|
response.setHeader('set-cookie', 'foo=bar');
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
const sess = session.fromPartition('cookie-tests-3');
|
||||||
|
let cookies = await sess.cookies.get({});
|
||||||
|
expect(cookies).to.have.lengthOf(0);
|
||||||
|
const urlRequest = net.request({
|
||||||
|
url: serverUrl,
|
||||||
|
session: sess,
|
||||||
|
useSessionCookies: true
|
||||||
|
});
|
||||||
|
await collectStreamBody(await getResponse(urlRequest));
|
||||||
|
cookies = await sess.cookies.get({});
|
||||||
|
expect(cookies).to.have.lengthOf(1);
|
||||||
|
expect(cookies[0]).to.deep.equal({
|
||||||
|
name: 'foo',
|
||||||
|
value: 'bar',
|
||||||
|
domain: '127.0.0.1',
|
||||||
|
hostOnly: true,
|
||||||
|
path: '/',
|
||||||
|
secure: false,
|
||||||
|
httpOnly: false,
|
||||||
|
session: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to use the sessions cookie store safely across redirects', async () => {
|
||||||
|
const serverUrl = await respondOnce.toSingleURL(async (request, response) => {
|
||||||
|
response.statusCode = 302;
|
||||||
|
response.statusMessage = 'Moved';
|
||||||
|
const newUrl = await respondOnce.toSingleURL((req, res) => {
|
||||||
|
res.statusCode = 200;
|
||||||
|
res.statusMessage = 'OK';
|
||||||
|
res.setHeader('x-cookie', req.headers.cookie!);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
response.setHeader('x-cookie', request.headers.cookie!);
|
||||||
|
response.setHeader('location', newUrl.replace('127.0.0.1', 'localhost'));
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
const sess = session.fromPartition('cookie-tests-4');
|
||||||
|
const cookie127Val = `${Date.now()}-127`;
|
||||||
|
const cookieLocalVal = `${Date.now()}-local`;
|
||||||
|
const localhostUrl = serverUrl.replace('127.0.0.1', 'localhost');
|
||||||
|
expect(localhostUrl).to.not.equal(serverUrl);
|
||||||
|
await Promise.all([
|
||||||
|
sess.cookies.set({
|
||||||
|
url: serverUrl,
|
||||||
|
name: 'wild_cookie',
|
||||||
|
value: cookie127Val
|
||||||
|
}), sess.cookies.set({
|
||||||
|
url: localhostUrl,
|
||||||
|
name: 'wild_cookie',
|
||||||
|
value: cookieLocalVal
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
const urlRequest = net.request({
|
||||||
|
url: serverUrl,
|
||||||
|
session: sess,
|
||||||
|
useSessionCookies: true
|
||||||
|
});
|
||||||
|
urlRequest.on('redirect', (status, method, url, headers) => {
|
||||||
|
// The initial redirect response should have received the 127 value here
|
||||||
|
expect(headers['x-cookie'][0]).to.equal(`wild_cookie=${cookie127Val}`);
|
||||||
|
urlRequest.followRedirect();
|
||||||
|
});
|
||||||
|
const response = await getResponse(urlRequest);
|
||||||
|
// We expect the server to have received the localhost value here
|
||||||
|
// The original request was to a 127.0.0.1 URL
|
||||||
|
// That request would have the cookie127Val cookie attached
|
||||||
|
// The request is then redirect to a localhost URL (different site)
|
||||||
|
// Because we are using the session cookie store it should do the safe / secure thing
|
||||||
|
// and attach the cookies for the new target domain
|
||||||
|
expect(response.headers['x-cookie']).to.equal(`wild_cookie=${cookieLocalVal}`);
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to abort an HTTP request before first write', async () => {
|
it('should be able to abort an HTTP request before first write', async () => {
|
||||||
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
||||||
response.end();
|
response.end();
|
||||||
|
|
Loading…
Reference in a new issue