Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add one stream support now.

  • Loading branch information...
commit fc8fd6713f3166ee0e7b2db48459f681f5a72291 1 parent 81acc17
@fengmk2 fengmk2 authored
View
7 .npmignore
@@ -0,0 +1,7 @@
+test/
+coverage.html
+lib-cov/
+Makefile
+.travis.yml
+logo.png
+example/
View
5 .travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+ - 0.9
+ - 0.8
+ - 0.6
View
21 LICENSE.txt
@@ -0,0 +1,21 @@
+This software is licensed under the MIT License.
+
+Copyright (C) 2012 by fengmk2 <fengmk2@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
20 Makefile
@@ -0,0 +1,20 @@
+TESTS = test/*.js
+REPORTER = spec
+TIMEOUT = 10000
+
+test:
+ @NODE_ENV=test ./node_modules/mocha/bin/mocha \
+ --reporter $(REPORTER) \
+ --timeout $(TIMEOUT) \
+ $(TESTS)
+
+test-cov:
+ @rm -rf ./lib-cov
+ @$(MAKE) lib-cov
+ @FORMSTREAM_COV=1 $(MAKE) test
+ @FORMSTREAM_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
+
+lib-cov:
+ @jscoverage lib $@
+
+.PHONY: test-cov test lib-cov
View
56 README.md
@@ -1,4 +1,56 @@
-formstream
+formstream [![Build Status](https://secure.travis-ci.org/fengmk2/formstream.png)](http://travis-ci.org/fengmk2/formstream)
==========
-multipart/form-data encoded stream, helper for file upload.
+![logo](https://raw.github.com/fengmk2/formstream/master/logo.png)
+
+A multipart/form-data encoded stream, helper for file upload.
+
+jscoverage: [-%](http://fengmk2.github.com/coverage/formstream.html)
+
+
+## Install
+
+```bash
+$ npm install formstream
+```
+
+## Usage
+
+```js
+var formstream = require('formstream');
+var http = require('http');
+
+var req = http.get('http://nodejs.org', function (res) {
+ res.on('data', function (chunk) {
+ console.log(charset(res.headers, chunk));
+ res.destroy();
+ });
+});
+
+form.pipe(req);
+```
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2012 fengmk2 &lt;fengmk2@gmail.com&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
52 example/upload.js
@@ -0,0 +1,52 @@
+/*!
+ * formstream - example/upload.js
+ * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com>
+ * MIT Licensed
+ */
+
+"use strict";
+
+/**
+ * Module dependencies.
+ */
+
+var formstream = require('../');
+var http = require('http');
+var fs = require('fs');
+var path = require('path');
+
+var filepath = __filename;
+var imagepath = path.join(path.dirname(__dirname), 'logo.png');
+
+var form = formstream.create();
+form.file('file', filepath);
+form.stream('image', fs.createReadStream(imagepath));
+form.field('foo', 'hello world');
+
+var req = http.request({
+ method: 'POST',
+ host: 'upload.cnodejs.net',
+ path: '/store',
+ headers: form.getHeaders()
+});
+req.on('response', function (res) {
+ console.log(res.statusCode, res.headers);
+ var chunks = [];
+ res.on('data', function (chunk) {
+ chunks.push(chunk);
+ }).on('end', function () {
+ console.log('%s', Buffer.concat(chunks).toString());
+ console.log('upload success.');
+ process.exit(0);
+ });
+});
+
+var size = 0;
+form.on('data', function (data) {
+ size += data.length;
+ console.log('uploading... %d bytes', size);
+ req.write(data);
+}).on('end', function () {
+ console.log('uploaded %d bytes', size);
+ req.end();
+});
View
1  index.js
@@ -0,0 +1 @@
+module.exports = process.env.FORMSTREAM_COV ? require('./lib-cov/formstream') : require('./lib/formstream');
View
119 lib/formstream.js
@@ -0,0 +1,119 @@
+/*!
+ * formstream - lib/formstream.js
+ * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com>
+ * MIT Licensed
+ *
+ * Data format:
+ *
+
+--FormStreamBoundary1349886663601\r\n
+Content-Disposition: form-data; name="foo"\r\n
+\r\n
+<FIELD-CONTENT>\r\n
+--FormStreamBoundary1349886663601\r\n
+Content-Disposition: form-data; name="file"; filename="formstream.test.js"\r\n
+Content-Type: application/javascript\r\n
+\r\n
+<FILE-CONTENT>\r\n
+--FormStreamBoundary1349886663601\r\n
+Content-Disposition: form-data; name="pic"; filename="fawave.png"\r\n
+Content-Type: image/png\r\n
+\r\n
+<IMAGE-CONTENT>\r\n
+--FormStreamBoundary1349886663601--
+
+ *
+ */
+
+"use strict";
+
+/**
+ * Module dependencies.
+ */
+
+var Stream = require('stream');
+var parseStream = require('pause-stream');
+var util = require('util');
+var mime = require('mime');
+var path = require('path');
+var fs = require('fs');
+
+var PADDING = '--';
+var NEW_LINE = '\r\n';
+
+function FormStream() {
+ if (!(this instanceof FormStream)) {
+ return new FormStream();
+ }
+
+ FormStream.super_.call(this);
+ this._boundary = 'FormStreamBoundary' + Date.now();
+ this._streams = [];
+ this._fields = [];
+
+}
+util.inherits(FormStream, Stream);
+module.exports = FormStream;
+
+FormStream.create = function () {
+ return new FormStream();
+};
+
+FormStream.prototype.file = function (name, filepath, filename) {
+ var mimeType = mime.lookup(filepath);
+ if (!filename) {
+ filename = path.basename(filepath);
+ }
+ this.stream(name, filename, mimeType, fs.createReadStream(filepath));
+};
+
+FormStream.prototype.field = function (name, value) {
+ this._fields.push([name, value]);
+ process.nextTick(this.resume.bind(this));
+};
+
+FormStream.prototype.stream = function (name, filename, mimeType, stream) {
+ var ps = parseStream().pause();
+ stream.pipe(ps);
+ this._streams.push([ name, filename, mimeType, ps ]);
+};
+
+FormStream.prototype.drain = function () {
+ if (this._fields.length > 0) {
+ var lines = '';
+ for (var i = 0; i < this._fields.length; i++) {
+ var field = this._fields[i];
+ lines += PADDING + this._boundary + NEW_LINE;
+ lines += 'Content-Disposition: form-data; name="' + field[0] + '"' + NEW_LINE;
+ lines += NEW_LINE;
+ lines += field[1] + NEW_LINE;
+ }
+ this._fields = [];
+ this.emit('data', lines);
+ }
+ var self = this;
+ var item = this._streams[0];
+ var data = PADDING + this._boundary + NEW_LINE;
+ data += 'Content-Disposition: form-data; name="' + item[0] +'"; filename="' + item[1] + '"' + NEW_LINE;
+ data += 'Content-Type: ' + item[2] + NEW_LINE;
+ data += NEW_LINE;
+ self.emit('data', data);
+
+ var stream = item[3];
+ stream.on('data', function (data) {
+ self.emit('data', data);
+ });
+ stream.on('end', function () {
+ var endData = NEW_LINE;
+ endData += PADDING + self._boundary + PADDING + NEW_LINE;
+ self.emit('data', endData);
+ self.emit('end');
+ });
+ stream.resume();
+};
+
+FormStream.prototype.resume = function () {
+ this.paused = false;
+ this.drain();
+ return this;
+};
View
BIN  logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
36 package.json
@@ -0,0 +1,36 @@
+{
+ "name": "formstream",
+ "version": "0.0.1",
+ "description": "A multipart/form-data encoded stream, helper for file upload.",
+ "main": "index.js",
+ "directories": {
+ "example": "example",
+ "test": "test"
+ },
+ "scripts": {
+ "test": "make test"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/fengmk2/formstream.git"
+ },
+ "keywords": [
+ "form",
+ "stream",
+ "multipart",
+ "form-data",
+ "upload",
+ "postfile",
+ "request"
+ ],
+ "devDependencies": {
+ "should": "*",
+ "mocha": "*"
+ },
+ "dependencies": {
+ "mime": "1.2.7",
+ "pause-stream": "0.0.5"
+ },
+ "author": "fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)",
+ "license": "MIT"
+}
View
50 test/formstream.test.js
@@ -0,0 +1,50 @@
+/*!
+ * formstream - test/formstream.js
+ * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com>
+ * MIT Licensed
+ */
+
+"use strict";
+
+/**
+ * Module dependencies.
+ */
+
+var formstream = require('../');
+var Stream = require('stream');
+
+describe('formstream.test.js', function () {
+ it('should emit fields first then file data', function (done) {
+ var form = formstream();
+ form.field('foo', 'bar');
+ form.file('file', __filename);
+ form.pipe(process.stdout);
+ form.on('end', function () {
+ process.nextTick(done);
+ });
+ });
+
+ it.only('should emit fields first then stream data', function (done) {
+ var form = formstream();
+ form.field('foo', '中文');
+ var s = new Stream();
+ var count = 0;
+ var timer = setInterval(function () {
+ s.emit('data', 'counter stream' + count + '\r\n');
+ count++;
+ if (count >= 5) {
+ clearInterval(timer);
+ process.nextTick(function () {
+ s.emit('end');
+ });
+ }
+ }, 500);
+ form.stream('stream', 'stream.txt', 'text/html', s);
+ form.pipe(process.stdout);
+ form.on('end', function () {
+ process.nextTick(done);
+ });
+ });
+});
+
+// end
Please sign in to comment.
Something went wrong with that request. Please try again.