Chromium Code Reviews| Index: content/renderer/websockethandle_impl.cc |
| diff --git a/content/renderer/websockethandle_impl.cc b/content/renderer/websockethandle_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d7cc64e7e8abea98cf903bcc4147adb15c5c7377 |
| --- /dev/null |
| +++ b/content/renderer/websockethandle_impl.cc |
| @@ -0,0 +1,292 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/renderer/websockethandle_impl.h" |
| + |
| +#include <stdint.h> |
| +#include <string.h> |
| + |
| +#include <string> |
| +#include <utility> |
| +#include <vector> |
|
Adam Rice
2016/07/27 02:38:54
<vector> unused?
|
| + |
| +#include "base/logging.h" |
| +#include "base/strings/string_util.h" |
| +#include "ipc/ipc_message.h" |
| +#include "third_party/WebKit/public/platform/ServiceRegistry.h" |
| +#include "third_party/WebKit/public/platform/WebSecurityOrigin.h" |
| +#include "third_party/WebKit/public/platform/WebString.h" |
| +#include "third_party/WebKit/public/platform/WebURL.h" |
| +#include "third_party/WebKit/public/platform/WebVector.h" |
| +#include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandle.h" |
| +#include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandleClient.h" |
| +#include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandshakeRequestInfo.h" |
| +#include "third_party/WebKit/public/platform/modules/websockets/WebSocketHandshakeResponseInfo.h" |
| +#include "url/gurl.h" |
| +#include "url/origin.h" |
| + |
| +using blink::WebSecurityOrigin; |
| +using blink::WebSocketHandle; |
| +using blink::WebSocketHandleClient; |
| +using blink::WebString; |
| +using blink::WebURL; |
| +using blink::WebVector; |
| + |
| +namespace content { |
| +namespace { |
| + |
| +const uint16_t kAbnormalShutdownOpCode = 1006; |
| + |
| +} // namespace |
| + |
| +WebSocketHandleImpl::WebSocketHandleImpl( |
| + blink::ServiceRegistry* service_registry, |
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
| + : client_(nullptr), |
| + client_binding_(this), |
| + task_runner_(std::move(task_runner)), |
| + render_frame_id_(MSG_ROUTING_NONE) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " created"; |
| + |
| + service_registry->connectToRemoteService(mojo::GetProxy(&websocket_)); |
| + |
| + websocket_.set_connection_error_handler( |
| + base::Bind(&WebSocketHandleImpl::OnConnectionError, |
| + base::Unretained(this))); |
| +} |
| + |
| +void WebSocketHandleImpl::connect(const WebURL& url, |
| + const WebVector<WebString>& protocols, |
| + const WebSecurityOrigin& origin, |
| + const WebURL& first_party_for_cookies, |
| + const WebString& user_agent_override, |
| + WebSocketHandleClient* client) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " Connect(" << url << ", " << origin.toString().utf8() << ")"; |
| + |
| + DCHECK(websocket_); |
| + |
| + DCHECK(!client_); |
| + DCHECK(client); |
| + client_ = client; |
| + |
| + mojo::Array<mojo::String> protocols_to_pass(protocols.size()); |
| + for (size_t i = 0; i < protocols.size(); ++i) |
| + protocols_to_pass[i] = protocols[i].utf8(); |
| + |
| + websocket_->AddChannelRequest( |
| + url, |
| + std::move(protocols_to_pass), |
| + origin, |
| + first_party_for_cookies, |
| + user_agent_override.latin1(), |
| + render_frame_id_, |
| + client_binding_.CreateInterfacePtrAndBind(task_runner_)); |
| +} |
| + |
| +void WebSocketHandleImpl::send(bool fin, |
| + WebSocketHandle::MessageType type, |
| + const char* data, |
| + size_t size) { |
| + DCHECK(websocket_); |
| + |
| + mojom::WebSocketMessageType type_to_pass; |
| + switch (type) { |
| + case WebSocketHandle::MessageTypeContinuation: |
| + type_to_pass = mojom::WebSocketMessageType::CONTINUATION; |
| + break; |
| + case WebSocketHandle::MessageTypeText: |
| + type_to_pass = mojom::WebSocketMessageType::TEXT; |
| + break; |
| + case WebSocketHandle::MessageTypeBinary: |
| + type_to_pass = mojom::WebSocketMessageType::BINARY; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " Send(" << fin << ", " << type_to_pass << ", " |
| + << "(data size = " << size << "))"; |
| + |
| + mojo::Array<uint8_t> data_to_pass(size); |
| + std::copy(data, data + size, data_to_pass.begin()); |
| + |
| + websocket_->SendFrame(fin, type_to_pass, std::move(data_to_pass)); |
| +} |
| + |
| +void WebSocketHandleImpl::flowControl(int64_t quota) { |
| + DCHECK(websocket_); |
| + |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " FlowControl(" << quota << ")"; |
| + |
| + websocket_->SendFlowControl(quota); |
| +} |
| + |
| +void WebSocketHandleImpl::close(unsigned short code, const WebString& reason) { |
| + DCHECK(websocket_); |
| + |
| + std::string reason_to_pass = reason.utf8(); |
| + |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " Close(" << code << ", " << reason_to_pass << ")"; |
| + |
| + websocket_->StartClosingHandshake(code, reason_to_pass); |
| +} |
| + |
| +WebSocketHandleImpl::~WebSocketHandleImpl() { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " deleted"; |
| + |
| + if (websocket_) |
| + websocket_->StartClosingHandshake(kAbnormalShutdownOpCode, std::string()); |
| +} |
| + |
| +void WebSocketHandleImpl::Disconnect() { |
| + websocket_.reset(); |
| + client_ = nullptr; |
| +} |
| + |
| +void WebSocketHandleImpl::OnConnectionError() { |
| + // Our connection to the WebSocket was dropped. This could be due to |
| + // exceeding the maximum number of concurrent websockets from this process. |
| + |
| + // TODO(darin): This error message is overly specific. We don't know for sure |
| + // that this is the only reason we'd get here. This should be more generic or |
| + // we should figure out how to make it more specific. |
| + OnFailChannel("Error in connection establishment: " |
| + "net::ERR_INSUFFICIENT_RESOURCES"); |
| +} |
| + |
| +void WebSocketHandleImpl::OnFailChannel(const mojo::String& message) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnFailChannel(" << message << ")"; |
| + |
| + WebSocketHandleClient* client = client_; |
| + Disconnect(); |
| + if (!client) |
| + return; |
| + |
| + client->didFail(this, WebString::fromUTF8(message)); |
| + // |this| can be deleted here. |
| +} |
| + |
| +void WebSocketHandleImpl::OnStartOpeningHandshake( |
| + mojom::WebSocketHandshakeRequestPtr request) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnStartOpeningHandshake(" << request->url << ")"; |
| + // All strings are already encoded to ASCII in the browser. |
| + blink::WebSocketHandshakeRequestInfo request_to_pass; |
| + request_to_pass.setURL(WebURL(request->url)); |
| + for (size_t i = 0; i < request->headers.size(); ++i) { |
| + const mojom::HttpHeaderPtr& header = request->headers[i]; |
| + request_to_pass.addHeaderField(WebString::fromLatin1(header->name), |
| + WebString::fromLatin1(header->value)); |
| + } |
| + request_to_pass.setHeadersText(WebString::fromLatin1(request->headers_text)); |
| + client_->didStartOpeningHandshake(this, request_to_pass); |
| +} |
| + |
| +void WebSocketHandleImpl::OnFinishOpeningHandshake( |
| + mojom::WebSocketHandshakeResponsePtr response) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnFinishOpeningHandshake(" << response->url << ")"; |
| + |
| + // All strings are already encoded to ASCII in the browser. |
| + blink::WebSocketHandshakeResponseInfo response_to_pass; |
| + response_to_pass.setStatusCode(response->status_code); |
| + response_to_pass.setStatusText(WebString::fromLatin1(response->status_text)); |
| + for (size_t i = 0; i < response->headers.size(); ++i) { |
| + const mojom::HttpHeaderPtr& header = response->headers[i]; |
| + response_to_pass.addHeaderField(WebString::fromLatin1(header->name), |
| + WebString::fromLatin1(header->value)); |
| + } |
| + response_to_pass.setHeadersText( |
| + WebString::fromLatin1(response->headers_text)); |
| + client_->didFinishOpeningHandshake(this, response_to_pass); |
| +} |
| + |
| +void WebSocketHandleImpl::OnAddChannelResponse( |
| + const mojo::String& protocol, |
| + const mojo::String& extensions) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnAddChannelResponse(" |
| + << protocol << ", " << extensions << ")"; |
| + |
| + if (!client_) |
| + return; |
| + |
| + client_->didConnect(this, |
| + WebString::fromUTF8(protocol), |
| + WebString::fromUTF8(extensions)); |
| + // |this| can be deleted here. |
| +} |
| + |
| +void WebSocketHandleImpl::OnDataFrame( |
| + bool fin, mojom::WebSocketMessageType type, |
| + mojo::Array<uint8_t> data) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnDataFrame(" << fin << ", " << type << ", " |
| + << "(data size = " << data.size() << "))"; |
| + if (!client_) |
| + return; |
| + |
| + WebSocketHandle::MessageType type_to_pass = |
| + WebSocketHandle::MessageTypeContinuation; |
| + switch (type) { |
| + case mojom::WebSocketMessageType::CONTINUATION: |
| + type_to_pass = WebSocketHandle::MessageTypeContinuation; |
| + break; |
| + case mojom::WebSocketMessageType::TEXT: |
| + type_to_pass = WebSocketHandle::MessageTypeText; |
| + break; |
| + case mojom::WebSocketMessageType::BINARY: |
| + type_to_pass = WebSocketHandle::MessageTypeBinary; |
| + break; |
| + } |
| + const char* data_to_pass = |
| + reinterpret_cast<const char*>(data.empty() ? nullptr : &data[0]); |
| + client_->didReceiveData(this, fin, type_to_pass, data_to_pass, data.size()); |
| + // |this| can be deleted here. |
| +} |
| + |
| +void WebSocketHandleImpl::OnFlowControl(int64_t quota) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnFlowControl(" << quota << ")"; |
| + if (!client_) |
| + return; |
| + |
| + client_->didReceiveFlowControl(this, quota); |
| + // |this| can be deleted here. |
| +} |
| + |
| +void WebSocketHandleImpl::OnDropChannel(bool was_clean, uint16_t code, |
| + const mojo::String& reason) { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnDropChannel(" << was_clean << ", " << code << ", " |
| + << reason << ")"; |
| + |
| + WebSocketHandleClient* client = client_; |
| + Disconnect(); |
| + if (!client) |
| + return; |
| + |
| + client->didClose(this, was_clean, code, WebString::fromUTF8(reason)); |
| + // |this| can be deleted here. |
| +} |
| + |
| +void WebSocketHandleImpl::OnClosingHandshake() { |
| + DVLOG(1) << "WebSocketHandleImpl @" << reinterpret_cast<void*>(this) |
| + << " OnClosingHandshake()"; |
| + if (!client_) |
| + return; |
| + |
| + client_->didStartClosingHandshake(this); |
| + // |this| can be deleted here. |
| +} |
| + |
| +} // namespace content |