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