Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

feat($http): add xhr statusText to completeRequest callback #2665

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions src/ng/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ function $HttpProvider() {
* - **status** – `{number}` – HTTP status code of the response.
* - **headers** – `{function([headerName])}` – Header getter function.
* - **config** – `{Object}` – The configuration object that was used to generate the request.
* - **statusText** – `{string}` – HTTP status text of the response.
*
* @property {Array.<Object>} pendingRequests Array of config objects for currently pending
* requests. This is primarily meant to be used for debugging purposes.
Expand Down Expand Up @@ -936,9 +937,9 @@ function $HttpProvider() {
} else {
// serving from cache
if (isArray(cachedResp)) {
resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]), cachedResp[3]);
} else {
resolvePromise(cachedResp, 200, {});
resolvePromise(cachedResp, 200, {}, 'OK');
}
}
} else {
Expand All @@ -962,33 +963,34 @@ function $HttpProvider() {
* - resolves the raw $http promise
* - calls $apply
*/
function done(status, response, headersString) {
function done(status, response, headersString, statusText) {
if (cache) {
if (isSuccess(status)) {
cache.put(url, [status, response, parseHeaders(headersString)]);
cache.put(url, [status, response, parseHeaders(headersString), statusText]);
} else {
// remove promise from the cache
cache.remove(url);
}
}

resolvePromise(response, status, headersString);
resolvePromise(response, status, headersString, statusText);
if (!$rootScope.$$phase) $rootScope.$apply();
}


/**
* Resolves the raw $http promise.
*/
function resolvePromise(response, status, headers) {
function resolvePromise(response, status, headers, statusText) {
// normalize internal statuses to 0
status = Math.max(status, 0);

(isSuccess(status) ? deferred.resolve : deferred.reject)({
data: response,
status: status,
headers: headersGetter(headers),
config: config
config: config,
statusText : statusText
});
}

Expand Down
23 changes: 18 additions & 5 deletions src/ng/httpBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
completeRequest(callback,
status || xhr.status,
(xhr.responseType ? xhr.response : xhr.responseText),
responseHeaders);
responseHeaders,
xhr.statusText || '');
}
};

Expand Down Expand Up @@ -119,7 +120,7 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
xhr && xhr.abort();
}

function completeRequest(callback, status, response, headersString) {
function completeRequest(callback, status, response, headersString, statusText) {
// URL_MATCH is defined in src/service/location.js
var protocol = (url.match(SERVER_MATCH) || ['', locationProtocol])[1];

Expand All @@ -128,12 +129,24 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
jsonpDone = xhr = null;

// fix status code for file protocol (it's always 0)
status = (protocol == 'file') ? (response ? 200 : 404) : status;
if (protocol == 'file') {
if (response) {
status = 200;
statusText = 'OK';
}
else {
status = 404;
statusText = 'Not Found';
}
}

// normalize IE bug (http://bugs.jquery.com/ticket/1450)
status = status == 1223 ? 204 : status;
if (status == 1223) {
status = 204;
statusText = 'No Content';
}

callback(status, response, headersString);
callback(status, response, headersString, statusText);
$browser.$$completeOutstandingRequest(noop);
}
};
Expand Down
32 changes: 16 additions & 16 deletions src/ngMock/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -952,12 +952,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
responses = [],
responsesPush = angular.bind(responses, responses.push);

function createResponse(status, data, headers) {
function createResponse(status, data, headers, statusText) {
if (angular.isFunction(status)) return status;

return function() {
return angular.isNumber(status)
? [status, data, headers]
? [status, data, headers, statusText]
: [200, status, data];
};
}
Expand All @@ -982,7 +982,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
function handleResponse() {
var response = wrapped.response(method, url, data, headers);
xhr.$$respHeaders = response[2];
callback(response[0], response[1], xhr.getAllResponseHeaders());
callback(response[0], response[1], xhr.getAllResponseHeaders(), response[3] || '');
}

function handleTimeout() {
Expand Down Expand Up @@ -1047,16 +1047,16 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*
* - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
* - respond – `{function([status,] data[, headers, statusText])|function(function(method, url, data, headers)}`
* – The respond method takes a set of static data to be returned or a function that can return
* an array containing response status (number), response data (string) and response headers
* (Object).
* an array containing response status (number), response data (string), response headers (Object), and the
* text for the status (string).
*/
$httpBackend.when = function(method, url, data, headers) {
var definition = new MockHttpExpectation(method, url, data, headers),
chain = {
respond: function(status, data, headers) {
definition.response = createResponse(status, data, headers);
respond: function(status, data, headers, statusText) {
definition.response = createResponse(status, data, headers, statusText);
}
};

Expand Down Expand Up @@ -1166,17 +1166,17 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @returns {requestHandler} Returns an object with `respond` method that control how a matched
* request is handled.
*
* - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
* - respond – `{function([status,] data[, headers, statusText])|function(function(method, url, data, headers)}`
* – The respond method takes a set of static data to be returned or a function that can return
* an array containing response status (number), response data (string) and response headers
* (Object).
* an array containing response status (number), response data (string), response headers (Object), and the
* text for the status (string).
*/
$httpBackend.expect = function(method, url, data, headers) {
var expectation = new MockHttpExpectation(method, url, data, headers);
expectations.push(expectation);
return {
respond: function(status, data, headers) {
expectation.response = createResponse(status, data, headers);
respond: function (status, data, headers, statusText) {
expectation.response = createResponse(status, data, headers, statusText);
}
};
};
Expand Down Expand Up @@ -1622,10 +1622,10 @@ angular.module('ngMockE2E', ['ng']).config(function($provide) {
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
* control how a matched request is handled.
*
* - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
* - respond – `{function([status,] data[, headers, statusText])|function(function(method, url, data, headers)}`
* – The respond method takes a set of static data to be returned or a function that can return
* an array containing response status (number), response data (string) and response headers
* (Object).
* an array containing response status (number), response data (string), response headers (Object), and the
* text for the status (string).
* - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
* handler, will be pass through to the real backend (an XHR request will be made to the
* server.
Expand Down
10 changes: 8 additions & 2 deletions test/ng/httpBackendSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ describe('$httpBackend', function() {


it('should normalize IE\'s 1223 status code into 204', function() {
callback.andCallFake(function(status) {
callback.andCallFake(function(status, response, headers, statusText) {
expect(status).toBe(204);
expect(statusText).toBe('No Content');
});

$backend('GET', 'URL', null, callback);
xhr = MockXhr.$$lastInstance;

xhr.status = 1223;
xhr.statusText = 'Unknown';
xhr.readyState = 4;
xhr.onreadystatechange();

Expand Down Expand Up @@ -351,6 +353,7 @@ describe('$httpBackend', function() {

expect(callback).toHaveBeenCalled();
expect(callback.mostRecentCall.args[0]).toBe(200);
expect(callback.mostRecentCall.args[3]).toBe('OK');
});


Expand All @@ -362,6 +365,7 @@ describe('$httpBackend', function() {

expect(callback).toHaveBeenCalled();
expect(callback.mostRecentCall.args[0]).toBe(200);
expect(callback.mostRecentCall.args[3]).toBe('OK');
});


Expand All @@ -373,17 +377,19 @@ describe('$httpBackend', function() {

expect(callback).toHaveBeenCalled();
expect(callback.mostRecentCall.args[0]).toBe(404);
expect(callback.mostRecentCall.args[3]).toBe('Not Found');
});


it('should convert 0 to 200 if content - relative url', function() {
it('should convert 0 to 404 if no content - relative url', function() {
$backend = createHttpBackend($browser, MockXhr, null, null, null, 'file');

$backend('GET', '/whatever/index.html', null, callback);
respond(0, '');

expect(callback).toHaveBeenCalled();
expect(callback.mostRecentCall.args[0]).toBe(404);
expect(callback.mostRecentCall.args[3]).toBe('Not Found');
});
});
});
Expand Down
20 changes: 10 additions & 10 deletions test/ngMock/angular-mocksSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -622,29 +622,29 @@ describe('ngMock', function() {
hb.flush();

expect(callback.callCount).toBe(2);
expect(callback.argsForCall[0]).toEqual([201, 'second', '']);
expect(callback.argsForCall[1]).toEqual([200, 'first', '']);
expect(callback.argsForCall[0]).toEqual([201, 'second', '', '']);
expect(callback.argsForCall[1]).toEqual([200, 'first', '', '']);
});


describe('respond()', function() {
it('should take values', function() {
hb.expect('GET', '/url1').respond(200, 'first', {'header': 'val'});
hb.expect('GET', '/url1').respond(200, 'first', {'header': 'val'}, 'OK');
hb('GET', '/url1', undefined, callback);
hb.flush();

expect(callback).toHaveBeenCalledOnceWith(200, 'first', 'header: val');
expect(callback).toHaveBeenCalledOnceWith(200, 'first', 'header: val', 'OK');
});

it('should take function', function() {
hb.expect('GET', '/some').respond(function(m, u, d, h) {
return [301, m + u + ';' + d + ';a=' + h.a, {'Connection': 'keep-alive'}];
hb.expect('GET', '/some').respond(function (m, u, d, h) {
return [301, m + u + ';' + d + ';a=' + h.a, {'Connection': 'keep-alive'}, 'Moved Permanently'];
});

hb('GET', '/some', 'data', callback, {a: 'b'});
hb.flush();

expect(callback).toHaveBeenCalledOnceWith(301, 'GET/some;data;a=b', 'Connection: keep-alive');
expect(callback).toHaveBeenCalledOnceWith(301, 'GET/some;data;a=b', 'Connection: keep-alive', 'Moved Permanently');
});

it('should default status code to 200', function() {
Expand Down Expand Up @@ -673,8 +673,8 @@ describe('ngMock', function() {
hb.flush();

expect(callback.callCount).toBe(2);
expect(callback.argsForCall[0]).toEqual([200, 'first', '']);
expect(callback.argsForCall[1]).toEqual([200, 'second', '']);
expect(callback.argsForCall[0]).toEqual([200, 'first', '', '']);
expect(callback.argsForCall[1]).toEqual([200, 'second', '', '']);
});
});

Expand Down Expand Up @@ -943,7 +943,7 @@ describe('ngMock', function() {
hb[shortcut]('/foo').respond('bar');
hb(method, '/foo', undefined, callback);
hb.flush();
expect(callback).toHaveBeenCalledOnceWith(200, 'bar', '');
expect(callback).toHaveBeenCalledOnceWith(200, 'bar', '', '');
});
});
});
Expand Down