mirror of
https://github.com/tenrok/axios.git
synced 2026-06-17 19:21:29 +03:00
Added data URL support for node.js; (#4725)
* Added data URL support for node.js; Added missed data URL protocol for the browser environment; Optimized JSON parsing in the default response transformer; Refactored project structure; Added `cause` prop for AxiosError instance that refers to the original error if it was wrapped with `AxiosError.from` method; Added fromDataURI helper; Added test for handling data:url as an `arraybuffer|text|stream`; * Added throwing of 405 HTTP error if the method is not GET;
This commit is contained in:
+76
-28
@@ -15,10 +15,15 @@ var VERSION = require('./../env/data').version;
|
||||
var transitionalDefaults = require('../defaults/transitional');
|
||||
var AxiosError = require('../core/AxiosError');
|
||||
var CanceledError = require('../cancel/CanceledError');
|
||||
var platform = require('../platform');
|
||||
var fromDataURI = require('../helpers/fromDataURI');
|
||||
var stream = require('stream');
|
||||
|
||||
var isHttps = /https:?/;
|
||||
|
||||
var supportedProtocols = [ 'http:', 'https:', 'file:' ];
|
||||
var supportedProtocols = platform.protocols.map(function(protocol) {
|
||||
return protocol + ':';
|
||||
});
|
||||
|
||||
function dispatchBeforeRedirect(options) {
|
||||
if (options.beforeRedirects.proxy) {
|
||||
@@ -99,6 +104,62 @@ module.exports = function httpAdapter(config) {
|
||||
rejectPromise(value);
|
||||
};
|
||||
var data = config.data;
|
||||
var responseType = config.responseType;
|
||||
var responseEncoding = config.responseEncoding;
|
||||
var method = config.method.toUpperCase();
|
||||
|
||||
// Parse url
|
||||
var fullPath = buildFullPath(config.baseURL, config.url);
|
||||
var parsed = url.parse(fullPath);
|
||||
var protocol = parsed.protocol || supportedProtocols[0];
|
||||
|
||||
if (protocol === 'data:') {
|
||||
var convertedData;
|
||||
|
||||
if (method !== 'GET') {
|
||||
return settle(resolve, reject, {
|
||||
status: 405,
|
||||
statusText: 'method not allowed',
|
||||
headers: {},
|
||||
config: config
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
convertedData = fromDataURI(config.url, responseType === 'blob', {
|
||||
Blob: config.env && config.env.Blob
|
||||
});
|
||||
} catch (err) {
|
||||
throw AxiosError.from(err, AxiosError.ERR_BAD_REQUEST, config);
|
||||
}
|
||||
|
||||
if (responseType === 'text') {
|
||||
convertedData = convertedData.toString(responseEncoding);
|
||||
|
||||
if (!responseEncoding || responseEncoding === 'utf8') {
|
||||
data = utils.stripBOM(convertedData);
|
||||
}
|
||||
} else if (responseType === 'stream') {
|
||||
convertedData = stream.Readable.from(convertedData);
|
||||
}
|
||||
|
||||
return settle(resolve, reject, {
|
||||
data: convertedData,
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
headers: {},
|
||||
config: config
|
||||
});
|
||||
}
|
||||
|
||||
if (supportedProtocols.indexOf(protocol) === -1) {
|
||||
return reject(new AxiosError(
|
||||
'Unsupported protocol ' + protocol,
|
||||
AxiosError.ERR_BAD_REQUEST,
|
||||
config
|
||||
));
|
||||
}
|
||||
|
||||
var headers = config.headers;
|
||||
var headerNames = {};
|
||||
|
||||
@@ -159,19 +220,6 @@ module.exports = function httpAdapter(config) {
|
||||
auth = username + ':' + password;
|
||||
}
|
||||
|
||||
// Parse url
|
||||
var fullPath = buildFullPath(config.baseURL, config.url);
|
||||
var parsed = url.parse(fullPath);
|
||||
var protocol = parsed.protocol || supportedProtocols[0];
|
||||
|
||||
if (supportedProtocols.indexOf(protocol) === -1) {
|
||||
return reject(new AxiosError(
|
||||
'Unsupported protocol ' + protocol,
|
||||
AxiosError.ERR_BAD_REQUEST,
|
||||
config
|
||||
));
|
||||
}
|
||||
|
||||
if (!auth && parsed.auth) {
|
||||
var urlAuth = parsed.auth.split(':');
|
||||
var urlUsername = urlAuth[0] || '';
|
||||
@@ -195,7 +243,7 @@ module.exports = function httpAdapter(config) {
|
||||
|
||||
var options = {
|
||||
path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''),
|
||||
method: config.method.toUpperCase(),
|
||||
method: method,
|
||||
headers: headers,
|
||||
agents: { http: config.httpAgent, https: config.httpsAgent },
|
||||
auth: auth,
|
||||
@@ -242,7 +290,7 @@ module.exports = function httpAdapter(config) {
|
||||
if (req.aborted) return;
|
||||
|
||||
// uncompress the response body transparently if required
|
||||
var stream = res;
|
||||
var responseStream = res;
|
||||
|
||||
// return the last request in case of redirects
|
||||
var lastRequest = res.req || req;
|
||||
@@ -261,7 +309,7 @@ module.exports = function httpAdapter(config) {
|
||||
case 'compress':
|
||||
case 'deflate':
|
||||
// add the unzipper to the body stream processing pipeline
|
||||
stream = stream.pipe(zlib.createUnzip());
|
||||
responseStream = responseStream.pipe(zlib.createUnzip());
|
||||
|
||||
// remove the content-encoding in order to not confuse downstream operations
|
||||
delete res.headers['content-encoding'];
|
||||
@@ -277,13 +325,13 @@ module.exports = function httpAdapter(config) {
|
||||
request: lastRequest
|
||||
};
|
||||
|
||||
if (config.responseType === 'stream') {
|
||||
response.data = stream;
|
||||
if (responseType === 'stream') {
|
||||
response.data = responseStream;
|
||||
settle(resolve, reject, response);
|
||||
} else {
|
||||
var responseBuffer = [];
|
||||
var totalResponseBytes = 0;
|
||||
stream.on('data', function handleStreamData(chunk) {
|
||||
responseStream.on('data', function handleStreamData(chunk) {
|
||||
responseBuffer.push(chunk);
|
||||
totalResponseBytes += chunk.length;
|
||||
|
||||
@@ -291,17 +339,17 @@ module.exports = function httpAdapter(config) {
|
||||
if (config.maxContentLength > -1 && totalResponseBytes > config.maxContentLength) {
|
||||
// stream.destroy() emit aborted event before calling reject() on Node.js v16
|
||||
rejected = true;
|
||||
stream.destroy();
|
||||
responseStream.destroy();
|
||||
reject(new AxiosError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
|
||||
AxiosError.ERR_BAD_RESPONSE, config, lastRequest));
|
||||
}
|
||||
});
|
||||
|
||||
stream.on('aborted', function handlerStreamAborted() {
|
||||
responseStream.on('aborted', function handlerStreamAborted() {
|
||||
if (rejected) {
|
||||
return;
|
||||
}
|
||||
stream.destroy();
|
||||
responseStream.destroy();
|
||||
reject(new AxiosError(
|
||||
'maxContentLength size of ' + config.maxContentLength + ' exceeded',
|
||||
AxiosError.ERR_BAD_RESPONSE,
|
||||
@@ -310,17 +358,17 @@ module.exports = function httpAdapter(config) {
|
||||
));
|
||||
});
|
||||
|
||||
stream.on('error', function handleStreamError(err) {
|
||||
responseStream.on('error', function handleStreamError(err) {
|
||||
if (req.aborted) return;
|
||||
reject(AxiosError.from(err, null, config, lastRequest));
|
||||
});
|
||||
|
||||
stream.on('end', function handleStreamEnd() {
|
||||
responseStream.on('end', function handleStreamEnd() {
|
||||
try {
|
||||
var responseData = responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
|
||||
if (config.responseType !== 'arraybuffer') {
|
||||
responseData = responseData.toString(config.responseEncoding);
|
||||
if (!config.responseEncoding || config.responseEncoding === 'utf8') {
|
||||
if (responseType !== 'arraybuffer') {
|
||||
responseData = responseData.toString(responseEncoding);
|
||||
if (!responseEncoding || responseEncoding === 'utf8') {
|
||||
responseData = utils.stripBOM(responseData);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@ var transitionalDefaults = require('../defaults/transitional');
|
||||
var AxiosError = require('../core/AxiosError');
|
||||
var CanceledError = require('../cancel/CanceledError');
|
||||
var parseProtocol = require('../helpers/parseProtocol');
|
||||
var platform = require('../platform');
|
||||
|
||||
module.exports = function xhrAdapter(config) {
|
||||
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
||||
@@ -210,7 +211,7 @@ module.exports = function xhrAdapter(config) {
|
||||
|
||||
var protocol = parseProtocol(fullPath);
|
||||
|
||||
if (protocol && [ 'http', 'https', 'file', 'blob' ].indexOf(protocol) === -1) {
|
||||
if (protocol && platform.protocols.indexOf(protocol) === -1) {
|
||||
reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config));
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user