Skip to content

Commit

Permalink
Add support for sending trailers (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
blakeembrey committed Mar 17, 2017
1 parent eab7f16 commit 2fdb181
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 19 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,10 @@
"express": "^4.15.2",
"jest": "^19.0.0",
"parseurl": "^1.3.1",
"popsicle": "^9.1.0",
"popsicle-server": "^2.0.0",
"rimraf": "^2.5.4",
"servie": "^0.2.0",
"servie-route": "^0.3.1",
"throwback": "^2.0.0",
"ts-jest": "^19.0.0",
"tslint": "^4.3.1",
"tslint-config-standard": "^4.0.0",
Expand Down
61 changes: 50 additions & 11 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,58 @@
import { Response } from 'servie'
import { get } from 'servie-route'
import { request } from 'popsicle'
import popsicleServer = require('popsicle-server')
import { compose } from 'throwback'
import { createReadStream } from 'fs'
import * as http from 'http'
import { join } from 'path'
import { createHandler } from './index'

describe('servie-http', () => {
const handler = createHandler(get('/', () => {
return new Response({ body: 'hello world' })
}))

it('should work over http', () => {
return request('/')
.use(popsicleServer(handler))
.then((res) => {
expect(res.body).toBe('hello world')
const handler = createHandler(compose([
get('/', () => {
return new Response({ body: 'hello world' })
}),
get('/stream', () => {
return new Response({
body: createReadStream(join(__dirname, 'index.ts')),
headers: {
'Trailer': 'Server-Timing'
},
trailers: {
'Server-Timing': 'end=100'
}
})
})
]))

const server = http.createServer(handler).listen(0)

afterAll(() => server.close())

it('should work over http', (done) => {
return http.get(`http://localhost:${server.address().port}`, (res) => {
let data = ''

res.on('data', (chunk: Buffer) => data += chunk.toString('utf8'))

res.on('end', () => {
expect(res.headers['content-type']).toEqual('text/plain')
expect(res.headers['content-length']).toEqual('11')
expect(data).toBe('hello world')

return done()
})
})
})

it('should send trailers', (done) => {
return http.get(`http://localhost:${server.address().port}/stream`, (res) => {
res.resume()

res.on('end', () => {
expect(res.trailers).toEqual({ 'server-timing': 'end=100' })

return done()
})
})
})
})
28 changes: 25 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Request, Response } from 'servie'
import { Request, Response, Headers } from 'servie'
import { IncomingMessage, ServerResponse } from 'http'
import { TLSSocket } from 'tls'
import { finalhandler } from 'servie-finalhandler'
Expand All @@ -11,6 +11,9 @@ export interface Options {
logError?: (err: any) => void
}

/**
* Create a node.js-compatible http handler.
*/
export function createHandler (app: App, options: Options = {}) {
return function (request: IncomingMessage, response: ServerResponse): void {
let responded = false
Expand Down Expand Up @@ -55,14 +58,20 @@ export function createHandler (app: App, options: Options = {}) {
}

if (res.bodyBuffered) {
response.addTrailers(toTrailers(res.trailers))
response.end(res.body)
} else {
res.stream().pipe(response).on('error', (err: Error) => sendError(err))
const stream = res.stream()

stream.on('error', sendError)
stream.on('end', () => response.addTrailers(toTrailers(res.trailers)))

stream.pipe(response)
}
}

// Handle request and response errors.
req.events.on('error', (err: Error) => sendError(err))
req.events.on('error', sendError)
req.events.on('abort', () => sendResponse(new Response({ status: 444 })))

req.started = true
Expand All @@ -74,3 +83,16 @@ export function createHandler (app: App, options: Options = {}) {
)
}
}

/**
* Convert the trailers object into a list of trailers for node.js.
*/
function toTrailers (trailers: Headers): any {
const result: [string, string][] = new Array(trailers.raw.length / 2)

for (let i = 0; i < trailers.raw.length; i += 2) {
result[i / 2] = [trailers.raw[i], trailers.raw[i + 1]]
}

return result
}
3 changes: 0 additions & 3 deletions typings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,5 @@
"globalDevDependencies": {
"jest": "registry:dt/jest#16.0.0+20170112172802",
"node": "registry:env/node#6.0.0+20170213133316"
},
"devDependencies": {
"popsicle": "npm:popsicle"
}
}

0 comments on commit 2fdb181

Please sign in to comment.