# 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 |
21 | goog.provide('goog.net.DefaultXmlHttpFactory');
22 | goog.provide('goog.net.XmlHttp');
23 | goog.provide('goog.net.XmlHttp.OptionType');
24 | goog.provide('goog.net.XmlHttp.ReadyState');
25 | goog.provide('goog.net.XmlHttpDefines');
26 |
27 | goog.require('goog.asserts');
28 | goog.require('goog.net.WrapperXmlHttpFactory');
29 | goog.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 | */
36 | goog.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(ruilopes): 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(ruilopes): Collapse both defines.
48 | */
49 | goog.define('goog.net.XmlHttp.ASSUME_NATIVE_XHR', false);
50 |
51 |
52 | /** @const */
53 | goog.net.XmlHttpDefines = {};
54 |
55 |
56 | /**
57 | * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to
58 | * true eliminates the ActiveX probing code.
59 | */
60 | goog.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 | */
68 | goog.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 | */
77 | goog.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 | */
99 | goog.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 | */
132 | goog.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 | */
141 | goog.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 | */
152 | goog.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 | */
164 | goog.net.DefaultXmlHttpFactory = function() {
165 | goog.net.XmlHttpFactory.call(this);
166 | };
167 | goog.inherits(goog.net.DefaultXmlHttpFactory, goog.net.XmlHttpFactory);
168 |
169 |
170 | /** @override */
171 | goog.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 */
182 | goog.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 | */
198 | goog.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 | */
206 | goog.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.
246 | goog.net.XmlHttp.setGlobalFactory(new goog.net.DefaultXmlHttpFactory());