fs.read(fd, buffer, 0, chunkSize, position, track(function (err, bytesRead) { if (err) { errors++; out.print("Error reading file (" + file + ")"); return; } var slice = buffer.slice(0, bytesRead); if (position == 0) { var headers = new meta.headers(), keys = file.split('/'); headers.set({ 'Content-Type': meta.sniff(file, slice), 'Content-Length': stats.size, 'Content-Disposition': [ 'attachment', { 'filename': keys.pop() } ], }); pipes.dataOut.write(headers.generate()); } pipes.dataOut.write(slice); position += bytesRead; if (position < stats.size) { read(); } progress && out.update('progress', { value: position }); })); // fs.read
request.on('response', function (res) { var headers = res.headers; process.stderr.write('headers '+ JSON.stringify(res.headers) + "\n\n"); length = headers['content-length']; if (length !== null) { progress = length > 16 * 1024; // yes, this is arbitrary if (progress) { out.add(null, view.progress('progress', 0, 0, length)); } } var mime = new meta.headers(); for (i in headers) { var key = i.replace(/(^|-)(.)/g, function (x,a,b) { return a + b.toUpperCase(); }); mime.set(key, headers[i].toString('utf8'), null, true); } // Write headers straight through. pipes.dataOut.write(mime.generate()); res.on('data', function (data) { // Track progress. received += data.length; progress && out.update('progress', { value: received }); // Pipe out. pipes.dataOut.write(data); }); res.on('end', function () { process.stderr.write('received ' + received + ' length ' + length); out.remove('progress'); exit(true); }); });
/** * Test grep.js */ function testGrep(assert) { var handler = grep.main, exit = function () {}, headers, content, pipes; // Helper for converting strings to buffers. function buffer(data) { if (data.constructor != Buffer) { data = new Buffer(data, 'utf8'); } return data; } // Simple grep. pipes = mockPipes(); handler([ 'grep', 'ba' ], pipes, exit); pipes.dataOut.on('data', function (data) { if (data.toString('utf-8').indexOf('\r\n\r\n') >= 0) return; var lines = data.toString('utf-8').split("\n"); assert(lines.length == 3 && lines[0] == 'bar' && lines[1] == 'baz' && lines[2] == 'ccbacc', "Grep plaintext lines"); }); headers = new meta.headers(); content = "foo\nbar\nbaz\nbingo\nccbacc\n\n\nfffuuu\n"; headers.set('Content-Type', 'text/plain'); headers.set('Content-Length', content.length); pipes.dataIn.emit('data', buffer(headers.generate())); pipes.dataIn.emit('data', buffer(content)); pipes.dataIn.emit('end'); // Simple grep (negative). pipes = mockPipes(); handler([ 'grep', '-v', 'ba' ], pipes, exit); pipes.dataOut.on('data', function (data) { if (data.toString('utf-8').indexOf('\r\n\r\n') >= 0) return; var lines = data.toString('utf-8').split("\n"); assert(lines.length == 5 && lines[0] == 'foo' && lines[1] == 'bingo' && lines[2] == '' && lines[3] == '' && lines[4] == 'fffuuu', "Grep plaintext lines (negative)"); }); headers = new meta.headers(); content = "foo\nbar\nbaz\nbingo\nccbacc\n\n\nfffuuu\n"; headers.set('Content-Type', 'text/plain'); headers.set('Content-Length', content.length); pipes.dataIn.emit('data', buffer(headers.generate())); pipes.dataIn.emit('data', buffer(content)); pipes.dataIn.emit('end'); // JSON grep. pipes = mockPipes(); handler([ 'grep', 'ba' ], pipes, exit); pipes.dataOut.on('data', function (data) { data = data.toString('utf-8'); if (data.indexOf('\r\n\r\n') >= 0) return; assert(data == '{"foo":"bar","baz":"bang"}', "Grep JSON object"); }); headers = new meta.headers(); content = '{"foo":"bar","baz":"bang","bingo":"fffuu"}'; headers.set('Content-Type', 'application/json'); headers.set('Content-Length', content.length); pipes.dataIn.emit('data', buffer(headers.generate())); pipes.dataIn.emit('data', buffer(content)); pipes.dataIn.emit('end'); // JSON grep (negative). pipes = mockPipes(); handler([ 'grep', '-v', 'ba' ], pipes, exit); pipes.dataOut.on('data', function (data) { data = data.toString('utf-8'); if (data.indexOf('\r\n\r\n') >= 0) return; assert(data == '{"bingo":"fffuu"}', "Grep JSON object (negative)"); }); headers = new meta.headers(); content = '{"foo":"bar","baz":"bang","bingo":"fffuu"}'; headers.set('Content-Type', 'application/json'); headers.set('Content-Length', content.length); pipes.dataIn.emit('data', buffer(headers.generate())); pipes.dataIn.emit('data', buffer(content)); pipes.dataIn.emit('end'); // Complex JSON grep. pipes = mockPipes(); handler([ 'grep', 'X' ], pipes, exit); pipes.dataOut.on('data', function (data) { data = data.toString('utf-8'); if (data.indexOf('\r\n\r\n') >= 0) return; assert(data == '["xXx",{"foo":"XX","baz":"X"},["XX","XXX"]]', "Grep complex JSON array/object"); }); headers = new meta.headers(); content = '[ "---", "xXx", { "foo": "XX", "bar": "YY", "baz": "X" }, { "meh": "no" }, [ 1, "XX", 3, "XXX" ]]'; headers.set('Content-Type', 'application/json'); headers.set('Content-Length', content.length); pipes.dataIn.emit('data', buffer(headers.generate())); pipes.dataIn.emit('data', buffer(content)); pipes.dataIn.emit('end'); // Complex JSON key grep. pipes = mockPipes(); handler([ 'grep', '-k', 'a' ], pipes, exit); pipes.dataOut.on('data', function (data) { data = data.toString('utf-8'); if (data.indexOf('\r\n\r\n') >= 0) return; assert(data == '[{"bar":"YY","baz":"X"},{"mah":"no"}]', "Grep complex JSON array/object (keys)"); }); headers = new meta.headers(); content = '[ "---", "xXx", { "foo": "XX", "bar": "YY", "baz": "X" }, { "mah": "no" }, [ {"foo":"bar"}, "XX", 3, "XXX" ]]'; headers.set('Content-Type', 'application/json'); headers.set('Content-Length', content.length); pipes.dataIn.emit('data', buffer(headers.generate())); pipes.dataIn.emit('data', buffer(content)); pipes.dataIn.emit('end'); // Tricky object grep pipes = mockPipes(); handler([ 'grep', 'lulz' ], pipes, exit); pipes.dataOut.on('data', function (data) { data = data.toString('utf-8'); if (data.indexOf('\r\n\r\n') >= 0) return; assert(data == '{"list":[{"lol":"lulz"}]}', "Tricky object grep"); }); headers = new meta.headers(); content = '{"foo": "bar", "meh": "teh", "lol": "wai", "list": [ { "lol": "lulz", "fail": "json" } , "wtf" ] }'; headers.set('Content-Type', 'application/json'); headers.set('Content-Length', content.length); pipes.dataIn.emit('data', buffer(headers.generate())); pipes.dataIn.emit('data', buffer(content)); pipes.dataIn.emit('end'); }
/** * Test mime-type handling. */ function testMeta(assert) { var headers, set, string; // Test basic getters and setters. headers = new meta.headers(); headers.set('Content-Type', 'text/plain'); assert(headers.get('Content-Type') == 'text/plain', 'Value getter/setter'); headers.set('Content-Type', 'charset', 'utf-8'); assert(headers.get('Content-Type', 'charset') == 'utf-8', 'Param getter/setter'); headers.set('Content-Type', [ 'text/html', { 'charset': 'iso-8859-1' } ]); assert(headers.get('Content-Type') == 'text/html' && headers.get('Content-Type', 'charset') == 'iso-8859-1', 'Combined getter/setter'); // Test multiple value getters/setters. headers.set('Accept-Encoding', [ 'compress', 'gzip' ]); set = headers.get('Accept-Encoding'); assert(set.length == 2 && set[0] == 'compress' && set[1] == 'gzip', 'Multi-value getter/setter'); headers.set('Accept', [ [ 'text/html', { 'q': 1 } ], [ 'text/css' ], [ 'text/plain', { 'q': 0.8 } ], ] ); set = headers.get('Accept'); assert(set.length == 3 && set[0] == 'text/html' && set[1] == 'text/css' && set[2] == 'text/plain', 'Multi-value getter/setter combined'); set = headers.get('Accept', 'q'); assert(set.length == 3 && set[0] == 1 && typeof set[1] == 'undefined' && set[2] == 0.8, 'Multi-param getter/setter combined'); // Test parsing rules of RFC 822 values. headers = new meta.headers(); assert(headers.parseValue('"application/javascript"') == 'application/javascript', "Parse quoted value"); assert(headers.parseValue('"app\\"li\\\\cati\\on\\/javascript"') == 'app"li\\cation/javascript', "Parse quoted value with escapes"); set = headers.parseValue('max-age=0', true); assert(set[0] == null && typeof set[1] == 'object' && set[1]['max-age'] == '0', "Parse param"); set = headers.parseValue('application/javascript;charset=utf-8', true); assert(set[0] == 'application/javascript' && typeof set[1] == 'object' && set[1].charset == 'utf-8', "Parse value + param"); set = headers.parseValue('application/javascript; charset="utf-8"', true); assert(set[0] == 'application/javascript' && typeof set[1] == 'object' && set[1].charset == 'utf-8', "Parse value + quoted param"); string = 'Mozilla/5.0 (Macintosh; U; (Intel Mac OS X 10_6_7); en-ca) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27'; set = headers.parseValue(string, true); assert(headers.parseValue(string) == string, "Pass-through comments safely"); // Parse entire set of headers at once. headers.parse([ 'Content-Type: text/plain;\r\n charset="utf-16"', 'Content-Disposition: attachment; filename=genome.jpeg;\r\n modification-date="Wed, 12 February 1997 16:29:51 -0500";', 'Foo: bar', 'Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'X-Unknown: this "value does not follow, (mime syntax', ].join("\r\n")); assert(headers.get('Content-Type') == 'text/plain', 'Parse folded line'); assert(headers.get('Content-Type', 'charset') == 'utf-16', 'Parse folded line'); assert(headers.get('Content-Disposition') == 'attachment', 'Mixed parameters'); assert(headers.get('Content-Disposition', 'filename') == 'genome.jpeg', 'Mixed parameters'); assert(headers.get('Content-Disposition', 'modification-date') == 'Wed, 12 February 1997 16:29:51 -0500', 'Mixed parameters'); assert(headers.get('Foo') == 'bar', 'Basic property'); assert(headers.get('X-Unknown') == 'this "value does not follow, (mime syntax', 'Unparseable property'); set = headers.get('Accept'); assert(set.length == 6 && set[0] == 'application/xml' && set[5] == '*/*', 'Identical properties'); set = headers.get('Accept', 'q'); assert(set.length == 6 && typeof set[1] == 'undefined' && set[2] == '0.9' && set[3] == '0.8' && set[5] == '0.5', 'Identical property parameters'); // Generate headers back. var string = headers.generate(); assert(/\r\n\r\n$/(string), 'Headers end in CRLF x2'); assert(string.split(/\r\n/).length == 5 + 2, '5 Headers returned'); assert(/^Content-Type:\s*text\/plain;\s*charset=utf-16\r\n/m, 'Content-Type correct'); assert(/^Content-Disposition:\s*attachment;\s*filename=genome.jpeg;\s*modification-date="Wed, 12 February 1997 16:29:51 -0500"\r\n/m, 'Content-Disposition correct'); assert(/^Foo: bar\r\n/m, 'Foo correct'); assert(/^Accept: application\/xml,application\/xhtml\+xml,text\/html;q=0.9,text\/plain;q=0.8,image\/png,\*\/\*;q=0.5\r\n/m, 'Accept correct'); assert(/^X-Unknown: "this \"value does not follow, \(mime syntax"\r\n/m, 'X-Unknown correct'); // Test raw set from mime-like source. headers = new meta.headers(); headers.set('Content-Type', 'text/plain; charset=utf-8', null, true); console.log(headers.fields); console.log(headers.params); assert(headers.get('Content-Type') == 'text/plain', 'Raw getter/setter'); assert(headers.get('Content-Type', 'charset') == 'utf-8', 'Raw param getter/setter'); }