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