Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

0.0.2

  • Loading branch information...
commit 8dd8d33c3ad5b43773aafdd2747996419bbbeac0 0 parents
geta6 authored
Showing with 235 additions and 0 deletions.
  1. +83 −0 README.md
  2. +59 −0 index.coffee
  3. +66 −0 index.js
  4. +27 −0 package.json
83 README.md
@@ -0,0 +1,83 @@
+# connect-stream
+
+connect middleware for _206 Partial Content_.
+
+## about
+
+response capability to the `206 Partial Content` request of express is extended.
+
+main targets are mobile devices.
+
+---
+
+モバイルデバイスなどからaudioやvideoをリクエストした際に発行される
+`206 Partial Content`への応答能力を拡張します。
+
+connect-middlewareと同じように振る舞うのでexpressへの追加は容易です。
+
+## usage
+
+### for plain http
+
+```
+stream = require('connect-stream');
+http.createServer(function(req, res) {
+ movie = '/path/to/movie.mp4'
+ return res.stream(new Buffer(fs.readFileSync(movie), {
+ 'Content-Type': 'video/mp4'
+ }));
+}).listen(3000);
+```
+
+### for express
+
+exception example contained.
+
+#### configure
+
+```
+app.configure(function() {
+ app.use(require('connect-stream'));
+});
+```
+
+#### response
+
+```js
+fs = require('fs');
+path = require('path');
+
+app.get('/movie/:title', function(req, res) {
+ movie = path.join('path', 'to', 'movie', req.params.title + '.mp4');
+ if (fs.existsSync(path)) {
+ stat = fs.statSync(movie);
+ if (stat.isFile()) {
+ return res.stream(new Buffer(fs.readFileSync(movie), {
+ 'Content-Type': 'video/mp4',
+ 'Last-Modified': stat.mtime
+ }));
+ }
+ }
+ res.writeHead(404, {'Content-Type': 'text/plain'});
+ return res.end('Not Found');
+});
+```
+
+## arguments
+
+### res.stream(_buffer_, _headers_);
+
+#### buffer
+
+* required
+* should be pass `Buffer.isBuffer(buffer)`
+
+#### headers
+
+* optional, defalut `{}`
+* should be pass `_.isObject(headers)`
+* extends partial headers
+
+---
+
+© 2013 geta6
59 index.coffee
@@ -0,0 +1,59 @@
+_ = require 'underscore'
+fs = require 'fs'
+
+streamError = (err, res) ->
+ console.error 'Usage: res.stream(buffer, header);'
+ console.error err
+ res.writeHead 500
+ res.end()
+
+module.exports = (req, res, next) ->
+
+ res.stream = (buf, headers = {}) ->
+
+ # exception
+
+ unless Buffer.isBuffer buf
+ return streamError '`buffer` should be typeof Buffer', res
+
+ unless _.isObject headers
+ return streamError '`headers` should be typeof Object', res
+
+ # cached response
+
+ if headers['Last-Modified']
+ since = String req.headers['if-modified-since']
+ modify = String headers['Last-Modified']
+ if since is modify
+ res.writeHead 304
+ return res.end()
+
+ range = req.headers.range
+
+ # normal response
+
+ unless range
+ res.writeHead 200, _.extend headers,
+ 'Content-Length': buf.length
+ return res.end buf
+
+ # range response
+
+ unless 0 < buf.length
+ return streamError 'null buffer passed to `buffer`', res
+
+ total = buf.length
+ [ini, end] = _.map ((range.replace 'bytes=', '').split '-'), (n) -> parseInt n
+
+ end = total - 1 if (isNaN end) or (end is 0)
+
+ res.writeHead 206, _.extend headers,
+ 'Connection': 'close'
+ 'Cache-Control': 'private'
+ 'Content-Length': end - ini + 1
+ 'Content-Range': "bytes #{ini}-#{end}/#{total}"
+ 'Accept-Ranges': 'bytes'
+ 'Transfer-Encoding': 'chunked'
+ return res.end buf.slice ini, end+1
+
+ next()
66 index.js
@@ -0,0 +1,66 @@
+// Generated by CoffeeScript 1.4.0
+(function() {
+ var fs, streamError, _;
+
+ _ = require('underscore');
+
+ fs = require('fs');
+
+ streamError = function(err, res) {
+ console.error('Usage: res.stream(buffer, header);');
+ console.error(err);
+ res.writeHead(500);
+ return res.end();
+ };
+
+ module.exports = function(req, res, next) {
+ res.stream = function(buf, headers) {
+ var end, ini, modify, range, since, total, _ref;
+ if (headers == null) {
+ headers = {};
+ }
+ if (!Buffer.isBuffer(buf)) {
+ return streamError('`buffer` should be typeof Buffer', res);
+ }
+ if (!_.isObject(headers)) {
+ return streamError('`headers` should be typeof Object', res);
+ }
+ if (headers['Last-Modified']) {
+ since = String(req.headers['if-modified-since']);
+ modify = String(headers['Last-Modified']);
+ if (since === modify) {
+ res.writeHead(304);
+ return res.end();
+ }
+ }
+ range = req.headers.range;
+ if (!range) {
+ res.writeHead(200, _.extend(headers, {
+ 'Content-Length': buf.length
+ }));
+ return res.end(buf);
+ }
+ if (!(0 < buf.length)) {
+ return streamError('null buffer passed to `buffer`', res);
+ }
+ total = buf.length;
+ _ref = _.map((range.replace('bytes=', '')).split('-'), function(n) {
+ return parseInt(n);
+ }), ini = _ref[0], end = _ref[1];
+ if ((isNaN(end)) || (end === 0)) {
+ end = total - 1;
+ }
+ res.writeHead(206, _.extend(headers, {
+ 'Connection': 'close',
+ 'Cache-Control': 'private',
+ 'Content-Length': end - ini + 1,
+ 'Content-Range': "bytes " + ini + "-" + end + "/" + total,
+ 'Accept-Ranges': 'bytes',
+ 'Transfer-Encoding': 'chunked'
+ }));
+ return res.end(buf.slice(ini, end + 1));
+ };
+ return next();
+ };
+
+}).call(this);
27 package.json
@@ -0,0 +1,27 @@
+{
+ "name": "connect-stream",
+ "version": "0.0.2",
+ "description": "connect middleware for 206 partial content request",
+ "tags": [
+ "partial",
+ "utility",
+ "connect",
+ "video",
+ "stream"
+ ],
+ "author": {
+ "name": "geta6"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/geta6/connect-stream.git"
+ },
+ "dependencies": {
+ "underscore": "*"
+ },
+ "licenses": "MIT",
+ "main": "index.js",
+ "readmeFilename": "README.md",
+ "_id": "connect-stream@0.0.1",
+ "_from": "connect-stream@"
+}
Please sign in to comment.
Something went wrong with that request. Please try again.