10000 fix: match net module headers & http.IncomingMessage headers by codebytere · Pull Request #17517 · electron/electron · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

fix: match net module headers & http.IncomingMessage headers #17517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions docs/api/net.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@ module instead of the native Node.js modules:
* Support for traffic monitoring proxies: Fiddler-like proxies used for access
control and monitoring.

The `net` module API has been specifically designed to mimic, as closely as
possible, the familiar Node.js API. The API components including classes,
methods, properties and event names are similar to those commonly used in
The API components (including classes, methods, properties and event names) are similar to those used in
Node.js.

For instance, the following example quickly shows how the `net` API might be
used:
Example usage:

```javascript
const { app } = require('electron')
Expand All @@ -48,10 +45,6 @@ app.on('ready', () => {
})
```

By the way, it is almost identical to how you would normally use the
[HTTP](https://nodejs.org/api/http.html)/[HTTPS](https://nodejs.org/api/https.html)
modules of Node.js

The `net` API can be used only after the application emits the `ready` event.
Trying to use the module before the `ready` event will throw an error.

Expand Down
41 changes: 40 additions & 1 deletion lib/browser/api/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,29 @@ Object.setPrototypeOf(URLRequest.prototype, EventEmitter.prototype)

const kSupportedProtocols = new Set(['http:', 'https:'])

// set of headers that Node.js discards duplicates for
// see https://nodejs.org/api/http.html#http_message_headers
const discardableDuplicateHeaders = new Set([
'content-type',
'content-length',
'user-agent',
'referer',
'host',
'authorization',
'proxy-authorization',
'if-modified-since',
'if-unmodified-since',
'from',
'location',
'max-forwards',
'retry-after',
'etag',
'last-modified',
'server',
'age',
'expires'
])

class IncomingMessage extends Readable {
constructor (urlRequest) {
super()
Expand All @@ -41,7 +64,23 @@ class IncomingMessage extends Readable {
}

get headers () {
return this.urlRequest.rawResponseHeaders
const filteredHeaders = {}
const rawHeaders = this.urlRequest.rawResponseHeaders
Object.keys(rawHeaders).forEach(header => {
if (header in filteredHeaders && discardableDuplicateHeaders.has(header)) {
// do nothing with discardable duplicate headers
} else {
if (header === 'set-cookie') {
// keep set-cookie as an array per Node.js rules
// see https://nodejs.org/api/http.html#http_message_headers
filteredHeaders[header] = rawHeaders[header]
} else {
// for non-cookie headers, the values are joined together with ', '
filteredHeaders[header] = rawHeaders[header].join(', ')
}
}
})
return filteredHeaders
}

get httpVersion () {
Expand Down
123 changes: 103 additions & 20 deletions spec/api-net-spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const assert = require('assert')
const { expect } = require('chai')
const { remote } = require('electron')
const { ipcRenderer } = require('electron')
const http = require('http')
Expand Down Expand Up @@ -1363,6 +1364,7 @@ describe('net module', () => {
const requestUrl = '/requestUrl'
const customHeaderName = 'Some-Custom-Header-Name'
const customHeaderValue = 'Some-Customer-Header-Value'

server.on('request', (request, response) => {
switch (request.url) {
case requestUrl:
Expand All @@ -1375,36 +1377,117 @@ describe('net module', () => {
handleUnexpectedURL(request, response)
}
})

const urlRequest = net.request({
method: 'GET',
url: `${server.url}${requestUrl}`
})

urlRequest.on('response', (response) => {
const statusCode = response.statusCode
assert(typeof statusCode === 'number')
assert.strictEqual(statusCode, 200)
const statusMessage = response.statusMessage
assert(typeof statusMessage === 'string')
assert.strictEqual(statusMessage, 'OK')
expect(response.statusCode).to.equal(200)
expect(response.statusMessage).to.equal('OK')

const headers = response.headers
assert(typeof headers === 'object')
assert.deepStrictEqual(headers[customHeaderName.toLowerCase()],
[customHeaderValue])
expect(headers).to.be.an('object')
const headerValue = headers[customHeaderName.toLowerCase()]
expect(headerValue).to.equal(customHeaderValue)

const httpVersion = response.httpVersion
assert(typeof httpVersion === 'string')
assert(httpVersion.length > 0)
expect(httpVersion).to.be.a('string').and.to.have.lengthOf.at.least(1)

const httpVersionMajor = response.httpVersionMajor
assert(typeof httpVersionMajor === 'number')
assert(httpVersionMajor >= 1)
expect(httpVersionMajor).to.be.a('number').and.to.be.at.least(1)

const httpVersionMinor = response.httpVersionMinor
assert(typeof httpVersionMinor === 'number')
assert(httpVersionMinor >= 0)
expect(httpVersionMinor).to.be.a('number').and.to.be.at.least(0)

response.pause()
response.on('data', (chunk) => {
})
response.on('end', () => {
done()
})
response.on('data', chunk => {})
response.on('end', () => { done() })
response.resume()
})
urlRequest.end()
})

it('should discard duplicate headers', (done) => {
const requestUrl = '/duplicateRequestUrl'
const includedHeader = 'max-forwards'
const discardableHeader = 'Max-Forwards'

const includedHeaderValue = 'max-fwds-val'
const discardableHeaderValue = 'max-fwds-val-two'

server.on('request', (request, response) => {
switch (request.url) {
case requestUrl:
response.statusCode = 200
response.statusMessage = 'OK'
response.setHeader(discardableHeader, discardableHeaderValue)
response.setHeader(includedHeader, includedHeaderValue)
response.end()
break
default:
handleUnexpectedURL(request, response)
}
})

const urlRequest = net.request({
method: 'GET',
url: `${server.url}${requestUrl}`
})

urlRequest.on('response', response => {
expect(response.statusCode).to.equal(200)
expect(response.statusMessage).to.equal('OK')

const headers = response.headers
expect(headers).to.be.an('object')

expect(headers).to.have.property(includedHeader)
expect(headers).to.not.have.property(discardableHeader)
expect(headers[includedHeader]).to.equal(includedHeaderValue)

response.pause()
response.on('data', chunk => {})
response.on('end', () => { done() })
response.resume()
})
urlRequest.end()
})

it('should join repeated non-discardable value with ,', (done) => {
const requestUrl = '/requestUrl'

server.on('request', (request, response) => {
switch (request.url) {
case requestUrl:
response.statusCode = 200
response.statusMessage = 'OK'
response.setHeader('referrer-policy', ['first-text', 'second-text'])
response.end()
break
default:
handleUnexpectedURL(request, response)
}
})

const urlRequest = net.request({
method: 'GET',
url: `${server.url}${requestUrl}`
})

urlRequest.on('response', response => {
expect(response.statusCode).to.equal(200)
expect(response.statusMessage).to.equal('OK')

const headers = response.headers
expect(headers).to.be.an('object')
expect(headers).to.have.a.property('referrer-policy')
expect(headers['referrer-policy']).to.equal('first-text, second-text')

response.pause()
response.on('data', chunk => {})
response.on('end', () => { done() })
response.resume()
})
urlRequest.end()
Expand Down
0