diff --git a/.travis.yml b/.travis.yml index 9d4506dfb0..e12ba8d29c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,11 @@ +services: + - xvfb language: node_js node_js: - node email: on_failure: change on_success: never -before_script: - - "export DISPLAY=:99.0" - - "sh -e /etc/init.d/xvfb start" - - sleep 3 # give xvfb some time to start after_success: - npm run coveralls env: diff --git a/README.md b/README.md index 2533e8d73f..f17e2a5b5d 100755 --- a/README.md +++ b/README.md @@ -413,7 +413,7 @@ The response for a request contains the following information. // `request` is the request that generated this response // It is the last ClientRequest instance in node.js (in redirects) - // and an XMLHttpRequest instance the browser + // and an XMLHttpRequest instance in the browser request: {} } ``` @@ -500,7 +500,7 @@ axios.interceptors.response.use(function (response) { }); ``` -If you may need to remove an interceptor later you can. +If you need to remove an interceptor later you can. ```js const myInterceptor = axios.interceptors.request.use(function () {/*...*/}); diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 06169ff2cb..e7faa3c48f 100755 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -2,6 +2,7 @@ var utils = require('./../utils'); var settle = require('./../core/settle'); +var buildFullPath = require('../core/buildFullPath'); var buildURL = require('./../helpers/buildURL'); var http = require('http'); var https = require('https'); @@ -64,7 +65,8 @@ module.exports = function httpAdapter(config) { } // Parse url - var parsed = url.parse(config.url); + var fullPath = buildFullPath(config.baseURL, config.url); + var parsed = url.parse(fullPath); var protocol = parsed.protocol || 'http:'; if (!auth && parsed.auth) { diff --git a/lib/adapters/xhr.js b/lib/adapters/xhr.js index 8c98d114b6..519e3c3745 100644 --- a/lib/adapters/xhr.js +++ b/lib/adapters/xhr.js @@ -3,6 +3,7 @@ var utils = require('./../utils'); var settle = require('./../core/settle'); var buildURL = require('./../helpers/buildURL'); +var buildFullPath = require('../core/buildFullPath'); var parseHeaders = require('./../helpers/parseHeaders'); var isURLSameOrigin = require('./../helpers/isURLSameOrigin'); var createError = require('../core/createError'); @@ -25,7 +26,8 @@ module.exports = function xhrAdapter(config) { requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password); } - request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true); + var fullPath = buildFullPath(config.baseURL, config.url); + request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); // Set the request timeout in MS request.timeout = config.timeout; @@ -100,7 +102,7 @@ module.exports = function xhrAdapter(config) { var cookies = require('./../helpers/cookies'); // Add xsrf header - var xsrfValue = (config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName ? + var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ? cookies.read(config.xsrfCookieName) : undefined; diff --git a/lib/core/buildFullPath.js b/lib/core/buildFullPath.js new file mode 100644 index 0000000000..00b2b050a1 --- /dev/null +++ b/lib/core/buildFullPath.js @@ -0,0 +1,20 @@ +'use strict'; + +var isAbsoluteURL = require('../helpers/isAbsoluteURL'); +var combineURLs = require('../helpers/combineURLs'); + +/** + * Creates a new URL by combining the baseURL with the requestedURL, + * only when the requestedURL is not already an absolute URL. + * If the requestURL is absolute, this function returns the requestedURL untouched. + * + * @param {string} baseURL The base URL + * @param {string} requestedURL Absolute or relative URL to combine + * @returns {string} The combined full path + */ +module.exports = function buildFullPath(baseURL, requestedURL) { + if (baseURL && !isAbsoluteURL(requestedURL)) { + return combineURLs(baseURL, requestedURL); + } + return requestedURL; +}; diff --git a/lib/core/dispatchRequest.js b/lib/core/dispatchRequest.js index 9ea70f2287..b5111017d1 100644 --- a/lib/core/dispatchRequest.js +++ b/lib/core/dispatchRequest.js @@ -4,8 +4,6 @@ var utils = require('./../utils'); var transformData = require('./transformData'); var isCancel = require('../cancel/isCancel'); var defaults = require('../defaults'); -var isAbsoluteURL = require('./../helpers/isAbsoluteURL'); -var combineURLs = require('./../helpers/combineURLs'); /** * Throws a `Cancel` if cancellation has been requested. @@ -25,11 +23,6 @@ function throwIfCancellationRequested(config) { module.exports = function dispatchRequest(config) { throwIfCancellationRequested(config); - // Support baseURL config - if (config.baseURL && !isAbsoluteURL(config.url)) { - config.url = combineURLs(config.baseURL, config.url); - } - // Ensure headers exist config.headers = config.headers || {}; diff --git a/lib/core/mergeConfig.js b/lib/core/mergeConfig.js index 6097a3e587..bb5e8d5f7f 100644 --- a/lib/core/mergeConfig.js +++ b/lib/core/mergeConfig.js @@ -34,7 +34,7 @@ module.exports = function mergeConfig(config1, config2) { }); utils.forEach([ - 'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer', + 'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer', 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken', diff --git a/test/specs/core/buildFullPath.spec.js b/test/specs/core/buildFullPath.spec.js new file mode 100644 index 0000000000..e7a64d3263 --- /dev/null +++ b/test/specs/core/buildFullPath.spec.js @@ -0,0 +1,20 @@ +var buildFullPath = require('../../../lib/core/buildFullPath'); + +describe('helpers::buildFullPath', function () { + it('should combine URLs when the requestedURL is relative', function () { + expect(buildFullPath('https://api.github.com', '/users')).toBe('https://api.github.com/users'); + }); + + it('should return the requestedURL when it is absolute', function () { + expect(buildFullPath('https://api.github.com', 'https://api.example.com/users')).toBe('https://api.example.com/users'); + }); + + it('should not combine URLs when the baseURL is not configured', function () { + expect(buildFullPath(undefined, '/users')).toBe('/users'); + }); + + it('should combine URLs when the baseURL and requestedURL are relative', function () { + expect(buildFullPath('/api', '/users')).toBe('/api/users'); + }); + +}); diff --git a/test/specs/core/mergeConfig.spec.js b/test/specs/core/mergeConfig.spec.js index bf6d2098c0..c6564ae2bd 100644 --- a/test/specs/core/mergeConfig.spec.js +++ b/test/specs/core/mergeConfig.spec.js @@ -32,13 +32,11 @@ describe('core::mergeConfig', function() { it('should not inherit request options', function() { var localDefaults = { - url: '__sample url__', method: '__sample method__', params: '__sample params__', data: { foo: true } }; var merged = mergeConfig(localDefaults, {}); - expect(merged.url).toEqual(undefined); expect(merged.method).toEqual(undefined); expect(merged.params).toEqual(undefined); expect(merged.data).toEqual(undefined); diff --git a/test/specs/instance.spec.js b/test/specs/instance.spec.js index e97d5ee394..d709c3d28e 100644 --- a/test/specs/instance.spec.js +++ b/test/specs/instance.spec.js @@ -37,6 +37,19 @@ describe('instance', function () { }); }); + it('should make an http request with url instead of baseURL', function () { + var instance = axios.create({ + url: 'https://api.example.com' + }); + + instance('/foo'); + + getAjaxRequest().then(function (request) { + expect(request.url).toBe('/foo'); + done(); + }); + }); + it('should make an http request', function (done) { var instance = axios.create(); diff --git a/test/specs/requests.spec.js b/test/specs/requests.spec.js index 78df9f1d9c..e73eedc810 100644 --- a/test/specs/requests.spec.js +++ b/test/specs/requests.spec.js @@ -245,6 +245,30 @@ describe('requests', function () { }); }); + it('should not modify the config url with relative baseURL', function (done) { + var config; + + axios.get('/foo', { + baseURL: '/api' + }).catch(function (error) { + config = error.config; + }); + + getAjaxRequest().then(function (request) { + request.respondWith({ + status: 404, + statusText: 'NOT FOUND', + responseText: 'Resource not found' + }); + + setTimeout(function () { + expect(config.baseURL).toEqual('/api'); + expect(config.url).toEqual('/foo'); + done(); + }, 100); + }); + }); + it('should allow overriding Content-Type header case-insensitive', function (done) { var response; var contentType = 'application/vnd.myapp.type+json'; diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index f35c0e0707..6e9c57f94a 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -646,6 +646,20 @@ describe('supports http with nodejs', function () { }); }); }); + + it('should combine baseURL and url', function (done) { + server = http.createServer(function (req, res) { + res.end(); + }).listen(4444, function () { + axios.get('/foo', { + baseURL: 'http://localhost:4444/', + }).then(function (res) { + assert.equal(res.config.baseURL, 'http://localhost:4444/'); + assert.equal(res.config.url, '/foo'); + done(); + }); + }); + }); });