probe-image-size
Advanced tools
Comparing version 2.2.0 to 3.0.0
@@ -0,1 +1,16 @@ | ||
3.0.0 / 2016-12-02 | ||
------------------ | ||
- Rewrite internals to `Promise`. | ||
- Separate options from url for http probe (old signature still supported | ||
for compatibility). | ||
- `err.status` -> `err.statusCode` | ||
- remove `{ rejectUnauthorized: false }` from defaults. | ||
- User-Agent string update. | ||
- Replaced `request` dependency with `got` (read options description in doc). | ||
- Retry requests on network fail. | ||
- Switched from `readable-stream` to native `stream` (node 4+ has normal Stream3). | ||
- Proper class for errors. | ||
2.2.0 / 2016-10-26 | ||
@@ -2,0 +17,0 @@ ------------------ |
89
http.js
'use strict'; | ||
var once = require('./lib/common').once; | ||
var error = require('./lib/common').error; | ||
var request = require('request').defaults({ | ||
var ProbeError = require('./lib/common').ProbeError; | ||
var got = require('got'); | ||
var merge = require('deepmerge'); | ||
var pkg = require('./package.json'); | ||
var probeStream = require('./stream'); | ||
var defaultAgent = pkg.name + '/' + pkg.version + '(+https://github.com/nodeca/probe-image-size)'; | ||
var defaults = { | ||
timeout: 30000, | ||
maxRedirects: 2, | ||
rejectUnauthorized: false, | ||
retries: 1, | ||
headers: { | ||
'User-Agent': 'Image size prober https://github.com/nodeca/probe-image-size' | ||
'User-Agent': defaultAgent | ||
} | ||
}); | ||
}; | ||
var probeStream = require('./stream'); | ||
var P; | ||
module.exports = function probeHttp(options, _callback) { | ||
var callback = once(_callback); | ||
var req; | ||
module.exports = function probeHttp(src, options) { | ||
// lazy Promise init | ||
P = P || require('any-promise'); | ||
try { | ||
req = request(options); | ||
} catch (err) { | ||
callback(err); | ||
return; | ||
} | ||
return new P(function (resolve, reject) { | ||
var request, length, finalUrl; | ||
req.on('response', function (res) { | ||
if (res.statusCode === 200) { | ||
probeStream(res, function (err, result) { | ||
req.abort(); | ||
var stream = got.stream(src, merge.all([ {}, defaults, options ], { clone: true })); | ||
if (result) { | ||
var length = res.headers['content-length']; | ||
stream.on('request', function (req) { | ||
request = req; | ||
}); | ||
stream.on('response', function (res) { | ||
if (res.statusCode === 200) { | ||
var len = res.headers['content-length']; | ||
if (length && length.match(/^\d+$/)) { | ||
result.length = +length; | ||
} | ||
if (len && len.match(/^\d+$/)) length = +len; | ||
finalUrl = res.url; | ||
result.url = res.request.uri.href; | ||
} | ||
return; | ||
} | ||
callback(err, result); | ||
reject(new ProbeError('bad status code: ' + res.statusCode, null, res.statusCode)); | ||
}); | ||
stream.on('error', function (err) { | ||
if (err.statusCode) { | ||
reject(new ProbeError('bad status code: ' + err.statusCode, null, err.statusCode)); | ||
return; | ||
} | ||
reject(err); | ||
}); | ||
probeStream(stream) | ||
.then(function (result) { | ||
if (length) result.length = length; | ||
result.url = finalUrl; | ||
resolve(result); | ||
}) | ||
.catch(reject) | ||
.then(function () { | ||
/* istanbul ignore else */ | ||
if (request) request.abort(); | ||
}); | ||
} else { | ||
var err = error('bad status code: ' + res.statusCode, null, res.statusCode); | ||
req.abort(); | ||
callback(err); | ||
} | ||
}); | ||
req.on('error', function (err) { callback(err); }); | ||
}; | ||
@@ -56,0 +71,0 @@ |
51
index.js
@@ -6,35 +6,48 @@ 'use strict'; | ||
var probeHttp = require('./http'); | ||
var nextTick = require('next-tick'); | ||
var merge = require('deepmerge'); | ||
// Cache for promise implementation | ||
var P; | ||
/* eslint-disable consistent-return */ | ||
module.exports = function get_image_size(src, callback) { | ||
var prober; | ||
module.exports = function get_image_size(src, options, callback) { | ||
if (typeof src.on === 'function' && typeof src.emit === 'function') { | ||
// looks like an EventEmitter, treating it as a stream | ||
prober = probeStream; | ||
} else { | ||
prober = probeHttp; | ||
callback = options; | ||
if (!callback) return probeStream(src); | ||
probeStream(src) | ||
.then(function (size) { nextTick(callback.bind(null, null, size)); }) | ||
.catch(function (err) { nextTick(callback.bind(null, err)); }); | ||
return; | ||
} | ||
if (!callback) { | ||
P = P || require('any-promise'); | ||
// HTTP (not stream) | ||
if (typeof src === 'string') { | ||
// `probe(string [, options, callback])` | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
options = options || {}; | ||
return new P(function (resolve, reject) { | ||
prober(src, function (err, data) { | ||
if (err) reject(err); | ||
else resolve(data); | ||
}); | ||
}); | ||
} else { | ||
// Legacy style, `probe(object [, callback])` | ||
callback = options; | ||
options = merge({}, src, { clone: true }); | ||
src = options.url; | ||
delete options.url; | ||
} | ||
prober(src, callback); | ||
if (!callback) return probeHttp(src, options); | ||
probeHttp(src, options) | ||
.then(function (size) { nextTick(callback.bind(null, null, size)); }) | ||
.catch(function (err) { nextTick(callback.bind(null, err)); }); | ||
}; | ||
module.exports.parsers = require('./lib/parsers_stream'); | ||
module.exports.sync = require('./sync'); | ||
module.exports.Error = require('./lib/common').ProbeError; |
'use strict'; | ||
var Transform = require('readable-stream').Transform; | ||
var Transform = require('stream').Transform; | ||
var streamParser = require('stream-parser'); | ||
@@ -19,13 +19,3 @@ var inherits = require('util').inherits; | ||
exports.once = function (fn) { | ||
var called = false; | ||
return function () { | ||
if (!called) { | ||
called = true; | ||
fn.apply(this, arguments); | ||
} | ||
}; | ||
}; | ||
exports.sliceEq = function (src, start, dest) { | ||
@@ -78,9 +68,18 @@ for (var i = start, j = 0; j < dest.length;) { | ||
exports.error = function (message, code, status) { | ||
var err = new Error(message); | ||
if (code) err.code = code; | ||
if (status) err.status = status; | ||
function ProbeError(message, code, statusCode) { | ||
Error.call(this); | ||
Error.captureStackTrace(this, this.constructor); | ||
return err; | ||
}; | ||
this.name = this.constructor.name; | ||
this.message = message; | ||
if (code) this.code = code; | ||
if (statusCode) this.statusCode = statusCode; | ||
} | ||
// Inherit from Error | ||
require('inherits')(ProbeError, Error); | ||
exports.ProbeError = ProbeError; |
@@ -35,5 +35,3 @@ 'use strict'; | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -36,5 +36,3 @@ 'use strict'; | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -102,5 +102,3 @@ 'use strict'; | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -43,5 +43,3 @@ 'use strict'; | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -39,5 +39,3 @@ 'use strict'; | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -5,3 +5,3 @@ 'use strict'; | ||
var Transform = require('readable-stream').Transform; | ||
var Transform = require('stream').Transform; | ||
@@ -18,3 +18,3 @@ var STATE_IDENTIFY = 0; // look for '<' | ||
var SVG_HEIGHT_RE = /\bheight="([^%]+?)"|\bheight='([^%]+?)'/; | ||
var SVG_VIEWBOX_RE = /\bviewbox="(.+?)"|\bviewbox='(.+?)'/; | ||
var SVG_VIEWBOX_RE = /\bview[bB]ox="(.+?)"|\bview[bB]ox='(.+?)'/; | ||
var SVG_UNITS_RE = /in$|mm$|cm$|pt$|pc$|px$|em$|ex$/; | ||
@@ -189,5 +189,3 @@ | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -113,5 +113,3 @@ 'use strict'; | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -20,2 +20,3 @@ 'use strict'; | ||
// bad code block signature | ||
parser.push(null); | ||
return; | ||
@@ -44,2 +45,3 @@ } | ||
// bad code block signature | ||
parser.push(null); | ||
return; | ||
@@ -103,5 +105,3 @@ } | ||
parser.on('finish', function () { parser.push(null); }); | ||
return parser; | ||
}; |
@@ -27,3 +27,3 @@ 'use strict'; | ||
var SVG_HEIGHT_RE = /\bheight="([^%]+?)"|\bheight='([^%]+?)'/; | ||
var SVG_VIEWBOX_RE = /\bviewbox="(.+?)"|\bviewbox='(.+?)'/; | ||
var SVG_VIEWBOX_RE = /\bview[bB]ox="(.+?)"|\bview[bB]ox='(.+?)'/; | ||
var SVG_UNITS_RE = /in$|mm$|cm$|pt$|pc$|px$|em$|ex$/; | ||
@@ -30,0 +30,0 @@ |
{ | ||
"name": "probe-image-size", | ||
"version": "2.2.0", | ||
"version": "3.0.0", | ||
"description": "Get image size without full download (JPG, GIF, PNG, WebP, BMP, TIFF, PSD)", | ||
@@ -35,4 +35,6 @@ "keywords": [ | ||
"any-promise": "^1.3.0", | ||
"readable-stream": "^2.1.4", | ||
"request": "^2.60.0", | ||
"deepmerge": "^1.3.0", | ||
"got": "^6.6.3", | ||
"inherits": "^2.0.3", | ||
"next-tick": "^1.0.0", | ||
"stream-parser": "~0.3.1" | ||
@@ -42,7 +44,7 @@ }, | ||
"coveralls": "^2.11.9", | ||
"eslint": "~3.0.1", | ||
"eslint": "^3.11.1", | ||
"from2": "^2.1", | ||
"istanbul": "^0.4.1", | ||
"mocha": "^2.2.5" | ||
"mocha": "^3.2.0" | ||
} | ||
} |
@@ -34,3 +34,3 @@ probe-image-size | ||
// | ||
probe('http://example.com/image.jpg', function (err, result) { | ||
probe('http://example.com/image.jpg').then(result => { | ||
console.log(result); // => | ||
@@ -52,9 +52,9 @@ /* | ||
// | ||
probe({ url: 'http://example.com/image.jpg', timeout: 5000 }, function (err, result) { | ||
probe('http://example.com/image.jpg', { timeout: 5000 }).then(function (result) { | ||
console.log(result); | ||
}); | ||
// With Promise | ||
// With callback | ||
// | ||
probe('http://example.com/image.jpg').then(function (result) { | ||
probe('http://example.com/image.jpg', function (err, result) { | ||
console.log(result); | ||
@@ -67,3 +67,3 @@ }); | ||
probe(input, function (err, result) { | ||
probe(input).then(result => { | ||
console.log(result); | ||
@@ -87,3 +87,3 @@ | ||
### probe(src [, callback(err, result)]) | ||
### probe(src [, options, callback]) -> Promise | ||
@@ -93,8 +93,9 @@ `src` can be of this types: | ||
- __String__ - URL to fetch | ||
- __Object__ - options for [request](https://github.com/request/request), | ||
defaults are `{ timeout: 5000, maxRedirects: 2 }` | ||
- __Stream__ - readable stream | ||
`result` contains: | ||
`options` - HTTP only. See [`got` documentation](https://github.com/sindresorhus/got). | ||
Defaults changed to `{ retries: 1, timeout: 30000 }` | ||
`result` (Promise) contains: | ||
```js | ||
@@ -113,10 +114,10 @@ { | ||
`err` is an error, which is extended with: | ||
Returned errors can be extended with 2 fields: | ||
- `code` - equals to `ECONTENT` if the library failed to parse the file; | ||
- `status` - equals to a HTTP status code if it receives a non-200 response. | ||
- `code` - equals to `ECONTENT` if the library failed to parse the file; | ||
- `status` - equals to a HTTP status code if it receives a non-200 response. | ||
If callback not provided, `Promise` will be returned. | ||
If callback (legacy node style) provided, `Promise` will not be returned. | ||
__Note.__ If you use `Stream` as source, it's your responsibility to close that | ||
__Note 1.__ If you use `Stream` as source, it's your responsibility to close that | ||
stream in callback. In other case you can get memory leak, because stream will | ||
@@ -126,3 +127,7 @@ be left in paused state. With http requests that's not a problem - everything | ||
__Note 2.__ We still support legacy v2.x signature for http probe (`src` is | ||
Object as described in [request](https://github.com/request/request)). But it | ||
will be deprecated in next versions. | ||
### sync.probe(src) -> result|null | ||
@@ -129,0 +134,0 @@ |
'use strict'; | ||
var once = require('./lib/common').once; | ||
var error = require('./lib/common').error; | ||
var parsers = require('./lib/parsers_stream'); | ||
var ProbeError = require('./lib/common').ProbeError; | ||
var parsers = require('./lib/parsers_stream'); | ||
var PassThrough = require('stream').PassThrough; | ||
var P; | ||
function unrecognizedFormat() { | ||
return error('unrecognized file format', 'ECONTENT'); | ||
} | ||
module.exports = function probeStream(stream) { | ||
// lazy Promise init | ||
P = P || require('any-promise'); | ||
module.exports = function probeStream(stream, _callback) { | ||
var callback = once(function () { | ||
// We should postpone callback to allow all piped parsers accept .write(). | ||
// In other case, if stream is closed from callback that can cause | ||
// exceptions like "write after end". | ||
var args = Array.prototype.slice.call(arguments); | ||
var proxy = new PassThrough(); | ||
var cnt = 0; // count of working parsers | ||
process.nextTick(function () { | ||
_callback.apply(null, args); | ||
}); | ||
}); | ||
var result = new P(function (resolve, reject) { | ||
stream.on('error', reject); | ||
proxy.on('error', reject); | ||
var pStreams = []; | ||
function nope() {} | ||
// prevent "possible EventEmitter memory leak" warnings | ||
stream.setMaxListeners(0); | ||
function cleanup(strm) { | ||
var i; | ||
if (strm) { | ||
stream.unpipe(strm); | ||
strm.end(); | ||
i = pStreams.indexOf(strm); | ||
if (i >= 0) pStreams.splice(i, 1); | ||
return; | ||
function parserEnd() { | ||
proxy.unpipe(this); | ||
this.removeAllListeners(); | ||
cnt--; | ||
// if all parsers finished without success -> fail. | ||
if (!cnt) reject(new ProbeError('unrecognized file format', 'ECONTENT')); | ||
} | ||
for (i = 0; i < pStreams.length; i++) { | ||
stream.unpipe(pStreams[i]); | ||
pStreams[i].end(); | ||
} | ||
pStreams.length = 0; | ||
} | ||
Object.keys(parsers).forEach(function (type) { | ||
var pStream = parsers[type](); | ||
stream.on('error', function (err) { cleanup(); callback(err); }); | ||
cnt++; | ||
Object.keys(parsers).forEach(function (type) { | ||
var pStream = parsers[type](); | ||
pStream.on('data', function (result) { | ||
callback(null, result); | ||
cleanup(); | ||
}); | ||
pStream.on('error', function () { | ||
pStream.once('data', resolve); | ||
pStream.once('end', parserEnd); | ||
// silently ignore errors because user does not need to know | ||
// that something wrong is happening here | ||
pStream.on('error', nope); | ||
proxy.pipe(pStream); | ||
}); | ||
}); | ||
pStream.on('end', function () { | ||
cleanup(pStream); | ||
function cleanup() { | ||
stream.unpipe(proxy); | ||
proxy.end(); | ||
} | ||
if (pStreams.length === 0) { | ||
cleanup(); | ||
callback(unrecognizedFormat()); | ||
} | ||
}); | ||
result.then(cleanup).catch(cleanup); | ||
stream.pipe(pStream); | ||
stream.pipe(proxy); | ||
pStreams.push(pStream); | ||
}); | ||
return result; | ||
}; | ||
@@ -78,0 +58,0 @@ |
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
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
41690
148
6
1087
+ Addeddeepmerge@^1.3.0
+ Addedgot@^6.6.3
+ Addedinherits@^2.0.3
+ Addednext-tick@^1.0.0
+ Addedcapture-stack-trace@1.0.2(transitive)
+ Addedcreate-error-class@3.0.2(transitive)
+ Addeddeepmerge@1.5.2(transitive)
+ Addedduplexer3@0.1.5(transitive)
+ Addedget-stream@3.0.0(transitive)
+ Addedgot@6.7.1(transitive)
+ Addedis-redirect@1.0.0(transitive)
+ Addedis-retry-allowed@1.2.0(transitive)
+ Addedis-stream@1.1.0(transitive)
+ Addedlowercase-keys@1.0.1(transitive)
+ Addednext-tick@1.1.0(transitive)
+ Addedprepend-http@1.0.4(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedtimed-out@4.0.1(transitive)
+ Addedunzip-response@2.0.1(transitive)
+ Addedurl-parse-lax@1.0.0(transitive)
- Removedreadable-stream@^2.1.4
- Removedrequest@^2.60.0
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.21.0.3(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedprocess-nextick-args@2.0.1(transitive)
- Removedpsl@1.15.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedreadable-stream@2.3.8(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedstring_decoder@1.1.1(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removeduri-js@4.4.1(transitive)
- Removedutil-deprecate@1.0.2(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)