Path: blob/trunk/third_party/closure/goog/net/fetchxmlhttpfactory.js
2868 views
// Copyright 2015 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314goog.provide('goog.net.FetchXmlHttp');15goog.provide('goog.net.FetchXmlHttpFactory');1617goog.require('goog.asserts');18goog.require('goog.events.EventTarget');19goog.require('goog.functions');20goog.require('goog.log');21goog.require('goog.net.XhrLike');22goog.require('goog.net.XmlHttpFactory');23242526/**27* Factory for creating Xhr objects that uses the native fetch() method.28* https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API29* Note that this factory is intended for use in Service Worker only.30* @param {!WorkerGlobalScope} worker The Service Worker global scope.31* @extends {goog.net.XmlHttpFactory}32* @struct33* @constructor34*/35goog.net.FetchXmlHttpFactory = function(worker) {36goog.net.FetchXmlHttpFactory.base(this, 'constructor');3738/** @private @final {!WorkerGlobalScope} */39this.worker_ = worker;4041/** @private {!RequestCredentials|undefined} */42this.credentialsMode_ = undefined;4344/** @private {!RequestCache|undefined} */45this.cacheMode_ = undefined;46};47goog.inherits(goog.net.FetchXmlHttpFactory, goog.net.XmlHttpFactory);484950/** @override */51goog.net.FetchXmlHttpFactory.prototype.createInstance = function() {52var instance = new goog.net.FetchXmlHttp(this.worker_);53if (this.credentialsMode_) {54instance.setCredentialsMode(this.credentialsMode_);55}56if (this.cacheMode_) {57instance.setCacheMode(this.cacheMode_);58}59return instance;60};616263/** @override */64goog.net.FetchXmlHttpFactory.prototype.internalGetOptions =65goog.functions.constant({});666768/**69* @param {!RequestCredentials} credentialsMode The credentials mode of the70* Service Worker fetch.71*/72goog.net.FetchXmlHttpFactory.prototype.setCredentialsMode = function(73credentialsMode) {74this.credentialsMode_ = credentialsMode;75};767778/**79* @param {!RequestCache} cacheMode The cache mode of the Service Worker fetch.80*/81goog.net.FetchXmlHttpFactory.prototype.setCacheMode = function(cacheMode) {82this.cacheMode_ = cacheMode;83};84858687/**88* FetchXmlHttp object constructor.89* @param {!WorkerGlobalScope} worker90* @extends {goog.events.EventTarget}91* @implements {goog.net.XhrLike}92* @constructor93* @struct94*/95goog.net.FetchXmlHttp = function(worker) {96goog.net.FetchXmlHttp.base(this, 'constructor');9798/** @private @final {!WorkerGlobalScope} */99this.worker_ = worker;100101/** @private {RequestCredentials|undefined} */102this.credentialsMode_ = undefined;103104/** @private {RequestCache|undefined} */105this.cacheMode_ = undefined;106107/**108* Request state.109* @type {goog.net.FetchXmlHttp.RequestState}110*/111this.readyState = goog.net.FetchXmlHttp.RequestState.UNSENT;112113/**114* HTTP status.115* @type {number}116*/117this.status = 0;118119/**120* HTTP status string.121* @type {string}122*/123this.statusText = '';124125/**126* Content of the response.127* @type {string}128*/129this.responseText = '';130131/**132* Document response entity body.133* NOTE: This is always null and not supported by this class.134* @final {null}135*/136this.responseXML = null;137138/**139* Method to call when the state changes.140* @type {?function()}141*/142this.onreadystatechange = null;143144/** @private {!Headers} */145this.requestHeaders_ = new Headers();146147/** @private {?Headers} */148this.responseHeaders_ = null;149150/**151* Request method (GET or POST).152* @private {string}153*/154this.method_ = 'GET';155156/**157* Request URL.158* @private {string}159*/160this.url_ = '';161162/**163* Whether the request is in progress.164* @private {boolean}165*/166this.inProgress_ = false;167168/** @private @final {?goog.log.Logger} */169this.logger_ = goog.log.getLogger('goog.net.FetchXmlHttp');170171};172goog.inherits(goog.net.FetchXmlHttp, goog.events.EventTarget);173174175/**176* State of the requests.177* @enum {number}178*/179goog.net.FetchXmlHttp.RequestState = {180UNSENT: 0,181OPENED: 1,182HEADER_RECEIVED: 2,183LOADING: 3,184DONE: 4185};186187188/** @override */189goog.net.FetchXmlHttp.prototype.open = function(method, url, opt_async) {190goog.asserts.assert(!!opt_async, 'Only async requests are supported.');191if (this.readyState != goog.net.FetchXmlHttp.RequestState.UNSENT) {192this.abort();193throw Error('Error reopening a connection');194}195196this.method_ = method;197this.url_ = url;198199this.readyState = goog.net.FetchXmlHttp.RequestState.OPENED;200this.dispatchCallback_();201};202203204/** @override */205goog.net.FetchXmlHttp.prototype.send = function(opt_data) {206if (this.readyState != goog.net.FetchXmlHttp.RequestState.OPENED) {207this.abort();208throw Error('need to call open() first. ');209}210211this.inProgress_ = true;212var requestInit = {213headers: this.requestHeaders_,214method: this.method_,215credentials: this.credentialsMode_,216cache: this.cacheMode_217};218if (opt_data) {219requestInit['body'] = opt_data;220}221this.worker_222.fetch(new Request(this.url_, /** @type {!RequestInit} */ (requestInit)))223.then(224this.handleResponse_.bind(this), this.handleSendFailure_.bind(this));225};226227228/** @override */229goog.net.FetchXmlHttp.prototype.abort = function() {230this.responseText = '';231this.requestHeaders_ = new Headers();232this.status = 0;233if (((this.readyState >= goog.net.FetchXmlHttp.RequestState.OPENED) &&234this.inProgress_) &&235(this.readyState != goog.net.FetchXmlHttp.RequestState.DONE)) {236this.readyState = goog.net.FetchXmlHttp.RequestState.DONE;237this.inProgress_ = false;238this.dispatchCallback_();239}240241this.readyState = goog.net.FetchXmlHttp.RequestState.UNSENT;242};243244245/**246* Handles the fetch response.247* @param {!Response} response248* @private249*/250goog.net.FetchXmlHttp.prototype.handleResponse_ = function(response) {251if (!this.inProgress_) {252// The request was aborted, ignore.253return;254}255256if (!this.responseHeaders_) {257this.responseHeaders_ = response.headers;258this.readyState = goog.net.FetchXmlHttp.RequestState.HEADER_RECEIVED;259this.dispatchCallback_();260}261// A callback may abort the request.262if (!this.inProgress_) {263// The request was aborted, ignore.264return;265}266267this.readyState = goog.net.FetchXmlHttp.RequestState.LOADING;268this.dispatchCallback_();269// A callback may abort the request.270if (!this.inProgress_) {271// The request was aborted, ignore.272return;273}274response.text().then(275this.handleResponseText_.bind(this, response),276this.handleSendFailure_.bind(this));277};278279280/**281* Handles the response text.282* @param {!Response} response283* @param {string} responseText284* @private285*/286goog.net.FetchXmlHttp.prototype.handleResponseText_ = function(287response, responseText) {288if (!this.inProgress_) {289// The request was aborted, ignore.290return;291}292this.status = response.status;293this.statusText = response.statusText;294this.responseText = responseText;295this.readyState = goog.net.FetchXmlHttp.RequestState.DONE;296this.dispatchCallback_();297};298299300/**301* Handles the send failure.302* @param {*} error303* @private304*/305goog.net.FetchXmlHttp.prototype.handleSendFailure_ = function(error) {306var e = error instanceof Error ? error : Error(error);307goog.log.warning(this.logger_, 'Failed to fetch url ' + this.url_, e);308if (!this.inProgress_) {309// The request was aborted, ignore.310return;311}312this.readyState = goog.net.FetchXmlHttp.RequestState.DONE;313this.dispatchCallback_();314};315316317/** @override */318goog.net.FetchXmlHttp.prototype.setRequestHeader = function(header, value) {319this.requestHeaders_.append(header, value);320};321322323/** @override */324goog.net.FetchXmlHttp.prototype.getResponseHeader = function(header) {325return this.responseHeaders_.get(header.toLowerCase()) || '';326};327328329/** @override */330goog.net.FetchXmlHttp.prototype.getAllResponseHeaders = function() {331// TODO(user): Implement once the Headers extern support entries().332return '';333};334335336/**337* @param {!RequestCredentials} credentialsMode The credentials mode of the338* Service Worker fetch.339*/340goog.net.FetchXmlHttp.prototype.setCredentialsMode = function(credentialsMode) {341this.credentialsMode_ = credentialsMode;342};343344345/**346* @param {!RequestCache} cacheMode The cache mode of the Service Worker fetch.347*/348goog.net.FetchXmlHttp.prototype.setCacheMode = function(cacheMode) {349this.cacheMode_ = cacheMode;350};351352353/**354* Dispatches the callback, if the callback attribute is defined.355* @private356*/357goog.net.FetchXmlHttp.prototype.dispatchCallback_ = function() {358if (this.onreadystatechange) {359this.onreadystatechange.call(this);360}361};362363364