Comparing version 1.0.1 to 1.1.0
130
index.js
@@ -0,1 +1,2 @@ | ||
var StringDecoder = require('string_decoder').StringDecoder | ||
var bytes = require('bytes') | ||
@@ -11,15 +12,3 @@ | ||
if (!stream._readableState) { | ||
// dump the stream, though it's probably unnecessary | ||
if (typeof stream.resume === 'function') | ||
stream.resume() | ||
process.nextTick(function () { | ||
var err = new Error('only readable streams are supported') | ||
err.status = 500 | ||
done(err) | ||
}) | ||
return defer | ||
} | ||
// convert the limit to an integer | ||
var limit = null | ||
@@ -31,2 +20,3 @@ if (typeof options.limit === 'number') | ||
// convert the expected length to an integer | ||
var length = null | ||
@@ -36,8 +26,14 @@ if (!isNaN(options.length)) | ||
// check the length and limit options. | ||
// note: we intentionally leave the stream paused, | ||
// so users should handle the stream themselves. | ||
if (limit !== null && length !== null && length > limit) { | ||
stream.resume() // dump stream | ||
if (typeof stream.pause === 'function') { | ||
stream.pause() | ||
} | ||
process.nextTick(function () { | ||
var err = new Error('request entity too large') | ||
err.status = 413 | ||
err.length = length | ||
var err = makeError('request entity too large', 'entity.too.large') | ||
err.status = err.statusCode = 413 | ||
err.length = err.expected = length | ||
err.limit = limit | ||
@@ -49,4 +45,27 @@ done(err) | ||
var state = stream._readableState | ||
// streams2+: assert the stream encoding is buffer. | ||
if (state && state.encoding !== null) { | ||
if (typeof stream.pause === 'function') { | ||
stream.pause() | ||
} | ||
process.nextTick(function () { | ||
var err = makeError('stream encoding should not be set', | ||
'stream.encoding.set') | ||
// developer error | ||
err.status = err.statusCode = 500 | ||
done(err) | ||
}) | ||
return defer | ||
} | ||
var received = 0 | ||
var buffers = [] | ||
// note: we delegate any invalid encodings to the constructor | ||
var decoder = options.encoding | ||
? new StringDecoder(options.encoding === true ? 'utf8' : options.encoding) | ||
: null | ||
var buffer = decoder | ||
? '' | ||
: [] | ||
@@ -60,2 +79,3 @@ stream.on('data', onData) | ||
// yieldable support | ||
function defer(fn) { | ||
@@ -66,8 +86,12 @@ done = fn | ||
function onData(chunk) { | ||
buffers.push(chunk) | ||
received += chunk.length | ||
decoder | ||
? buffer += decoder.write(chunk) | ||
: buffer.push(chunk) | ||
if (limit !== null && received > limit) { | ||
var err = new Error('request entity too large') | ||
err.status = 413 | ||
if (typeof stream.pause === 'function') | ||
stream.pause() | ||
var err = makeError('request entity too large', 'entity.too.large') | ||
err.status = err.statusCode = 413 | ||
err.received = received | ||
@@ -82,18 +106,18 @@ err.limit = limit | ||
if (err) { | ||
if (typeof stream.pause === 'function') { | ||
stream.pause() | ||
} | ||
done(err) | ||
} else if (length !== null && received !== length) { | ||
var state = stream._readableState | ||
if (!state || state.encoding === null) { | ||
err = new Error('request size did not match content length') | ||
err.status = 400 | ||
err.received = received | ||
err.length = length | ||
done(err) | ||
} else { | ||
err = new Error('raw-body expects a buffer stream, but a string chunk was received. please do not set an encoding') | ||
err.status = 500 | ||
done(err) | ||
} | ||
err = makeError('request size did not match content length', | ||
'request.size.invalid') | ||
err.status = err.statusCode = 400 | ||
err.received = received | ||
err.length = err.expected = length | ||
done(err) | ||
} else { | ||
done(null, Buffer.concat(buffers)) | ||
done(null, decoder | ||
? buffer + endStringDecoder(decoder) | ||
: Buffer.concat(buffer) | ||
) | ||
} | ||
@@ -105,3 +129,3 @@ | ||
function cleanup() { | ||
received = buffers = null | ||
received = buffer = null | ||
@@ -113,2 +137,36 @@ stream.removeListener('data', onData) | ||
} | ||
} | ||
} | ||
// to create serializable errors you must re-set message so | ||
// that it is enumerable and you must re configure the type | ||
// property so that is writable and enumerable | ||
function makeError(message, type) { | ||
var error = new Error() | ||
error.message = message | ||
Object.defineProperty(error, 'type', { | ||
value: type, | ||
enumerable: true, | ||
writable: true, | ||
configurable: true | ||
}) | ||
return error | ||
} | ||
// https://github.com/Raynos/body/blob/2512ced39e31776e5a2f7492b907330badac3a40/index.js#L72 | ||
// bug fix for missing `StringDecoder.end` in v0.8.x | ||
function endStringDecoder(decoder) { | ||
if (decoder.end) { | ||
return decoder.end() | ||
} | ||
var res = "" | ||
if (decoder.charReceived) { | ||
var cr = decoder.charReceived | ||
var buf = decoder.charBuffer | ||
var enc = decoder.encoding | ||
res += buf.slice(0, cr).toString(enc) | ||
} | ||
return res | ||
} |
{ | ||
"name": "raw-body", | ||
"description": "Get and validate the raw body of a readable stream.", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"author": { | ||
@@ -24,9 +24,13 @@ "name": "Jonathan Ong", | ||
"devDependencies": { | ||
"co": "*", | ||
"gnode": "*", | ||
"mocha": "*" | ||
"readable-stream": "~1.0.17", | ||
"co": "2", | ||
"gnode": "~0.0.4", | ||
"mocha": "~1.14.0", | ||
"through": "~2.3.4", | ||
"request": "~2.27.0", | ||
"assert-tap": "~0.1.4" | ||
}, | ||
"scripts": { | ||
"test": "NODE=gnode make test" | ||
"test": "NODE=gnode make test && node ./test/acceptance.js" | ||
} | ||
} |
# Raw Body [![Build Status](https://travis-ci.org/stream-utils/raw-body.png)](https://travis-ci.org/stream-utils/raw-body) | ||
Gets the entire buffer of a stream and validates its length against an expected length and maximum limit. | ||
Gets the entire buffer of a stream either as a `Buffer` or a string. | ||
Validates the stream's length against an expected length and maximum limit. | ||
Ideal for parsing request bodies. | ||
@@ -14,8 +15,9 @@ | ||
length: req.headers['content-length'], | ||
limit: '1mb' | ||
}, function (err, buffer) { | ||
limit: '1mb', | ||
encoding: 'utf8' | ||
}, function (err, string) { | ||
if (err) | ||
return next(err) | ||
req.rawBody = buffer | ||
req.text = string | ||
next() | ||
@@ -30,5 +32,6 @@ }) | ||
app.use(function* (next) { | ||
var buffer = yield getRawBody(this.req, { | ||
var string = yield getRawBody(this.req, { | ||
length: this.length, | ||
limit: '1mb' | ||
limit: '1mb', | ||
encoding: 'utf8' | ||
}) | ||
@@ -38,4 +41,8 @@ }) | ||
### Options | ||
### getRawBody(stream, [options], [callback]) | ||
Returns a thunk for yielding with generators. | ||
Options: | ||
- `length` - The length length of the stream. | ||
@@ -47,19 +54,25 @@ If the contents of the stream do not add up to this length, | ||
a `413` error code is returned. | ||
- `encoding` - The requested encoding. | ||
By default, a `Buffer` instance will be returned. | ||
Most likely, you want `utf8`. | ||
You can use any type of encoding supported by [StringDecoder](http://nodejs.org/api/string_decoder.html). | ||
You can also pass `true` which sets it to the default `utf8` | ||
### Strings | ||
`callback(err, res)`: | ||
This library only returns the raw buffer. | ||
If you want the string, | ||
you can do something like this: | ||
- `err` - the following attributes will be defined if applicable: | ||
```js | ||
getRawBody(req, function (err, buffer) { | ||
if (err) | ||
return next(err) | ||
- `limit` - the limit in bytes | ||
- `length` and `expected` - the expected length of the stream | ||
- `received` - the received bytes | ||
- `status` and `statusCode` - the corresponding status code for the error | ||
- `type` - either `entity.too.large`, `request.size.invalid`, or `stream.encoding.set` | ||
req.text = buffer.toString('utf8') | ||
next() | ||
}) | ||
``` | ||
- `res` - the result, either as a `String` if an encoding was set or a `Buffer` otherwise. | ||
If an error occurs, the stream will be paused, | ||
and you are responsible for correctly disposing the stream. | ||
For HTTP requests, no handling is required if you send a response. | ||
For streams that use file descriptors, you should `stream.destroy()` or `stream.close()` to prevent leaks. | ||
## License | ||
@@ -87,2 +100,2 @@ | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
THE SOFTWARE. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18796
8
502
97
7
1
2