lib/goog/net/xmlhttp.js

1// Copyright 2006 The Closure Library Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS-IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/**
16 * @fileoverview Low level handling of XMLHttpRequest.
17 * @author arv@google.com (Erik Arvidsson)
18 * @author dbk@google.com (David Barrett-Kahn)
19 */
20
21goog.provide('goog.net.DefaultXmlHttpFactory');
22goog.provide('goog.net.XmlHttp');
23goog.provide('goog.net.XmlHttp.OptionType');
24goog.provide('goog.net.XmlHttp.ReadyState');
25goog.provide('goog.net.XmlHttpDefines');
26
27goog.require('goog.asserts');
28goog.require('goog.net.WrapperXmlHttpFactory');
29goog.require('goog.net.XmlHttpFactory');
30
31
32/**
33 * Static class for creating XMLHttpRequest objects.
34 * @return {!goog.net.XhrLike.OrNative} A new XMLHttpRequest object.
35 */
36goog.net.XmlHttp = function() {
37 return goog.net.XmlHttp.factory_.createInstance();
38};
39
40
41/**
42 * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to
43 * true bypasses the ActiveX probing code.
44 * NOTE(user): Due to the way JSCompiler works, this define *will not* strip
45 * out the ActiveX probing code from binaries. To achieve this, use
46 * {@code goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR} instead.
47 * TODO(user): Collapse both defines.
48 */
49goog.define('goog.net.XmlHttp.ASSUME_NATIVE_XHR', false);
50
51
52/** @const */
53goog.net.XmlHttpDefines = {};
54
55
56/**
57 * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to
58 * true eliminates the ActiveX probing code.
59 */
60goog.define('goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR', false);
61
62
63/**
64 * Gets the options to use with the XMLHttpRequest objects obtained using
65 * the static methods.
66 * @return {Object} The options.
67 */
68goog.net.XmlHttp.getOptions = function() {
69 return goog.net.XmlHttp.factory_.getOptions();
70};
71
72
73/**
74 * Type of options that an XmlHttp object can have.
75 * @enum {number}
76 */
77goog.net.XmlHttp.OptionType = {
78 /**
79 * Whether a goog.nullFunction should be used to clear the onreadystatechange
80 * handler instead of null.
81 */
82 USE_NULL_FUNCTION: 0,
83
84 /**
85 * NOTE(user): In IE if send() errors on a *local* request the readystate
86 * is still changed to COMPLETE. We need to ignore it and allow the
87 * try/catch around send() to pick up the error.
88 */
89 LOCAL_REQUEST_ERROR: 1
90};
91
92
93/**
94 * Status constants for XMLHTTP, matches:
95 * http://msdn.microsoft.com/library/default.asp?url=/library/
96 * en-us/xmlsdk/html/0e6a34e4-f90c-489d-acff-cb44242fafc6.asp
97 * @enum {number}
98 */
99goog.net.XmlHttp.ReadyState = {
100 /**
101 * Constant for when xmlhttprequest.readyState is uninitialized
102 */
103 UNINITIALIZED: 0,
104
105 /**
106 * Constant for when xmlhttprequest.readyState is loading.
107 */
108 LOADING: 1,
109
110 /**
111 * Constant for when xmlhttprequest.readyState is loaded.
112 */
113 LOADED: 2,
114
115 /**
116 * Constant for when xmlhttprequest.readyState is in an interactive state.
117 */
118 INTERACTIVE: 3,
119
120 /**
121 * Constant for when xmlhttprequest.readyState is completed
122 */
123 COMPLETE: 4
124};
125
126
127/**
128 * The global factory instance for creating XMLHttpRequest objects.
129 * @type {goog.net.XmlHttpFactory}
130 * @private
131 */
132goog.net.XmlHttp.factory_;
133
134
135/**
136 * Sets the factories for creating XMLHttpRequest objects and their options.
137 * @param {Function} factory The factory for XMLHttpRequest objects.
138 * @param {Function} optionsFactory The factory for options.
139 * @deprecated Use setGlobalFactory instead.
140 */
141goog.net.XmlHttp.setFactory = function(factory, optionsFactory) {
142 goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory(
143 goog.asserts.assert(factory),
144 goog.asserts.assert(optionsFactory)));
145};
146
147
148/**
149 * Sets the global factory object.
150 * @param {!goog.net.XmlHttpFactory} factory New global factory object.
151 */
152goog.net.XmlHttp.setGlobalFactory = function(factory) {
153 goog.net.XmlHttp.factory_ = factory;
154};
155
156
157
158/**
159 * Default factory to use when creating xhr objects. You probably shouldn't be
160 * instantiating this directly, but rather using it via goog.net.XmlHttp.
161 * @extends {goog.net.XmlHttpFactory}
162 * @constructor
163 */
164goog.net.DefaultXmlHttpFactory = function() {
165 goog.net.XmlHttpFactory.call(this);
166};
167goog.inherits(goog.net.DefaultXmlHttpFactory, goog.net.XmlHttpFactory);
168
169
170/** @override */
171goog.net.DefaultXmlHttpFactory.prototype.createInstance = function() {
172 var progId = this.getProgId_();
173 if (progId) {
174 return new ActiveXObject(progId);
175 } else {
176 return new XMLHttpRequest();
177 }
178};
179
180
181/** @override */
182goog.net.DefaultXmlHttpFactory.prototype.internalGetOptions = function() {
183 var progId = this.getProgId_();
184 var options = {};
185 if (progId) {
186 options[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] = true;
187 options[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] = true;
188 }
189 return options;
190};
191
192
193/**
194 * The ActiveX PROG ID string to use to create xhr's in IE. Lazily initialized.
195 * @type {string|undefined}
196 * @private
197 */
198goog.net.DefaultXmlHttpFactory.prototype.ieProgId_;
199
200
201/**
202 * Initialize the private state used by other functions.
203 * @return {string} The ActiveX PROG ID string to use to create xhr's in IE.
204 * @private
205 */
206goog.net.DefaultXmlHttpFactory.prototype.getProgId_ = function() {
207 if (goog.net.XmlHttp.ASSUME_NATIVE_XHR ||
208 goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR) {
209 return '';
210 }
211
212 // The following blog post describes what PROG IDs to use to create the
213 // XMLHTTP object in Internet Explorer:
214 // http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
215 // However we do not (yet) fully trust that this will be OK for old versions
216 // of IE on Win9x so we therefore keep the last 2.
217 if (!this.ieProgId_ && typeof XMLHttpRequest == 'undefined' &&
218 typeof ActiveXObject != 'undefined') {
219 // Candidate Active X types.
220 var ACTIVE_X_IDENTS = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0',
221 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
222 for (var i = 0; i < ACTIVE_X_IDENTS.length; i++) {
223 var candidate = ACTIVE_X_IDENTS[i];
224 /** @preserveTry */
225 try {
226 new ActiveXObject(candidate);
227 // NOTE(user): cannot assign progid and return candidate in one line
228 // because JSCompiler complaings: BUG 658126
229 this.ieProgId_ = candidate;
230 return candidate;
231 } catch (e) {
232 // do nothing; try next choice
233 }
234 }
235
236 // couldn't find any matches
237 throw Error('Could not create ActiveXObject. ActiveX might be disabled,' +
238 ' or MSXML might not be installed');
239 }
240
241 return /** @type {string} */ (this.ieProgId_);
242};
243
244
245//Set the global factory to an instance of the default factory.
246goog.net.XmlHttp.setGlobalFactory(new goog.net.DefaultXmlHttpFactory());