Adding abort, webRequest interception and creation tests.
This commit is contained in:
parent
b731ca50bc
commit
a5c508d2d7
2 changed files with 387 additions and 51 deletions
|
@ -98,7 +98,7 @@ URLRequest.prototype._emitRequestEvent = function (async, ...rest) {
|
|||
URLRequest.prototype._emitResponseEvent = function (async, ...rest) {
|
||||
if (async) {
|
||||
process.nextTick(() => {
|
||||
this._request.emit.apply(this._request, rest)
|
||||
this._request.emit.apply(this._response, rest)
|
||||
})
|
||||
} else {
|
||||
this._response.emit.apply(this._response, rest)
|
||||
|
@ -141,6 +141,7 @@ class ClientRequest extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (options.path && / /.test(options.path)) {
|
||||
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
||||
// with an additional rule for ignoring percentage-escaped characters
|
||||
|
@ -150,9 +151,10 @@ class ClientRequest extends EventEmitter {
|
|||
// an invalid request.
|
||||
throw new TypeError('Request path contains unescaped characters.')
|
||||
}
|
||||
urlObj.pathname = options.pathname || '/'
|
||||
urlObj.search = options.search
|
||||
urlObj.hash = options.hash
|
||||
let pathObj = url.parse(options.path || '/')
|
||||
urlObj.pathname = pathObj.pathname
|
||||
urlObj.search = pathObj.search
|
||||
urlObj.hash = pathObj.hash
|
||||
urlStr = url.format(urlObj)
|
||||
}
|
||||
|
||||
|
@ -167,6 +169,11 @@ class ClientRequest extends EventEmitter {
|
|||
this._url_request = urlRequest
|
||||
urlRequest._request = this
|
||||
|
||||
// This is a copy of the extra headers structure held by the native
|
||||
// net::URLRequest. The main reason is to keep the getHeader API synchronous
|
||||
// after the request starts.
|
||||
this._extra_headers = {}
|
||||
|
||||
if (options.headers) {
|
||||
const keys = Object.keys(options.headers)
|
||||
for (let i = 0, l = keys.length; i < l; i++) {
|
||||
|
@ -179,11 +186,6 @@ class ClientRequest extends EventEmitter {
|
|||
// to true only once and never set back to false.
|
||||
this._chunkedEncoding = false
|
||||
|
||||
// This is a copy of the extra headers structure held by the native
|
||||
// net::URLRequest. The main reason is to keep the getHeader API synchronous
|
||||
// after the request starts.
|
||||
this._extra_headers = {}
|
||||
|
||||
urlRequest.on('response', () => {
|
||||
const response = new IncomingMessage(urlRequest)
|
||||
urlRequest._response = response
|
||||
|
|
|
@ -3,6 +3,7 @@ const {remote} = require('electron')
|
|||
const http = require('http')
|
||||
const url = require('url')
|
||||
const {net} = remote
|
||||
const {session} = remote
|
||||
|
||||
function randomBuffer(size, start, end) {
|
||||
start = start || 0
|
||||
|
@ -24,7 +25,7 @@ const kOneKiloByte = 1024
|
|||
const kOneMegaByte = kOneKiloByte * kOneKiloByte
|
||||
|
||||
|
||||
describe.only('net module', function() {
|
||||
describe('net module', function() {
|
||||
this.timeout(0)
|
||||
describe('HTTP basics', function() {
|
||||
|
||||
|
@ -52,9 +53,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request(`${server.url}${request_url}`)
|
||||
|
@ -80,9 +79,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request({
|
||||
|
@ -113,9 +110,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request(`${server.url}${request_url}`)
|
||||
|
@ -152,9 +147,7 @@ describe.only('net module', function() {
|
|||
})
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request({
|
||||
|
@ -194,9 +187,7 @@ describe.only('net module', function() {
|
|||
})
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request({
|
||||
|
@ -264,9 +255,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
let response_event_emitted = false;
|
||||
|
@ -324,9 +313,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -408,9 +395,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request({
|
||||
|
@ -454,9 +439,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request({
|
||||
|
@ -495,9 +478,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request({
|
||||
|
@ -538,9 +519,7 @@ describe.only('net module', function() {
|
|||
response.end();
|
||||
break;
|
||||
default:
|
||||
response.statusCode = 501
|
||||
response.statusMessage = 'Not Implemented'
|
||||
response.end()
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
const urlRequest = net.request({
|
||||
|
@ -570,20 +549,375 @@ describe.only('net module', function() {
|
|||
urlRequest.end();
|
||||
})
|
||||
|
||||
|
||||
|
||||
it ('should be able to abort an HTTP request', function() {
|
||||
it('should be able to abort an HTTP request before first write', function() {
|
||||
const request_url = '/request_url'
|
||||
server.on('request', function(request, response) {
|
||||
assert(false)
|
||||
})
|
||||
|
||||
let request_abort_event_emitted = false
|
||||
let request_close_event_emitted = false
|
||||
|
||||
const urlRequest = net.request({
|
||||
method: 'GET',
|
||||
url: `${server.url}${request_url}`
|
||||
})
|
||||
urlRequest.on('response', function(response) {
|
||||
assert(false)
|
||||
})
|
||||
urlRequest.on('finish', function() {
|
||||
assert(false);
|
||||
})
|
||||
urlRequest.on('error', function(error) {
|
||||
assert(false);
|
||||
})
|
||||
urlRequest.on('abort', function() {
|
||||
request_abort_event_emitted = true
|
||||
})
|
||||
urlRequest.on('close', function() {
|
||||
request_close_event_emitted = true
|
||||
assert(request_abort_event_emitted)
|
||||
assert(request_close_event_emitted)
|
||||
done();
|
||||
})
|
||||
urlRequest.abort()
|
||||
assert(!urlRequest.write(''))
|
||||
urlRequest.end();
|
||||
})
|
||||
|
||||
|
||||
it('it should be able to abort an HTTP request before request end', function(done) {
|
||||
const request_url = '/request_url'
|
||||
let request_received_by_server = false
|
||||
server.on('request', function(request, response) {
|
||||
switch (request.url) {
|
||||
case request_url:
|
||||
request_received_by_server = true;
|
||||
cancelRequest();
|
||||
break;
|
||||
default:
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
|
||||
let request_abort_event_emitted = false
|
||||
let request_close_event_emitted = false
|
||||
|
||||
const urlRequest = net.request({
|
||||
method: 'GET',
|
||||
url: `${server.url}${request_url}`
|
||||
})
|
||||
urlRequest.on('response', function(response) {
|
||||
assert(false)
|
||||
})
|
||||
urlRequest.on('finish', function() {
|
||||
assert(false)
|
||||
})
|
||||
urlRequest.on('error', function(error) {
|
||||
assert(false);
|
||||
})
|
||||
urlRequest.on('abort', function() {
|
||||
request_abort_event_emitted = true
|
||||
})
|
||||
urlRequest.on('close', function() {
|
||||
request_close_event_emitted = true
|
||||
assert(request_received_by_server)
|
||||
assert(request_abort_event_emitted)
|
||||
assert(request_close_event_emitted)
|
||||
done()
|
||||
})
|
||||
|
||||
urlRequest.chunkedEncoding = true
|
||||
urlRequest.write(randomString(kOneKiloByte))
|
||||
function cancelRequest() {
|
||||
urlRequest.abort()
|
||||
}
|
||||
})
|
||||
|
||||
it('it should be able to abort an HTTP request after request end and before response', function(done) {
|
||||
const request_url = '/request_url'
|
||||
let request_received_by_server = false
|
||||
server.on('request', function(request, response) {
|
||||
switch (request.url) {
|
||||
case request_url:
|
||||
request_received_by_server = true;
|
||||
cancelRequest();
|
||||
process.nextTick( () => {
|
||||
response.statusCode = 200
|
||||
response.statusMessage = 'OK'
|
||||
response.end();
|
||||
})
|
||||
break;
|
||||
default:
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
|
||||
let request_abort_event_emitted = false
|
||||
let request_finish_event_emitted = false
|
||||
let request_close_event_emitted = false
|
||||
|
||||
const urlRequest = net.request({
|
||||
method: 'GET',
|
||||
url: `${server.url}${request_url}`
|
||||
})
|
||||
urlRequest.on('response', function(response) {
|
||||
assert(false)
|
||||
})
|
||||
urlRequest.on('finish', function() {
|
||||
request_finish_event_emitted = true
|
||||
})
|
||||
urlRequest.on('error', function(error) {
|
||||
assert(false);
|
||||
})
|
||||
urlRequest.on('abort', function() {
|
||||
request_abort_event_emitted = true
|
||||
})
|
||||
urlRequest.on('close', function() {
|
||||
request_close_event_emitted = true
|
||||
assert(request_finish_event_emitted)
|
||||
assert(request_received_by_server)
|
||||
assert(request_abort_event_emitted)
|
||||
assert(request_close_event_emitted)
|
||||
done()
|
||||
})
|
||||
|
||||
urlRequest.end(randomString(kOneKiloByte))
|
||||
function cancelRequest() {
|
||||
urlRequest.abort()
|
||||
}
|
||||
})
|
||||
|
||||
it('it should be able to abort an HTTP request after response start', function(done) {
|
||||
const request_url = '/request_url'
|
||||
let request_received_by_server = false
|
||||
server.on('request', function(request, response) {
|
||||
switch (request.url) {
|
||||
case request_url:
|
||||
request_received_by_server = true;
|
||||
response.statusCode = 200
|
||||
response.statusMessage = 'OK'
|
||||
response.write(randomString(kOneKiloByte))
|
||||
break;
|
||||
default:
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
|
||||
let request_finish_event_emitted = false
|
||||
let request_response_event_emitted = false
|
||||
let request_abort_event_emitted = false
|
||||
let request_close_event_emitted = false
|
||||
let response_aborted_event_emitted = false
|
||||
|
||||
|
||||
const urlRequest = net.request({
|
||||
method: 'GET',
|
||||
url: `${server.url}${request_url}`
|
||||
})
|
||||
urlRequest.on('response', function(response) {
|
||||
request_response_event_emitted = true
|
||||
const statusCode = response.statusCode
|
||||
assert.equal(statusCode, 200)
|
||||
response.pause();
|
||||
response.on('data', function(chunk) {
|
||||
})
|
||||
response.on('end', function() {
|
||||
assert(false)
|
||||
})
|
||||
response.resume();
|
||||
response.on('error', function(error) {
|
||||
assert(false)
|
||||
})
|
||||
response.on('aborted', function() {
|
||||
response_aborted_event_emitted = true
|
||||
})
|
||||
urlRequest.abort()
|
||||
})
|
||||
urlRequest.on('finish', function() {
|
||||
request_finish_event_emitted = true
|
||||
})
|
||||
urlRequest.on('error', function(error) {
|
||||
assert(false);
|
||||
})
|
||||
urlRequest.on('abort', function() {
|
||||
request_abort_event_emitted = true
|
||||
})
|
||||
urlRequest.on('close', function() {
|
||||
request_close_event_emitted = true
|
||||
assert(request_finish_event_emitted, 'request should emit "finish" event')
|
||||
assert(request_received_by_server, 'request should be received by the server')
|
||||
assert(request_response_event_emitted, '"response" event should be emitted')
|
||||
assert(request_abort_event_emitted, 'request should emit "abort" event')
|
||||
assert(response_aborted_event_emitted, 'response should emit "aborted" event')
|
||||
assert(request_close_event_emitted, 'request should emit "close" event')
|
||||
done()
|
||||
})
|
||||
urlRequest.end(randomString(kOneKiloByte))
|
||||
})
|
||||
|
||||
it('Requests should be intercepted by webRequest module', function(done) {
|
||||
|
||||
const request_url = '/request_url'
|
||||
const redirect_url = '/redirect_url'
|
||||
let request_is_redirected = false;
|
||||
server.on('request', function(request, response) {
|
||||
switch (request.url) {
|
||||
case request_url:
|
||||
assert(false)
|
||||
break
|
||||
case redirect_url:
|
||||
request_is_redirected = true
|
||||
response.end();
|
||||
break
|
||||
default:
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
|
||||
let request_is_intercepted = false
|
||||
session.defaultSession.webRequest.onBeforeRequest(
|
||||
function(details, callback){
|
||||
if (details.url === `${server.url}${request_url}`) {
|
||||
request_is_intercepted = true
|
||||
callback({
|
||||
redirectURL: `${server.url}${redirect_url}`
|
||||
})
|
||||
} else {
|
||||
callback( {
|
||||
cancel: false
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
const urlRequest = net.request(`${server.url}${request_url}`)
|
||||
|
||||
urlRequest.on('response', function(response) {
|
||||
assert.equal(response.statusCode, 200)
|
||||
response.pause()
|
||||
response.on('data', function(chunk) {
|
||||
})
|
||||
response.on('end', function() {
|
||||
assert(request_is_redirected, 'The server should receive a request to the forward URL')
|
||||
assert(request_is_intercepted, 'The request should be intercepted by the webRequest module')
|
||||
done()
|
||||
})
|
||||
response.resume()
|
||||
})
|
||||
urlRequest.end();
|
||||
})
|
||||
|
||||
it('should to able to create and intercept a request on a custom session', function(done) {
|
||||
const request_url = '/request_url'
|
||||
const redirect_url = '/redirect_url'
|
||||
const custom_session_name = 'custom-session'
|
||||
let request_is_redirected = false;
|
||||
server.on('request', function(request, response) {
|
||||
switch (request.url) {
|
||||
case request_url:
|
||||
assert(false)
|
||||
break
|
||||
case redirect_url:
|
||||
request_is_redirected = true
|
||||
response.end();
|
||||
break
|
||||
default:
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
|
||||
session.defaultSession.webRequest.onBeforeRequest(
|
||||
function(details, callback) {
|
||||
assert(false, 'Request should not be intercepted by the default session')
|
||||
});
|
||||
|
||||
let custom_session = session.fromPartition(custom_session_name, {
|
||||
cache: false
|
||||
})
|
||||
let request_is_intercepted = false
|
||||
custom_session.webRequest.onBeforeRequest(
|
||||
function(details, callback){
|
||||
if (details.url === `${server.url}${request_url}`) {
|
||||
request_is_intercepted = true
|
||||
callback({
|
||||
redirectURL: `${server.url}${redirect_url}`
|
||||
})
|
||||
} else {
|
||||
callback( {
|
||||
cancel: false
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
const urlRequest = net.request({
|
||||
url: `${server.url}${request_url}`,
|
||||
session: custom_session_name
|
||||
})
|
||||
urlRequest.on('response', function(response) {
|
||||
assert.equal(response.statusCode, 200)
|
||||
response.pause()
|
||||
response.on('data', function(chunk) {
|
||||
})
|
||||
response.on('end', function() {
|
||||
assert(request_is_redirected, 'The server should receive a request to the forward URL')
|
||||
assert(request_is_intercepted, 'The request should be intercepted by the webRequest module')
|
||||
done()
|
||||
})
|
||||
response.resume()
|
||||
})
|
||||
urlRequest.end();
|
||||
})
|
||||
|
||||
it.only ('should be able to create a request with options', function() {
|
||||
const request_url = '/'
|
||||
const custom_header_name = 'Some-Custom-Header-Name'
|
||||
const custom_header_value = 'Some-Customer-Header-Value'
|
||||
server.on('request', function(request, response) {
|
||||
switch (request.url) {
|
||||
case request_url:
|
||||
assert.equal(request.method, 'GET')
|
||||
assert.equal(request.headers[custom_header_name.toLowerCase()],
|
||||
custom_header_value)
|
||||
response.end();
|
||||
break;
|
||||
default:
|
||||
assert(false)
|
||||
}
|
||||
})
|
||||
|
||||
const server_url = url.parse(server.url)
|
||||
let options = {
|
||||
port: server_url.port,
|
||||
headers: {}
|
||||
}
|
||||
options.headers[custom_header_name] = custom_header_value
|
||||
const urlRequest = net.request(options)
|
||||
urlRequest.on('response', function(response) {
|
||||
assert.equal(response.statusCode, 200)
|
||||
response.pause()
|
||||
response.on('data', function(chunk) {
|
||||
})
|
||||
response.on('end', function() {
|
||||
done()
|
||||
})
|
||||
response.resume()
|
||||
})
|
||||
urlRequest.end();
|
||||
})
|
||||
|
||||
it('abort request should be emitted at most once', function() {
|
||||
assert(false)
|
||||
})
|
||||
|
||||
it('headers cannot be manipulated after abort', function() {
|
||||
assert(false)
|
||||
})
|
||||
|
||||
it ('should be able to pipe into a request', function() {
|
||||
assert(false)
|
||||
})
|
||||
it ('should be able to create a request with options', function() {
|
||||
assert(false)
|
||||
})
|
||||
it ('should be able to specify a custom session', function() {
|
||||
assert(false)
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
describe('IncomingMessage API', function() {
|
||||
it('should provide a Node.js-similar API', function() {
|
||||
|
|
Loading…
Reference in a new issue