1'use strict'; 2 3// Tests the ability to minimally request a byte range with respondWithFD 4 5const common = require('../common'); 6if (!common.hasCrypto) 7 common.skip('missing crypto'); 8const fixtures = require('../common/fixtures'); 9const http2 = require('http2'); 10const assert = require('assert'); 11const fs = require('fs'); 12const Countdown = require('../common/countdown'); 13 14const { 15 HTTP2_HEADER_CONTENT_TYPE, 16 HTTP2_HEADER_CONTENT_LENGTH 17} = http2.constants; 18 19const fname = fixtures.path('printA.js'); 20const data = fs.readFileSync(fname); 21const fd = fs.openSync(fname, 'r'); 22 23// Note: this is not anywhere close to a proper implementation of the range 24// header. 25function getOffsetLength(range) { 26 if (range === undefined) 27 return [0, -1]; 28 const r = /bytes=(\d+)-(\d+)/.exec(range); 29 return [+r[1], +r[2] - +r[1]]; 30} 31 32const server = http2.createServer(); 33server.on('stream', (stream, headers) => { 34 35 const [ offset, length ] = getOffsetLength(headers.range); 36 37 stream.respondWithFD(fd, { 38 [HTTP2_HEADER_CONTENT_TYPE]: 'text/plain' 39 }, { 40 statCheck: common.mustCall((stat, headers, options) => { 41 assert.strictEqual(options.length, length); 42 assert.strictEqual(options.offset, offset); 43 headers['content-length'] = 44 Math.min(options.length, stat.size - offset); 45 }), 46 offset: offset, 47 length: length 48 }); 49}); 50server.on('close', common.mustCall(() => fs.closeSync(fd))); 51 52server.listen(0, () => { 53 const client = http2.connect(`http://localhost:${server.address().port}`); 54 55 const countdown = new Countdown(2, () => { 56 client.close(); 57 server.close(); 58 }); 59 60 { 61 const req = client.request({ range: 'bytes=8-11' }); 62 63 req.on('response', common.mustCall((headers) => { 64 assert.strictEqual(headers['content-type'], 'text/plain'); 65 assert.strictEqual(+headers['content-length'], 3); 66 })); 67 req.setEncoding('utf8'); 68 let check = ''; 69 req.on('data', (chunk) => check += chunk); 70 req.on('end', common.mustCall(() => { 71 assert.strictEqual(check, data.toString('utf8', 8, 11)); 72 })); 73 req.on('close', common.mustCall(() => countdown.dec())); 74 req.end(); 75 } 76 77 { 78 const req = client.request({ range: 'bytes=8-28' }); 79 80 req.on('response', common.mustCall((headers) => { 81 assert.strictEqual(headers[HTTP2_HEADER_CONTENT_TYPE], 'text/plain'); 82 assert.strictEqual(+headers[HTTP2_HEADER_CONTENT_LENGTH], 9); 83 })); 84 req.setEncoding('utf8'); 85 let check = ''; 86 req.on('data', (chunk) => check += chunk); 87 req.on('end', common.mustCall(() => { 88 assert.strictEqual(check, data.toString('utf8', 8, 28)); 89 })); 90 req.on('close', common.mustCall(() => countdown.dec())); 91 req.end(); 92 } 93 94}); 95