diff options
Diffstat (limited to 'src/ng/httpBackend.js')
| -rw-r--r-- | src/ng/httpBackend.js | 99 | 
1 files changed, 99 insertions, 0 deletions
| diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js new file mode 100644 index 00000000..201d1a87 --- /dev/null +++ b/src/ng/httpBackend.js @@ -0,0 +1,99 @@ +var XHR = window.XMLHttpRequest || function() { +  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {} +  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {} +  try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {} +  throw new Error("This browser does not support XMLHttpRequest."); +}; + + +/** + * @ngdoc object + * @name angular.module.ng.$httpBackend + * @requires $browser + * @requires $window + * @requires $document + * + * @description + * HTTP backend used by the {@link angular.module.ng.$http service} that delegates to + * XMLHttpRequest object or JSONP and deals with browser incompatibilities. + * + * You should never need to use this service directly, instead use the higher-level abstractions: + * {@link angular.module.ng.$http $http} or {@link angular.module.ng.$resource $resource}. + * + * During testing this implementation is swapped with {@link angular.module.ngMock.$httpBackend mock + * $httpBackend} which can be trained with responses. + */ +function $HttpBackendProvider() { +  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { +    return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, +        $document[0].body, $window.location.protocol.replace(':', '')); +  }]; +} + +function createHttpBackend($browser, XHR, $browserDefer, callbacks, body, locationProtocol) { +  // TODO(vojta): fix the signature +  return function(method, url, post, callback, headers, timeout) { +    $browser.$$incOutstandingRequestCount(); +    url = url || $browser.url(); + +    if (lowercase(method) == 'jsonp') { +      var callbackId = '_' + (callbacks.counter++).toString(36); +      callbacks[callbackId] = function(data) { +        callbacks[callbackId].data = data; +      }; + +      var script = $browser.addJs(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId), +          function() { +        if (callbacks[callbackId].data) { +          completeRequest(callback, 200, callbacks[callbackId].data); +        } else { +          completeRequest(callback, -2); +        } +        delete callbacks[callbackId]; +        body.removeChild(script); +      }); +    } else { +      var xhr = new XHR(); +      xhr.open(method, url, true); +      forEach(headers, function(value, key) { +        if (value) xhr.setRequestHeader(key, value); +      }); + +      var status; + +      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the +      // response is in the cache. the promise api will ensure that to the app code the api is +      // always async +      xhr.onreadystatechange = function() { +        if (xhr.readyState == 4) { +          completeRequest( +              callback, status || xhr.status, xhr.responseText, xhr.getAllResponseHeaders()); +        } +      }; + +      xhr.send(post || ''); + +      if (timeout > 0) { +        $browserDefer(function() { +          status = -1; +          xhr.abort(); +        }, timeout); +      } +    } + + +    function completeRequest(callback, status, response, headersString) { +      // URL_MATCH is defined in src/service/location.js +      var protocol = (url.match(URL_MATCH) || ['', locationProtocol])[1]; + +      // fix status code for file protocol (it's always 0) +      status = (protocol == 'file') ? (response ? 200 : 404) : status; + +      // normalize IE bug (http://bugs.jquery.com/ticket/1450) +      status = status == 1223 ? 204 : status; + +      callback(status, response, headersString); +      $browser.$$completeOutstandingRequest(noop); +    } +  }; +} | 
