-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
Expand file tree
/
Copy pathcorsclient.js
More file actions
132 lines (116 loc) · 5.12 KB
/
corsclient.js
File metadata and controls
132 lines (116 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
goog.provide('webdriver.http.CorsClient');
goog.require('goog.Promise');
goog.require('webdriver.http.Client');
goog.require('webdriver.http.Response');
/**
* Communicates with a WebDriver server, which may be on a different domain,
* using the <a href="http://www.w3.org/TR/cors/">cross-origin resource sharing
* </a> (CORS) extension to WebDriver's JSON wire protocol.
*
* <p>Each command from the standard JSON protocol will be encoded in a
* JSON object with the following form:
* {method:string, path:string, data:!Object}
*
* <p>The encoded command is then sent as a POST request to the server's /xdrpc
* endpoint. The server will decode the command, re-route it to the appropriate
* handler, and then return the command's response as a standard JSON response
* object. The JSON responses will <em>always</em> be returned with a 200
* response from the server; clients must rely on the response's "status" field
* to determine whether the command succeeded.
*
* <p>This client cannot be used with the standard wire protocol due to
* limitations in the various browser implementations of the CORS specification:
* <ul>
* <li>IE's <a href="http://goo.gl/6l3kA">XDomainRequest</a> object is only
* capable of generating the types of requests that may be generated through
* a standard <a href="http://goo.gl/vgzAU">HTML form</a> - it can not send
* DELETE requests, as is required in the wire protocol.
* <li>WebKit's implementation of CORS does not follow the spec and forbids
* redirects: https://bugs.webkit.org/show_bug.cgi?id=57600
* This limitation appears to be intentional and is documented in WebKit's
* Layout tests:
* //LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects.html
* <li>If the server does not return a 2xx response, IE
* implementation will fire the XDomainRequest/XMLHttpRequest object's
* onerror handler, but without the corresponding response text returned by
* the server. This renders IE incapable of handling command
* failures in the standard JSON protocol.
* </ul>
*
* @param {string} url URL for the WebDriver server to send commands to.
* @constructor
* @implements {webdriver.http.Client}
* @see <a href="http://www.w3.org/TR/cors/">CORS Spec</a>
* @see <a href="https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol">
* JSON wire protocol</a>
*/
webdriver.http.CorsClient = function(url) {
if (!webdriver.http.CorsClient.isAvailable()) {
throw Error('The current environment does not support cross-origin ' +
'resource sharing');
}
/** @private {string} */
this.url_ = url + webdriver.http.CorsClient.XDRPC_ENDPOINT;
};
/**
* Resource URL to send commands to on the server.
* @type {string}
* @const
*/
webdriver.http.CorsClient.XDRPC_ENDPOINT = '/xdrpc';
/**
* Tests whether the current environment supports cross-origin resource sharing.
* @return {boolean} Whether cross-origin resource sharing is supported.
* @see http://www.w3.org/TR/cors/
*/
webdriver.http.CorsClient.isAvailable = function() {
return typeof XDomainRequest !== 'undefined' ||
(typeof XMLHttpRequest !== 'undefined' &&
goog.isBoolean(new XMLHttpRequest().withCredentials));
};
/** @override */
webdriver.http.CorsClient.prototype.send = function(request) {
var url = this.url_;
return new goog.Promise(function(fulfill, reject) {
var xhr = new (typeof XDomainRequest !== 'undefined' ?
XDomainRequest : XMLHttpRequest);
xhr.open('POST', url, true);
xhr.onload = function() {
fulfill(webdriver.http.Response.fromXmlHttpRequest(
/** @type {!XMLHttpRequest} */ (xhr)));
};
xhr.onerror = function() {
reject(Error([
'Unable to send request: POST ', url,
'\nPerhaps the server did not respond to the preflight request ',
'with valid access control headers?'
].join('')));
};
// Define event handlers for all events on the XDomainRequest. Apparently,
// if we don't do this, IE9+10 will silently abort our request. Yay IE.
// Note, we're not using goog.nullFunction, because it tends to get
// optimized away by the compiler, which leaves us where we were before.
xhr.onprogress = xhr.ontimeout = function() {};
xhr.send(JSON.stringify({
'method': request.method,
'path': request.path,
'data': request.data
}));
});
};