diff options
| author | Karl Seamon | 2011-07-29 18:32:30 -0400 | 
|---|---|---|
| committer | Igor Minar | 2011-08-19 01:20:45 -0700 | 
| commit | 4ec1d8ee86e3138fb91543ca0dca28463895c090 (patch) | |
| tree | 9f7fff13f177317ff15f8804789a44576a151908 /src | |
| parent | c37bfde9eb31556ee1eb146795b0c1f1504a4a26 (diff) | |
| download | angular.js-4ec1d8ee86e3138fb91543ca0dca28463895c090.tar.bz2 | |
feat($xhr,$resource): expose response headers in callbacks
all $xhr*, $resource and related mocks now have access to headers from
their callbacks
Diffstat (limited to 'src')
| -rw-r--r-- | src/Browser.js | 35 | ||||
| -rw-r--r-- | src/Resource.js | 4 | ||||
| -rw-r--r-- | src/angular-mocks.js | 35 | ||||
| -rw-r--r-- | src/service/resource.js | 10 | ||||
| -rw-r--r-- | src/service/xhr.bulk.js | 11 | ||||
| -rw-r--r-- | src/service/xhr.cache.js | 18 | ||||
| -rw-r--r-- | src/service/xhr.js | 11 | 
7 files changed, 91 insertions, 33 deletions
| diff --git a/src/Browser.js b/src/Browser.js index 2b2170e2..65d27448 100644 --- a/src/Browser.js +++ b/src/Browser.js @@ -84,7 +84,9 @@ function Browser(window, document, body, XHR, $log) {     * @param {string} method Requested method (get|post|put|delete|head|json)     * @param {string} url Requested url     * @param {?string} post Post data to send (null if nothing to post) -   * @param {function(number, string)} callback Function that will be called on response +   * @param {function(number, string, function([string]))} callback Function that will be called on +   *   response. The third argument is a function that can be called to return a specified response +   *   header or an Object containing all headers (when called with no arguments).     * @param {object=} header additional HTTP headers to send with XHR.     *   Standard headers are:     *   <ul> @@ -97,6 +99,8 @@ function Browser(window, document, body, XHR, $log) {     * Send ajax request     */    self.xhr = function(method, url, post, callback, headers) { +    var parsedHeaders; +      outstandingRequestCount ++;      if (lowercase(method) == 'json') {        var callbackId = ("angular_" + Math.random() + '_' + (idCounter++)).replace(/\d\./, ''); @@ -123,7 +127,34 @@ function Browser(window, document, body, XHR, $log) {          if (xhr.readyState == 4) {            // normalize IE bug (http://bugs.jquery.com/ticket/1450)            var status = xhr.status == 1223 ? 204 : xhr.status || 200; -          completeOutstandingRequest(callback, status, xhr.responseText); +          completeOutstandingRequest(callback, status, xhr.responseText, function(header) { +            header = lowercase(header); + +            if (header) { +              return parsedHeaders +                ? parsedHeaders[header] || null +                : xhr.getResponseHeader(header); +            } else { +              // Return an object containing each response header +              parsedHeaders = {}; + +              forEach(xhr.getAllResponseHeaders().split('\n'), function(line) { +                var i = line.indexOf(':'), +                    key = lowercase(trim(line.substr(0, i))), +                    value = trim(line.substr(i + 1)); + +                if (parsedHeaders[key]) { +                  // Combine repeated headers +                  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 +                  parsedHeaders[key] += ', ' + value; +                } else { +                  parsedHeaders[key] = value; +                } +              }); + +              return parsedHeaders; +            } +          });          }        };        xhr.send(post || ''); diff --git a/src/Resource.js b/src/Resource.js index 74d952ed..4bf5cf65 100644 --- a/src/Resource.js +++ b/src/Resource.js @@ -111,7 +111,7 @@ ResourceFactory.prototype = {            action.method,            route.url(extend({}, action.params || {}, extractParams(data), params)),            data, -          function(status, response) { +          function(status, response, responseHeaders) {              if (response) {                if (action.isArray) {                  value.length = 0; @@ -122,7 +122,7 @@ ResourceFactory.prototype = {                  copy(response, value);                }              } -            (success||noop)(value); +            (success||noop)(value, responseHeaders);            },            error || action.verifyCache,            action.verifyCache); diff --git a/src/angular-mocks.js b/src/angular-mocks.js index 5d56ae27..d793f511 100644 --- a/src/angular-mocks.js +++ b/src/angular-mocks.js @@ -152,7 +152,14 @@ function MockBrowser() {            throw new Error("Missing HTTP request header: " + key + ": " + value);          }        }); -      callback(expectation.code, expectation.response); +      callback(expectation.code, expectation.response, function(header) { +        if (header) { +          header = header.toLowerCase(); +          return expectation.responseHeaders && expectation.responseHeaders[header] || null; +        } else { +          return expectation.responseHeaders || {}; +        } +      });      });    };    self.xhr.expectations = expectations; @@ -162,12 +169,22 @@ function MockBrowser() {      if (data && angular.isString(data)) url += "|" + data;      var expect = expectations[method] || (expectations[method] = {});      return { -      respond: function(code, response) { +      respond: function(code, response, responseHeaders) {          if (!angular.isNumber(code)) { +          responseHeaders = response;            response = code;            code = 200;          } -        expect[url] = {code:code, response:response, headers: headers || {}}; +        angular.forEach(responseHeaders, function(value, key) { +          delete responseHeaders[key]; +          responseHeaders[key.toLowerCase()] = value; +        }); +        expect[url] = { +          code: code, +          response: response, +          headers: headers || {}, +          responseHeaders: responseHeaders || {} +        };        }      };    }; @@ -268,7 +285,7 @@ function MockBrowser() {    self.defer = function(fn, delay) {      delay = delay || 0;      self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId}); -    self.deferredFns.sort(function(a,b){ return a.time - b.time;}); +    self.deferredFns.sort(function(a,b){return a.time - b.time;});      return self.deferredNextId++;    }; @@ -374,7 +391,7 @@ angular.service('$browser', function(){   * See {@link angular.mock} for more info on angular mocks.   */  angular.service('$exceptionHandler', function() { -  return function(e) { throw e;}; +  return function(e) {throw e;};  }); @@ -394,10 +411,10 @@ angular.service('$log', MockLogFactory);  function MockLogFactory() {    var $log = { -    log: function(){ $log.log.logs.push(arguments); }, -    warn: function(){ $log.warn.logs.push(arguments); }, -    info: function(){ $log.info.logs.push(arguments); }, -    error: function(){ $log.error.logs.push(arguments); } +    log: function(){$log.log.logs.push(arguments);}, +    warn: function(){$log.warn.logs.push(arguments);}, +    info: function(){$log.info.logs.push(arguments);}, +    error: function(){$log.error.logs.push(arguments);}    };    $log.log.logs = []; diff --git a/src/service/resource.js b/src/service/resource.js index f6e0be18..47b57645 100644 --- a/src/service/resource.js +++ b/src/service/resource.js @@ -147,9 +147,15 @@   *     <pre>       var User = $resource('/user/:userId', {userId:'@id'}); -     User.get({userId:123}, function(u){ +     User.get({userId:123}, function(u, responseHeaders){         u.abc = true; -       u.$save(); +       u.$save(function(u, responseHeaders) { +         // Get an Object containing all response headers +         var allHeaders = responseHeaders(); + +         // Get a specific response header +         u.newId = responseHeaders('Location'); +       });       });     </pre> diff --git a/src/service/xhr.bulk.js b/src/service/xhr.bulk.js index d7fc7990..8d9e7a72 100644 --- a/src/service/xhr.bulk.js +++ b/src/service/xhr.bulk.js @@ -48,13 +48,14 @@ angularServiceInject('$xhr.bulk', function($xhr, $error, $log){          queue.requests = [];          queue.callbacks = [];          $xhr('POST', url, {requests: currentRequests}, -          function(code, response) { +          function(code, response, responseHeaders) {              forEach(response, function(response, i) {                try {                  if (response.status == 200) { -                  (currentRequests[i].success || noop)(response.status, response.response); +                  (currentRequests[i].success || noop) +                      (response.status, response.response, responseHeaders);                  } else if (isFunction(currentRequests[i].error)) { -                    currentRequests[i].error(response.status, response.response); +                    currentRequests[i].error(response.status, response.response, responseHeaders);                  } else {                    $error(currentRequests[i], response);                  } @@ -64,11 +65,11 @@ angularServiceInject('$xhr.bulk', function($xhr, $error, $log){              });              (success || noop)();            }, -          function(code, response) { +          function(code, response, responseHeaders) {              forEach(currentRequests, function(request, i) {                try {                  if (isFunction(request.error)) { -                  request.error(code, response); +                  request.error(code, response, responseHeaders);                  } else {                    $error(request, response);                  } diff --git a/src/service/xhr.cache.js b/src/service/xhr.cache.js index 256b936e..b3280101 100644 --- a/src/service/xhr.cache.js +++ b/src/service/xhr.cache.js @@ -22,8 +22,8 @@   * @param {string} method HTTP method.   * @param {string} url Destination URL.   * @param {(string|Object)=} post Request body. - * @param {function(number, (string|Object))} success Response success callback. - * @param {function(number, (string|Object))=} error Response error callback. + * @param {function(number, (string|Object), Function)} success Response success callback. + * @param {function(number, (string|Object), Function)} error Response error callback.   * @param {boolean=} [verifyCache=false] If `true` then a result is immediately returned from cache   *   (if present) while a request is sent to the server for a fresh response that will update the   *   cached entry. The `success` function will be called when the response is received. @@ -55,9 +55,9 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $error, $log) {        if (dataCached = cache.data[url]) {          if (sync) { -          success(200, copy(dataCached.value)); +          success(200, copy(dataCached.value), copy(dataCached.headers));          } else { -          $defer(function() { success(200, copy(dataCached.value)); }); +          $defer(function() { success(200, copy(dataCached.value), copy(dataCached.headers)); });          }          if (!verifyCache) @@ -70,20 +70,20 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $error, $log) {        } else {          inflight[url] = {successes: [success], errors: [error]};          cache.delegate(method, url, post, -          function(status, response) { +          function(status, response, responseHeaders) {              if (status == 200) -              cache.data[url] = {value: response}; +              cache.data[url] = {value: response, headers: responseHeaders};              var successes = inflight[url].successes;              delete inflight[url];              forEach(successes, function(success) {                try { -                (success||noop)(status, copy(response)); +                (success||noop)(status, copy(response), responseHeaders);                } catch(e) {                  $log.error(e);                }              });            }, -          function(status, response) { +          function(status, response, responseHeaders) {              var errors = inflight[url].errors,                  successes = inflight[url].successes;              delete inflight[url]; @@ -91,7 +91,7 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $error, $log) {              forEach(errors, function(error, i) {                try {                  if (isFunction(error)) { -                  error(status, copy(response)); +                  error(status, copy(response), copy(responseHeaders));                  } else {                    $error(                      {method: method, url: url, data: post, success: successes[i]}, diff --git a/src/service/xhr.js b/src/service/xhr.js index 70fcd067..6bff6f04 100644 --- a/src/service/xhr.js +++ b/src/service/xhr.js @@ -96,7 +96,7 @@   *   angular generated callback function.   * @param {(string|Object)=} post Request content as either a string or an object to be stringified   *   as JSON before sent to the server. - * @param {function(number, (string|Object))} success A function to be called when the response is + * @param {function(number, (string|Object), Function)} success A function to be called when the response is   *   received. The success function will be called with:   *   *   - {number} code [HTTP status code](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes) of @@ -104,6 +104,9 @@   *     {@link angular.service.$xhr.error} service (or custom error callback).   *   - {string|Object} response Response object as string or an Object if the response was in JSON   *     format. + *   - {function(string=)} responseHeaders A function that when called with a {string} header name, + *     returns the value of that header or null if it does not exist; when called without + *     arguments, returns an object containing every response header   * @param {function(number, (string|Object))} error A function to be called if the response code is   *   not 2xx.. Accepts the same arguments as success, above.   * @@ -198,7 +201,7 @@ angularServiceInject('$xhr', function($browser, $error, $log, $updateView){        post = toJson(post);      } -    $browser.xhr(method, url, post, function(code, response){ +    $browser.xhr(method, url, post, function(code, response, responseHeaders){        try {          if (isString(response)) {            if (response.match(/^\)\]\}',\n/)) response=response.substr(6); @@ -207,9 +210,9 @@ angularServiceInject('$xhr', function($browser, $error, $log, $updateView){            }          }          if (200 <= code && code < 300) { -          success(code, response); +          success(code, response, responseHeaders);          } else if (isFunction(error)) { -          error(code, response); +          error(code, response, responseHeaders);          } else {            $error(              {method: method, url: url, data: post, success: success}, | 
