OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/renderer/websockethandle_impl.h" | |
6 | |
7 #include <stdint.h> | |
8 #include <string.h> | |
9 | |
10 #include <string> | |
11 #include <utility> | |
12 #include <vector> | |
Adam Rice
2016/07/27 02:38:54
<vector> unused?
| |
13 | |
14 #include "base/logging.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "ipc/ipc_message.h" | |
17 #include "third_party/WebKit/public/platform/ServiceRegistry.h" | |
18 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" | |
19 #include "third_party/WebKit/public/platform/WebString.h" | |
20 #include "third_party/WebKit/public/platform/WebURL.h" | |
21 #include "third_party/WebKit/public/platform/WebVector.h" | |
22 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandle. h" | |
23 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandleC lient.h" | |
24 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandsha keRequestInfo.h" | |
25 #include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandsha keResponseInfo.h" | |
26 #include "url/gurl.h" | |
27 #include "url/origin.h" | |
28 | |
29 using blink::WebSecurityOrigin; | |
30 using blink::WebSocketHandle; | |
31 using blink::WebSocketHandleClient; | |
32 using blink::WebString; | |
33 using blink::WebURL; | |
34 using blink::WebVector; | |
35 | |
36 namespace content { | |
37 namespace { | |
38 | |
39 const uint16_t kAbnormalShutdownOpCode = 1006; | |
40 | |
41 } // namespace | |
42 | |
43 WebSocketHandleImpl::WebSocketHandleImpl( | |
44 blink::ServiceRegistry* service_registry, | |
45 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | |
46 : client_(nullptr), | |
47 client_binding_(this), | |
48 task_runner_(std::move(task_runner)), | |
49 render_frame_id_(MSG_ROUTING_NONE) { | |
50 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
51 << " created"; | |
52 | |
53 service_registry->connectToRemoteService(mojo::GetProxy(&websocket_)); | |
54 | |
55 websocket_.set_connection_error_handler( | |
56 base::Bind(&WebSocketHandleImpl::OnConnectionError, | |
57 base::Unretained(this))); | |
58 } | |
59 | |
60 void WebSocketHandleImpl::connect(const WebURL& url, | |
61 const WebVector<WebString>& protocols, | |
62 const WebSecurityOrigin& origin, | |
63 const WebURL& first_party_for_cookies, | |
64 const WebString& user_agent_override, | |
65 WebSocketHandleClient* client) { | |
66 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
67 << " Connect(" << url << ", " << origin.toString().utf8() << ")"; | |
68 | |
69 DCHECK(websocket_); | |
70 | |
71 DCHECK(!client_); | |
72 DCHECK(client); | |
73 client_ = client; | |
74 | |
75 mojo::Array<mojo::String> protocols_to_pass(protocols.size()); | |
76 for (size_t i = 0; i < protocols.size(); ++i) | |
77 protocols_to_pass[i] = protocols[i].utf8(); | |
78 | |
79 websocket_->AddChannelRequest( | |
80 url, | |
81 std::move(protocols_to_pass), | |
82 origin, | |
83 first_party_for_cookies, | |
84 user_agent_override.latin1(), | |
85 render_frame_id_, | |
86 client_binding_.CreateInterfacePtrAndBind(task_runner_)); | |
87 } | |
88 | |
89 void WebSocketHandleImpl::send(bool fin, | |
90 WebSocketHandle::MessageType type, | |
91 const char* data, | |
92 size_t size) { | |
93 DCHECK(websocket_); | |
94 | |
95 mojom::WebSocketMessageType type_to_pass; | |
96 switch (type) { | |
97 case WebSocketHandle::MessageTypeContinuation: | |
98 type_to_pass = mojom::WebSocketMessageType::CONTINUATION; | |
99 break; | |
100 case WebSocketHandle::MessageTypeText: | |
101 type_to_pass = mojom::WebSocketMessageType::TEXT; | |
102 break; | |
103 case WebSocketHandle::MessageTypeBinary: | |
104 type_to_pass = mojom::WebSocketMessageType::BINARY; | |
105 break; | |
106 default: | |
107 NOTREACHED(); | |
108 return; | |
109 } | |
110 | |
111 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
112 << " Send(" << fin << ", " << type_to_pass << ", " | |
113 << "(data size = " << size << "))"; | |
114 | |
115 mojo::Array<uint8_t> data_to_pass(size); | |
116 std::copy(data, data + size, data_to_pass.begin()); | |
117 | |
118 websocket_->SendFrame(fin, type_to_pass, std::move(data_to_pass)); | |
119 } | |
120 | |
121 void WebSocketHandleImpl::flowControl(int64_t quota) { | |
122 DCHECK(websocket_); | |
123 | |
124 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
125 << " FlowControl(" << quota << ")"; | |
126 | |
127 websocket_->SendFlowControl(quota); | |
128 } | |
129 | |
130 void WebSocketHandleImpl::close(unsigned short code, const WebString& reason) { | |
131 DCHECK(websocket_); | |
132 | |
133 std::string reason_to_pass = reason.utf8(); | |
134 | |
135 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
136 << " Close(" << code << ", " << reason_to_pass << ")"; | |
137 | |
138 websocket_->StartClosingHandshake(code, reason_to_pass); | |
139 } | |
140 | |
141 WebSocketHandleImpl::~WebSocketHandleImpl() { | |
142 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
143 << " deleted"; | |
144 | |
145 if (websocket_) | |
146 websocket_->StartClosingHandshake(kAbnormalShutdownOpCode, std::string()); | |
147 } | |
148 | |
149 void WebSocketHandleImpl::Disconnect() { | |
150 websocket_.reset(); | |
151 client_ = nullptr; | |
152 } | |
153 | |
154 void WebSocketHandleImpl::OnConnectionError() { | |
155 // Our connection to the WebSocket was dropped. This could be due to | |
156 // exceeding the maximum number of concurrent websockets from this process. | |
157 | |
158 // TODO(darin): This error message is overly specific. We don't know for sure | |
159 // that this is the only reason we'd get here. This should be more generic or | |
160 // we should figure out how to make it more specific. | |
161 OnFailChannel("Error in connection establishment: " | |
162 "net::ERR_INSUFFICIENT_RESOURCES"); | |
163 } | |
164 | |
165 void WebSocketHandleImpl::OnFailChannel(const mojo::String& message) { | |
166 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
167 << " OnFailChannel(" << message << ")"; | |
168 | |
169 WebSocketHandleClient* client = client_; | |
170 Disconnect(); | |
171 if (!client) | |
172 return; | |
173 | |
174 client->didFail(this, WebString::fromUTF8(message)); | |
175 // |this| can be deleted here. | |
176 } | |
177 | |
178 void WebSocketHandleImpl::OnStartOpeningHandshake( | |
179 mojom::WebSocketHandshakeRequestPtr request) { | |
180 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
181 << " OnStartOpeningHandshake(" << request->url << ")"; | |
182 // All strings are already encoded to ASCII in the browser. | |
183 blink::WebSocketHandshakeRequestInfo request_to_pass; | |
184 request_to_pass.setURL(WebURL(request->url)); | |
185 for (size_t i = 0; i < request->headers.size(); ++i) { | |
186 const mojom::HttpHeaderPtr& header = request->headers[i]; | |
187 request_to_pass.addHeaderField(WebString::fromLatin1(header->name), | |
188 WebString::fromLatin1(header->value)); | |
189 } | |
190 request_to_pass.setHeadersText(WebString::fromLatin1(request->headers_text)); | |
191 client_->didStartOpeningHandshake(this, request_to_pass); | |
192 } | |
193 | |
194 void WebSocketHandleImpl::OnFinishOpeningHandshake( | |
195 mojom::WebSocketHandshakeResponsePtr response) { | |
196 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
197 << " OnFinishOpeningHandshake(" << response->url << ")"; | |
198 | |
199 // All strings are already encoded to ASCII in the browser. | |
200 blink::WebSocketHandshakeResponseInfo response_to_pass; | |
201 response_to_pass.setStatusCode(response->status_code); | |
202 response_to_pass.setStatusText(WebString::fromLatin1(response->status_text)); | |
203 for (size_t i = 0; i < response->headers.size(); ++i) { | |
204 const mojom::HttpHeaderPtr& header = response->headers[i]; | |
205 response_to_pass.addHeaderField(WebString::fromLatin1(header->name), | |
206 WebString::fromLatin1(header->value)); | |
207 } | |
208 response_to_pass.setHeadersText( | |
209 WebString::fromLatin1(response->headers_text)); | |
210 client_->didFinishOpeningHandshake(this, response_to_pass); | |
211 } | |
212 | |
213 void WebSocketHandleImpl::OnAddChannelResponse( | |
214 const mojo::String& protocol, | |
215 const mojo::String& extensions) { | |
216 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
217 << " OnAddChannelResponse(" | |
218 << protocol << ", " << extensions << ")"; | |
219 | |
220 if (!client_) | |
221 return; | |
222 | |
223 client_->didConnect(this, | |
224 WebString::fromUTF8(protocol), | |
225 WebString::fromUTF8(extensions)); | |
226 // |this| can be deleted here. | |
227 } | |
228 | |
229 void WebSocketHandleImpl::OnDataFrame( | |
230 bool fin, mojom::WebSocketMessageType type, | |
231 mojo::Array<uint8_t> data) { | |
232 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
233 << " OnDataFrame(" << fin << ", " << type << ", " | |
234 << "(data size = " << data.size() << "))"; | |
235 if (!client_) | |
236 return; | |
237 | |
238 WebSocketHandle::MessageType type_to_pass = | |
239 WebSocketHandle::MessageTypeContinuation; | |
240 switch (type) { | |
241 case mojom::WebSocketMessageType::CONTINUATION: | |
242 type_to_pass = WebSocketHandle::MessageTypeContinuation; | |
243 break; | |
244 case mojom::WebSocketMessageType::TEXT: | |
245 type_to_pass = WebSocketHandle::MessageTypeText; | |
246 break; | |
247 case mojom::WebSocketMessageType::BINARY: | |
248 type_to_pass = WebSocketHandle::MessageTypeBinary; | |
249 break; | |
250 } | |
251 const char* data_to_pass = | |
252 reinterpret_cast<const char*>(data.empty() ? nullptr : &data[0]); | |
253 client_->didReceiveData(this, fin, type_to_pass, data_to_pass, data.size()); | |
254 // |this| can be deleted here. | |
255 } | |
256 | |
257 void WebSocketHandleImpl::OnFlowControl(int64_t quota) { | |
258 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
259 << " OnFlowControl(" << quota << ")"; | |
260 if (!client_) | |
261 return; | |
262 | |
263 client_->didReceiveFlowControl(this, quota); | |
264 // |this| can be deleted here. | |
265 } | |
266 | |
267 void WebSocketHandleImpl::OnDropChannel(bool was_clean, uint16_t code, | |
268 const mojo::String& reason) { | |
269 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
270 << " OnDropChannel(" << was_clean << ", " << code << ", " | |
271 << reason << ")"; | |
272 | |
273 WebSocketHandleClient* client = client_; | |
274 Disconnect(); | |
275 if (!client) | |
276 return; | |
277 | |
278 client->didClose(this, was_clean, code, WebString::fromUTF8(reason)); | |
279 // |this| can be deleted here. | |
280 } | |
281 | |
282 void WebSocketHandleImpl::OnClosingHandshake() { | |
283 DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) | |
284 << " OnClosingHandshake()"; | |
285 if (!client_) | |
286 return; | |
287 | |
288 client_->didStartClosingHandshake(this); | |
289 // |this| can be deleted here. | |
290 } | |
291 | |
292 } // namespace content | |
OLD | NEW |