diff --git a/CHANGELOG.md b/CHANGELOG.md index 850618174..1ed4603c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ + +## [32.0.1](https://github.com/ipfs/js-ipfs-http-client/compare/v32.0.0...v32.0.1) (2019-05-21) + + +### Bug Fixes + +* error reporting for non-JSON responses ([#1016](https://github.com/ipfs/js-ipfs-http-client/issues/1016)) ([4251c88](https://github.com/ipfs/js-ipfs-http-client/commit/4251c88)), closes [#912](https://github.com/ipfs/js-ipfs-http-client/issues/912) [#1000](https://github.com/ipfs/js-ipfs-http-client/issues/1000) [#1001](https://github.com/ipfs/js-ipfs-http-client/issues/1001) +* send trickle param to trigger trickle dag builder ([#1015](https://github.com/ipfs/js-ipfs-http-client/issues/1015)) ([a28b009](https://github.com/ipfs/js-ipfs-http-client/commit/a28b009)) + + + # [32.0.0](https://github.com/ipfs/js-ipfs-http-client/compare/v31.1.0...v32.0.0) (2019-05-21) diff --git a/package.json b/package.json index 409c0c7ec..50f63ae52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipfs-http-client", - "version": "32.0.0", + "version": "32.0.1", "description": "A client library for the IPFS HTTP API", "leadMaintainer": "Alan Shaw ", "main": "src/index.js", diff --git a/src/utils/send-files-stream.js b/src/utils/send-files-stream.js index c2450d39e..4c91798fc 100644 --- a/src/utils/send-files-stream.js +++ b/src/utils/send-files-stream.js @@ -81,6 +81,10 @@ module.exports = (send, path) => { qs['wrap-with-directory'] = propOrProp(options, 'wrap-with-directory', 'wrapWithDirectory') qs.hash = propOrProp(options, 'hash', 'hashAlg') + if (options.strategy === 'trickle' || options.trickle) { + qs['trickle'] = 'true' + } + const args = { path: path, qs: qs, diff --git a/src/utils/send-request.js b/src/utils/send-request.js index 219327adf..1645969f2 100644 --- a/src/utils/send-request.js +++ b/src/utils/send-request.js @@ -13,8 +13,26 @@ const log = require('debug')('ipfs-http-client:request') // -- Internal +function hasJSONHeaders (res) { + return res.headers['content-type'] && + res.headers['content-type'].indexOf('application/json') === 0 +} + function parseError (res, cb) { const error = new Error(`Server responded with ${res.statusCode}`) + error.statusCode = res.statusCode + + if (!hasJSONHeaders(res)) { + return streamToValue(res, (err, data) => { // eslint-disable-line handle-callback-err + // the `err` here refers to errors in stream processing, which + // we ignore here, since we already have a valid `error` response + // from the server above that we have to report to the caller. + if (data && data.length) { + error.message = data.toString() + } + cb(error) + }) + } streamToJsonValue(res, (err, payload) => { if (err) { @@ -34,8 +52,7 @@ function onRes (buffer, cb) { return (res) => { const stream = Boolean(res.headers['x-stream-output']) const chunkedObjects = Boolean(res.headers['x-chunked-output']) - const isJson = res.headers['content-type'] && - res.headers['content-type'].indexOf('application/json') === 0 + const isJson = hasJSONHeaders(res) if (res.req) { log(res.req.method, `${res.req.getHeaders().host}${res.req.path}`, res.statusCode, res.statusMessage) diff --git a/src/utils/stream-to-json-value.js b/src/utils/stream-to-json-value.js index e42de2fc6..2ae83e50d 100644 --- a/src/utils/stream-to-json-value.js +++ b/src/utils/stream-to-json-value.js @@ -24,7 +24,7 @@ function streamToJsonValue (res, cb) { try { res = JSON.parse(data) } catch (err) { - return cb(err) + return cb(new Error(`Invalid JSON: ${data}`)) } cb(null, res) diff --git a/test/request-api.spec.js b/test/request-api.spec.js index 02f342e53..a9b2fcf2e 100644 --- a/test/request-api.spec.js +++ b/test/request-api.spec.js @@ -65,3 +65,77 @@ describe('trailer headers', () => { }) }) }) + +describe('error handling', () => { + it('should handle plain text error response', function (done) { + if (!isNode) return this.skip() + + const server = require('http').createServer((req, res) => { + // Consume the entire request, before responding. + req.on('data', () => {}) + req.on('end', () => { + // Write a text/plain response with a 403 (forbidden) status + res.writeHead(403, { 'Content-Type': 'text/plain' }) + res.write('ipfs method not allowed') + res.end() + }) + }) + + server.listen(6001, () => { + ipfsClient('/ip4/127.0.0.1/tcp/6001').config.replace('test/fixtures/r-config.json', (err) => { + expect(err).to.exist() + expect(err.statusCode).to.equal(403) + expect(err.message).to.equal('ipfs method not allowed') + server.close(done) + }) + }) + }) + + it('should handle JSON error response', function (done) { + if (!isNode) return this.skip() + + const server = require('http').createServer((req, res) => { + // Consume the entire request, before responding. + req.on('data', () => {}) + req.on('end', () => { + // Write a application/json response with a 400 (bad request) header + res.writeHead(400, { 'Content-Type': 'application/json' }) + res.write(JSON.stringify({ Message: 'client error', Code: 1 })) + res.end() + }) + }) + + server.listen(6001, () => { + ipfsClient('/ip4/127.0.0.1/tcp/6001').config.replace('test/fixtures/r-config.json', (err) => { + expect(err).to.exist() + expect(err.statusCode).to.equal(400) + expect(err.message).to.equal('client error') + expect(err.code).to.equal(1) + server.close(done) + }) + }) + }) + + it('should handle JSON error response with invalid JSON', function (done) { + if (!isNode) return this.skip() + + const server = require('http').createServer((req, res) => { + // Consume the entire request, before responding. + req.on('data', () => {}) + req.on('end', () => { + // Write a application/json response with a 400 (bad request) header + res.writeHead(400, { 'Content-Type': 'application/json' }) + res.write('{ Message: ') + res.end() + }) + }) + + server.listen(6001, () => { + ipfsClient('/ip4/127.0.0.1/tcp/6001').config.replace('test/fixtures/r-config.json', (err) => { + expect(err).to.exist() + expect(err.message).to.include('Invalid JSON') + server.close(done) + }) + }) + }) +})