Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: onInfo & onTrailers options
Browse files Browse the repository at this point in the history
Fixes: #179
Fixes: #196
ronag committed Aug 1, 2020
1 parent 251c610 commit 3d079f0
Showing 8 changed files with 252 additions and 6 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -106,6 +106,9 @@ Options:
If `false` the request won't be sent until all preceeding
requests in the pipeline has completed.
Default: `true` if `method` is `HEAD` or `GET`.
* `onInfo(statusCode, headers)`, function invoked for informational
1xx responses.
* `onTrailers(trailers)`, function invoked for trailers.

Headers are represented by an object like this:

21 changes: 21 additions & 0 deletions lib/client-pipeline.js
Original file line number Diff line number Diff line change
@@ -21,11 +21,28 @@ class PipelineRequest extends Request {
constructor (client, opts, callback) {
super(opts, client)

if (opts.onInfo && typeof opts.onInfo !== 'function') {
throw new InvalidArgumentError('invalid opts.onInfo')
}

if (opts.onTrailers && typeof opts.onTrailers !== 'function') {
throw new InvalidArgumentError('invalid opts.onTrailers')
}

this.callback = callback
this.aborted = false
this.onInfo = opts.onInfo
this.onTrailers = opts.onTrailers
}

_onHeaders (statusCode, headers, resume) {
if (statusCode < 200) {
if (this.onInfo) {
this.onInfo(statusCode, headers)
}
return
}

const { callback } = this

assert(callback)
@@ -48,6 +65,10 @@ class PipelineRequest extends Request {
const res = this.res
this.res = null
res(null, null)

if (this.onTrailers) {
this.onTrailers(trailers)
}
}

_onError (err) {
21 changes: 21 additions & 0 deletions lib/client-request.js
Original file line number Diff line number Diff line change
@@ -20,13 +20,30 @@ class RequestRequest extends Request {
throw new InvalidArgumentError('invalid method')
}

if (opts.onInfo && typeof opts.onInfo !== 'function') {
throw new InvalidArgumentError('invalid opts.onInfo')
}

if (opts.onTrailers && typeof opts.onTrailers !== 'function') {
throw new InvalidArgumentError('invalid opts.onTrailers')
}

super(opts, client)

this.callback = callback
this.res = null
this.onInfo = opts.onInfo
this.onTrailers = opts.onTrailers
}

_onHeaders (statusCode, headers, resume) {
if (statusCode < 200) {
if (this.onInfo) {
this.onInfo(statusCode, headers)
}
return
}

const { callback, opaque } = this

assert(callback)
@@ -64,6 +81,10 @@ class RequestRequest extends Request {

_onComplete (trailers) {
this.res.push(null)

if (this.onTrailers) {
this.onTrailers(trailers)
}
}

_onError (err) {
21 changes: 21 additions & 0 deletions lib/client-stream.js
Original file line number Diff line number Diff line change
@@ -24,14 +24,31 @@ class StreamRequest extends Request {
throw new InvalidArgumentError('invalid method')
}

if (opts.onInfo && typeof opts.onInfo !== 'function') {
throw new InvalidArgumentError('invalid opts.onInfo')
}

if (opts.onTrailers && typeof opts.onTrailers !== 'function') {
throw new InvalidArgumentError('invalid opts.onTrailers')
}

super(opts, client)

this.factory = factory
this.callback = callback
this.res = null
this.onInfo = opts.onInfo
this.onTrailers = opts.onTrailers
}

_onHeaders (statusCode, headers, resume) {
if (statusCode < 200) {
if (this.onInfo) {
this.onInfo(statusCode, headers)
}
return
}

const { factory, opaque } = this

assert(factory)
@@ -109,6 +126,10 @@ class StreamRequest extends Request {
if (this.res) {
this.res.end()
}

if (this.onTrailers) {
this.onTrailers(trailers)
}
}

_onError (err) {
6 changes: 1 addition & 5 deletions lib/client.js
Original file line number Diff line number Diff line change
@@ -508,11 +508,7 @@ class Parser extends HTTPParser {

// TODO: More statusCode validation?

if (statusCode >= 200) {
request.onHeaders(statusCode, headers, resumeSocket)
} else {
// TODO: Info
}
request.onHeaders(statusCode, headers, resumeSocket)

return request.method === 'HEAD' || statusCode < 200 ? 1 : 0
}
61 changes: 61 additions & 0 deletions test/client-pipeline.js
Original file line number Diff line number Diff line change
@@ -893,3 +893,64 @@ test('pipeline body without destroy', (t) => {
.resume()
})
})

test('trailers', (t) => {
t.plan(2)

const server = createServer((req, res) => {
res.writeHead(200, { Trailer: 'Content-MD5' })
res.addTrailers({ 'Content-MD5': 'test' })
res.end()
})
t.tearDown(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.tearDown(client.close.bind(client))

client.pipeline({
path: '/',
method: 'GET',
onTrailers: (trailers) => {
t.strictDeepEqual({ 'content-md5': 'test' }, trailers)
}
}, ({ body }) => body)
.end()
.resume()
.on('end', () => {
t.pass()
})
})
})

test('info', (t) => {
t.plan(2)

const server = createServer((req, res) => {
req.pipe(res)
})
t.tearDown(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.tearDown(client.close.bind(client))

let recv = ''

client.pipeline({
path: '/',
method: 'POST',
headers: { Expect: '100-continue' },
onInfo: (statusCode, trailers) => {
t.strictEqual(statusCode, 100)
}
}, ({ body }) => body)
.end('hello')
.on('data', chunk => {
recv += chunk
})
.on('end', () => {
t.strictEqual(recv, 'hello')
})
})
})
61 changes: 61 additions & 0 deletions test/client-request.js
Original file line number Diff line number Diff line change
@@ -38,3 +38,64 @@ test('request abort before headers', (t) => {
})
})
})

test('trailers', (t) => {
t.plan(3)

const server = createServer((req, res) => {
res.writeHead(200, { Trailer: 'Content-MD5' })
res.addTrailers({ 'Content-MD5': 'test' })
res.end()
})
t.tearDown(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.tearDown(client.close.bind(client))

client.request({
path: '/',
method: 'GET',
onTrailers: (trailers) => {
t.strictDeepEqual({ 'content-md5': 'test' }, trailers)
}
}, (err, data) => {
t.error(err)
data.body.on('end', () => {
t.pass()
}).resume()
})
})
})

test('info', (t) => {
t.plan(3)

const server = createServer((req, res) => {
req.pipe(res)
})
t.tearDown(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.tearDown(client.close.bind(client))

client.request({
path: '/',
method: 'POST',
body: 'hello',
headers: { Expect: '100-continue' },
onInfo: (statusCode, trailers) => {
t.strictEqual(statusCode, 100)
}
}, (err, data) => {
t.error(err)
let recv = ''
data.body.on('end', () => {
t.strictEqual(recv, 'hello')
}).on('data', buf => {
recv += buf
})
})
})
})
64 changes: 63 additions & 1 deletion test/client-stream.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
const { test } = require('tap')
const { Client, errors } = require('..')
const { createServer } = require('http')
const { PassThrough } = require('stream')
const { PassThrough, Writable } = require('stream')
const EE = require('events')

test('stream get', (t) => {
@@ -518,3 +518,65 @@ test('stream abort after complete', (t) => {
})
})
})

test('trailers', (t) => {
t.plan(2)

const server = createServer((req, res) => {
res.writeHead(200, { Trailer: 'Content-MD5' })
res.addTrailers({ 'Content-MD5': 'test' })
res.end()
})
t.tearDown(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.tearDown(client.close.bind(client))

client.stream({
path: '/',
method: 'GET',
onTrailers: (trailers) => {
t.strictDeepEqual({ 'content-md5': 'test' }, trailers)
}
}, () => null, (err, data) => {
t.error(err)
})
})
})

test('info', (t) => {
t.plan(3)

const server = createServer((req, res) => {
req.pipe(res)
})
t.tearDown(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.tearDown(client.close.bind(client))

let recv = ''

client.stream({
path: '/',
method: 'POST',
body: 'hello',
headers: { Expect: '100-continue' },
onInfo: (statusCode, trailers) => {
t.strictEqual(statusCode, 100)
}
}, () => {
return new Writable({
write (chunk, encoding, callback) {
recv += chunk
callback()
}
})
}, (err) => {
t.error(err)
t.strictEqual(recv, 'hello')
})
})
})

0 comments on commit 3d079f0

Please sign in to comment.