Skip to content

Commit 6fe506f

Browse files
multicolaurefelipewmartins
authored andcommitted
Do not modify config.url when using a relative baseURL (resolves axios#1628) (axios#2391)
* Adding tests to show config.url mutation Because config.url is modified while processing the request when the baseURL is set, it is impossible to perform a retry with the provided config object. Ref axios#1628 * Fixing url combining without modifying config.url As config.url is not modified anymore during the request processing. The request can safely be retried after it failed with the provided config. resolves axios#1628
1 parent 98e4acd commit 6fe506f

7 files changed

Lines changed: 85 additions & 10 deletions

File tree

lib/adapters/http.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
var utils = require('./../utils');
44
var settle = require('./../core/settle');
5+
var buildFullPath = require('../core/buildFullPath');
56
var buildURL = require('./../helpers/buildURL');
67
var http = require('http');
78
var https = require('https');
@@ -64,7 +65,8 @@ module.exports = function httpAdapter(config) {
6465
}
6566

6667
// Parse url
67-
var parsed = url.parse(config.url);
68+
var fullPath = buildFullPath(config.baseURL, config.url);
69+
var parsed = url.parse(fullPath);
6870
var protocol = parsed.protocol || 'http:';
6971

7072
if (!auth && parsed.auth) {

lib/adapters/xhr.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var utils = require('./../utils');
44
var settle = require('./../core/settle');
55
var buildURL = require('./../helpers/buildURL');
6+
var buildFullPath = require('../core/buildFullPath');
67
var parseHeaders = require('./../helpers/parseHeaders');
78
var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
89
var createError = require('../core/createError');
@@ -25,7 +26,8 @@ module.exports = function xhrAdapter(config) {
2526
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
2627
}
2728

28-
request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true);
29+
var fullPath = buildFullPath(config.baseURL, config.url);
30+
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
2931

3032
// Set the request timeout in MS
3133
request.timeout = config.timeout;
@@ -100,7 +102,7 @@ module.exports = function xhrAdapter(config) {
100102
var cookies = require('./../helpers/cookies');
101103

102104
// Add xsrf header
103-
var xsrfValue = (config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName ?
105+
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
104106
cookies.read(config.xsrfCookieName) :
105107
undefined;
106108

lib/core/buildFullPath.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
var isAbsoluteURL = require('../helpers/isAbsoluteURL');
4+
var combineURLs = require('../helpers/combineURLs');
5+
6+
/**
7+
* Creates a new URL by combining the baseURL with the requestedURL,
8+
* only when the requestedURL is not already an absolute URL.
9+
* If the requestURL is absolute, this function returns the requestedURL untouched.
10+
*
11+
* @param {string} baseURL The base URL
12+
* @param {string} requestedURL Absolute or relative URL to combine
13+
* @returns {string} The combined full path
14+
*/
15+
module.exports = function buildFullPath(baseURL, requestedURL) {
16+
if (baseURL && !isAbsoluteURL(requestedURL)) {
17+
return combineURLs(baseURL, requestedURL);
18+
}
19+
return requestedURL;
20+
};

lib/core/dispatchRequest.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ var utils = require('./../utils');
44
var transformData = require('./transformData');
55
var isCancel = require('../cancel/isCancel');
66
var defaults = require('../defaults');
7-
var isAbsoluteURL = require('./../helpers/isAbsoluteURL');
8-
var combineURLs = require('./../helpers/combineURLs');
97

108
/**
119
* Throws a `Cancel` if cancellation has been requested.
@@ -25,11 +23,6 @@ function throwIfCancellationRequested(config) {
2523
module.exports = function dispatchRequest(config) {
2624
throwIfCancellationRequested(config);
2725

28-
// Support baseURL config
29-
if (config.baseURL && !isAbsoluteURL(config.url)) {
30-
config.url = combineURLs(config.baseURL, config.url);
31-
}
32-
3326
// Ensure headers exist
3427
config.headers = config.headers || {};
3528

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
var buildFullPath = require('../../../lib/core/buildFullPath');
2+
3+
describe('helpers::buildFullPath', function () {
4+
it('should combine URLs when the requestedURL is relative', function () {
5+
expect(buildFullPath('https://api.github.com', '/users')).toBe('https://api.github.com/users');
6+
});
7+
8+
it('should return the requestedURL when it is absolute', function () {
9+
expect(buildFullPath('https://api.github.com', 'https://api.example.com/users')).toBe('https://api.example.com/users');
10+
});
11+
12+
it('should not combine URLs when the baseURL is not configured', function () {
13+
expect(buildFullPath(undefined, '/users')).toBe('/users');
14+
});
15+
16+
it('should combine URLs when the baseURL and requestedURL are relative', function () {
17+
expect(buildFullPath('/api', '/users')).toBe('/api/users');
18+
});
19+
20+
});

test/specs/requests.spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,30 @@ describe('requests', function () {
245245
});
246246
});
247247

248+
it('should not modify the config url with relative baseURL', function (done) {
249+
var config;
250+
251+
axios.get('/foo', {
252+
baseURL: '/api'
253+
}).catch(function (error) {
254+
config = error.config;
255+
});
256+
257+
getAjaxRequest().then(function (request) {
258+
request.respondWith({
259+
status: 404,
260+
statusText: 'NOT FOUND',
261+
responseText: 'Resource not found'
262+
});
263+
264+
setTimeout(function () {
265+
expect(config.baseURL).toEqual('/api');
266+
expect(config.url).toEqual('/foo');
267+
done();
268+
}, 100);
269+
});
270+
});
271+
248272
it('should allow overriding Content-Type header case-insensitive', function (done) {
249273
var response;
250274
var contentType = 'application/vnd.myapp.type+json';

test/unit/adapters/http.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,20 @@ describe('supports http with nodejs', function () {
646646
});
647647
});
648648
});
649+
650+
it('should combine baseURL and url', function (done) {
651+
server = http.createServer(function (req, res) {
652+
res.end();
653+
}).listen(4444, function () {
654+
axios.get('/foo', {
655+
baseURL: 'http://localhost:4444/',
656+
}).then(function (res) {
657+
assert.equal(res.config.baseURL, 'http://localhost:4444/');
658+
assert.equal(res.config.url, '/foo');
659+
done();
660+
});
661+
});
662+
});
649663
});
650664

651665

0 commit comments

Comments
 (0)