Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: webkit/plugins/ppapi/ppb_websocket_impl.cc

Issue 8558017: WebSocket Pepper API: in process API implementation (reland) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed reviewed points Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/plugins/ppapi/ppb_websocket_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "webkit/plugins/ppapi/ppb_websocket_impl.h" 5 #include "webkit/plugins/ppapi/ppb_websocket_impl.h"
6 6
7 #include <string>
8
9 #include "base/logging.h"
10 #include "googleurl/src/gurl.h"
11 #include "net/base/net_util.h"
12 #include "ppapi/c/pp_completion_callback.h"
7 #include "ppapi/c/pp_errors.h" 13 #include "ppapi/c/pp_errors.h"
8 #include "ppapi/c/pp_var.h" 14 #include "ppapi/c/pp_var.h"
15 #include "ppapi/c/ppb_var.h"
16 #include "ppapi/cpp/module.h"
17 #include "ppapi/shared_impl/var.h"
18 #include "ppapi/shared_impl/var_tracker.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebData.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSocket.h"
25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
26 #include "webkit/plugins/ppapi/host_globals.h"
27 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
28 #include "webkit/plugins/ppapi/resource_helper.h"
9 29
30 using ppapi::PpapiGlobals;
31 using ppapi::StringVar;
10 using ppapi::thunk::PPB_WebSocket_API; 32 using ppapi::thunk::PPB_WebSocket_API;
33 using ppapi::VarTracker;
34 using WebKit::WebData;
35 using WebKit::WebDocument;
36 using WebKit::WebString;
37 using WebKit::WebSocket;
38 using WebKit::WebSocketClient;
39 using WebKit::WebURL;
40
41 static const uint32_t kMaxReasonSizeInBytes = 123;
11 42
12 namespace webkit { 43 namespace webkit {
13 namespace ppapi { 44 namespace ppapi {
14 45
15 PPB_WebSocket_Impl::PPB_WebSocket_Impl(PP_Instance instance) 46 PPB_WebSocket_Impl::PPB_WebSocket_Impl(PP_Instance instance)
16 : Resource(instance) { 47 : Resource(instance),
48 state_(PP_WEBSOCKETREADYSTATE_INVALID_DEV),
49 receive_callback_var_(NULL),
50 wait_for_receive_(false),
51 close_code_(0),
52 close_was_clean_(PP_FALSE) {
53 empty_string_ = new StringVar(pp::Module::Get()->pp_module(), "", 0);
17 } 54 }
18 55
19 PPB_WebSocket_Impl::~PPB_WebSocket_Impl() { 56 PPB_WebSocket_Impl::~PPB_WebSocket_Impl() {
57 if (websocket_.get())
58 websocket_->disconnect();
59
60 // Clean up received and unread messages
61 VarTracker* var_tracker = PpapiGlobals::Get()->GetVarTracker();
62 while (!received_messages_.empty()) {
63 PP_Var var = received_messages_.front();
64 received_messages_.pop();
65 var_tracker->ReleaseVar(var);
66 }
20 } 67 }
21 68
22 // static 69 // static
23 PP_Resource PPB_WebSocket_Impl::Create(PP_Instance instance) { 70 PP_Resource PPB_WebSocket_Impl::Create(PP_Instance instance) {
24 scoped_refptr<PPB_WebSocket_Impl> ws(new PPB_WebSocket_Impl(instance)); 71 scoped_refptr<PPB_WebSocket_Impl> ws(new PPB_WebSocket_Impl(instance));
25 return ws->GetReference(); 72 return ws->GetReference();
26 } 73 }
27 74
28 PPB_WebSocket_API* PPB_WebSocket_Impl::AsPPB_WebSocket_API() { 75 PPB_WebSocket_API* PPB_WebSocket_Impl::AsPPB_WebSocket_API() {
29 return this; 76 return this;
30 } 77 }
31 78
32 int32_t PPB_WebSocket_Impl::Connect(PP_Var url, 79 int32_t PPB_WebSocket_Impl::Connect(PP_Var url,
33 const PP_Var protocols[], 80 const PP_Var protocols[],
34 uint32_t protocol_count, 81 uint32_t protocol_count,
35 PP_CompletionCallback callback) { 82 PP_CompletionCallback callback) {
36 // TODO(toyoshim): Implement it. 83 // Check mandatory interfaces.
37 return PP_ERROR_NOTSUPPORTED; 84 PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(this);
85 DCHECK(plugin_instance);
86 if (!plugin_instance)
87 return PP_ERROR_FAILED;
88
89 // Connect() can be called at most once.
90 if (websocket_.get())
91 return PP_ERROR_INPROGRESS;
92 if (state_ != PP_WEBSOCKETREADYSTATE_INVALID_DEV)
93 return PP_ERROR_INPROGRESS;
94 state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV;
95
96 // Validate |callback| (Doesn't support blocking callback)
97 if (!callback.func)
98 return PP_ERROR_BLOCKS_MAIN_THREAD;
99
100 // Validate url and convert it to WebURL.
101 scoped_refptr<StringVar> url_string = StringVar::FromPPVar(url);
102 if (!url_string)
103 return PP_ERROR_BADARGUMENT;
104 GURL gurl(url_string->value());
105 if (!gurl.is_valid())
106 return PP_ERROR_BADARGUMENT;
107 if (!gurl.SchemeIs("ws") && !gurl.SchemeIs("wss"))
108 return PP_ERROR_BADARGUMENT;
109 if (gurl.has_ref())
110 return PP_ERROR_BADARGUMENT;
111 if (!net::IsPortAllowedByDefault(gurl.IntPort()))
112 return PP_ERROR_BADARGUMENT;
113 WebURL web_url(gurl);
114
115 // Validate protocols and convert it to WebString.
116 // TODO(toyoshim): Detect duplicated protocols as error.
117 std::string protocol_string;
118 for (uint32_t i = 0; i < protocol_count; i++) {
119 // TODO(toyoshim): Similar function exist in WebKit::WebSocket.
120 // We must rearrange them into WebKit::WebChannel and share its protocol
121 // related implementation via WebKit API.
122 scoped_refptr<StringVar> string_var;
123 string_var = StringVar::FromPPVar(protocols[i]);
124 if (!string_var->value().length())
125 return PP_ERROR_BADARGUMENT;
dmichael (off chromium) 2011/11/24 04:32:36 Shouldn't we also check that string_var is valid (
Takashi Toyoshima 2011/11/25 05:42:48 Done.
126 for (std::string::const_iterator it = string_var->value().begin();
127 it != string_var->value().end();
128 ++it) {
129 uint8_t character = static_cast<uint8_t>(*it);
130 // WebSocket specification says "(Subprotocol string must consist of)
131 // characters in the range U+0021 to U+007E not including separator
132 // characters as defined in [RFC2616]."
133 const uint8_t minimumProtocolCharacter = '!'; // U+0021.
134 const uint8_t maximumProtocolCharacter = '~'; // U+007E.
135 if (character < minimumProtocolCharacter ||
136 character > maximumProtocolCharacter ||
137 character == '"' || character == '(' || character == ')' ||
138 character == ',' || character == '/' ||
139 (character >= ':' && character <= '@') || // U+003A - U+0040
140 (character >= '[' && character <= ']') || // U+005B - u+005D
141 character == '{' || character == '}')
142 return PP_ERROR_BADARGUMENT;
143 }
144 if (i != 0)
145 protocol_string.append(",");
146 protocol_string.append(string_var->value());
147 }
148 WebString web_protocols = WebString::fromUTF8(protocol_string);
149
150 // Create WebKit::WebSocket object.
151 WebDocument document = plugin_instance->container()->element().document();
152 websocket_.reset(WebSocket::create(document, this));
153 DCHECK(websocket_.get());
154 if (!websocket_.get())
155 return PP_ERROR_NOTSUPPORTED;
156
157 websocket_->connect(web_url, web_protocols);
158 state_ = PP_WEBSOCKETREADYSTATE_CONNECTING_DEV;
159
160 // Install callback.
161 connect_callback_ = callback;
162
163 return PP_OK_COMPLETIONPENDING;
38 } 164 }
39 165
40 int32_t PPB_WebSocket_Impl::Close(uint16_t code, 166 int32_t PPB_WebSocket_Impl::Close(uint16_t code,
41 PP_Var reason, 167 PP_Var reason,
42 PP_CompletionCallback callback) { 168 PP_CompletionCallback callback) {
43 // TODO(toyoshim): Implement it. 169 // Check mandarory interfaces.
44 return PP_ERROR_NOTSUPPORTED; 170 if (!websocket_.get())
171 return PP_ERROR_FAILED;
172
173 // Validate |callback| (Doesn't support blocking callback)
174 if (!callback.func)
175 return PP_ERROR_BLOCKS_MAIN_THREAD;
176
177 // Validate |code|.
178 if (code != WebSocket::CloseEventCodeNotSpecified) {
179 if (!(code == WebSocket::CloseEventCodeNormalClosure ||
180 (WebSocket::CloseEventCodeMinimumUserDefined <= code &&
181 code <= WebSocket::CloseEventCodeMaximumUserDefined)))
182 return PP_ERROR_NOACCESS;
183 }
184 // Validate |reason|.
185 // TODO(toyoshim): Returns PP_ERROR_BADARGUMENT if |reason| contains any
186 // surrogates.
187 scoped_refptr<StringVar> reason_string = StringVar::FromPPVar(reason);
188 if (!reason_string || reason_string->value().size() > kMaxReasonSizeInBytes)
189 return PP_ERROR_BADARGUMENT;
190
191 // Check state.
192 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING_DEV ||
193 state_ == PP_WEBSOCKETREADYSTATE_CLOSED_DEV)
194 return PP_ERROR_INPROGRESS;
195
196 // Install |callback|.
197 close_callback_ = callback;
198
199 if (state_ == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV) {
200 state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV;
201 PP_RunAndClearCompletionCallback(&connect_callback_, PP_ERROR_ABORTED);
202 websocket_->fail(
203 "WebSocket was closed before the connection was established.");
204 return PP_OK_COMPLETIONPENDING;
205 }
206
207 // TODO(toyoshim): Handle bufferedAmount here.
208
209 state_ = PP_WEBSOCKETREADYSTATE_CLOSING_DEV;
210 WebString web_reason = WebString::fromUTF8(reason_string->value());
211 websocket_->close(code, web_reason);
212
213 return PP_OK_COMPLETIONPENDING;
45 } 214 }
46 215
47 int32_t PPB_WebSocket_Impl::ReceiveMessage(PP_Var* message, 216 int32_t PPB_WebSocket_Impl::ReceiveMessage(PP_Var* message,
48 PP_CompletionCallback callback) { 217 PP_CompletionCallback callback) {
49 // TODO(toyoshim): Implement it. 218 // Check state.
50 return PP_ERROR_NOTSUPPORTED; 219 if (state_ == PP_WEBSOCKETREADYSTATE_INVALID_DEV ||
220 state_ == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV)
221 return PP_ERROR_BADARGUMENT;
222
223 // Just return received message if any received message is queued.
224 if (!received_messages_.empty())
225 return DoReceive();
226
227 // Or retain |message| as buffer to store and install |callback|.
228 wait_for_receive_ = true;
229 receive_callback_var_ = message;
230 receive_callback_ = callback;
231
232 return PP_OK_COMPLETIONPENDING;
51 } 233 }
52 234
53 int32_t PPB_WebSocket_Impl::SendMessage(PP_Var message) { 235 int32_t PPB_WebSocket_Impl::SendMessage(PP_Var message) {
54 // TODO(toyoshim): Implement it. 236 // Check mandatory interfaces.
55 return PP_ERROR_NOTSUPPORTED; 237 if (!websocket_.get())
238 return PP_ERROR_FAILED;
239
240 // Check state.
241 if (state_ == PP_WEBSOCKETREADYSTATE_INVALID_DEV ||
242 state_ == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV)
243 return PP_ERROR_BADARGUMENT;
244
245 if (state_ == PP_WEBSOCKETREADYSTATE_CLOSING_DEV ||
246 state_ == PP_WEBSOCKETREADYSTATE_CLOSED_DEV) {
247 // TODO(toyoshim): Handle bufferedAmount here.
248 }
249
250 if (message.type != PP_VARTYPE_STRING) {
251 // TODO(toyoshim): Support binary data.
252 return PP_ERROR_NOTSUPPORTED;
253 }
254
255 // Convert message to WebString.
256 scoped_refptr<StringVar> message_string = StringVar::FromPPVar(message);
257 if (!message_string)
258 return PP_ERROR_BADARGUMENT;
259 WebString web_message = WebString::fromUTF8(message_string->value());
260 if (!websocket_->sendText(web_message))
261 return PP_ERROR_BADARGUMENT;
262
263 return PP_OK;
56 } 264 }
57 265
58 uint64_t PPB_WebSocket_Impl::GetBufferedAmount() { 266 uint64_t PPB_WebSocket_Impl::GetBufferedAmount() {
59 // TODO(toyoshim): Implement it. 267 // TODO(toyoshim): Implement.
60 return 0; 268 return 0;
61 } 269 }
62 270
63 uint16_t PPB_WebSocket_Impl::GetCloseCode() { 271 uint16_t PPB_WebSocket_Impl::GetCloseCode() {
64 // TODO(toyoshim): Implement it. 272 return close_code_;
65 return 0;
66 } 273 }
67 274
68 PP_Var PPB_WebSocket_Impl::GetCloseReason() { 275 PP_Var PPB_WebSocket_Impl::GetCloseReason() {
69 // TODO(toyoshim): Implement it. 276 if (!close_reason_)
70 return PP_MakeUndefined(); 277 return empty_string_->GetPPVar();
278 return close_reason_->GetPPVar();
71 } 279 }
72 280
73 PP_Bool PPB_WebSocket_Impl::GetCloseWasClean() { 281 PP_Bool PPB_WebSocket_Impl::GetCloseWasClean() {
74 // TODO(toyoshim): Implement it. 282 return close_was_clean_;
75 return PP_FALSE;
76 } 283 }
77 284
78 PP_Var PPB_WebSocket_Impl::GetExtensions() { 285 PP_Var PPB_WebSocket_Impl::GetExtensions() {
79 // TODO(toyoshim): Implement it. 286 // TODO(toyoshim): For now, always returns empty string.
80 return PP_MakeUndefined(); 287 if (!extensions_)
288 return empty_string_->GetPPVar();
289 return extensions_->GetPPVar();
81 } 290 }
82 291
83 PP_Var PPB_WebSocket_Impl::GetProtocol() { 292 PP_Var PPB_WebSocket_Impl::GetProtocol() {
84 // TODO(toyoshim): Implement it. 293 // TODO(toyoshim): Implement.
85 return PP_MakeUndefined(); 294 if (!protocol_)
295 return empty_string_->GetPPVar();
296 return protocol_->GetPPVar();
86 } 297 }
87 298
88 PP_WebSocketReadyState_Dev PPB_WebSocket_Impl::GetReadyState() { 299 PP_WebSocketReadyState_Dev PPB_WebSocket_Impl::GetReadyState() {
89 // TODO(toyoshim): Implement it. 300 return state_;
90 return PP_WEBSOCKETREADYSTATE_INVALID_DEV;
91 } 301 }
92 302
93 PP_Var PPB_WebSocket_Impl::GetURL() { 303 PP_Var PPB_WebSocket_Impl::GetURL() {
94 // TODO(toyoshim): Implement it. 304 // TODO(toyoshim): For now, always returns empty string.
95 return PP_MakeUndefined(); 305 if (!url_)
306 return empty_string_->GetPPVar();
307 return url_->GetPPVar();
308 }
309
310 void PPB_WebSocket_Impl::didConnect() {
311 DCHECK_EQ(PP_WEBSOCKETREADYSTATE_CONNECTING_DEV, state_);
312 state_ = PP_WEBSOCKETREADYSTATE_OPEN_DEV;
313 PP_RunAndClearCompletionCallback(&connect_callback_, PP_OK);
314 }
315
316 void PPB_WebSocket_Impl::didReceiveMessage(const WebString& message) {
317 // Append received data to queue.
318 std::string string = message.utf8();
319 PP_Var var = StringVar::StringToPPVar(
320 pp::Module::Get()->pp_module(), string);
321 received_messages_.push(var);
322
323 if (!wait_for_receive_)
324 return;
325
326 PP_RunAndClearCompletionCallback(&receive_callback_, DoReceive());
327 }
328
329 void PPB_WebSocket_Impl::didReceiveBinaryData(const WebData& binaryData) {
330 DLOG(INFO) << "didReceiveBinaryData is not implemented yet.";
331 // TODO(toyoshim): Support to receive binary data.
332 }
333
334 void PPB_WebSocket_Impl::didReceiveMessageError() {
335 // TODO(toyoshim): Must implement.
336 DLOG(INFO) << "didReceiveMessageError is not implemented yet.";
337 }
338
339 void PPB_WebSocket_Impl::didStartClosingHandshake() {
340 // TODO(toyoshim): Must implement.
341 DLOG(INFO) << "didStartClosingHandshake is not implemented yet.";
342 }
343
344 void PPB_WebSocket_Impl::didClose(unsigned long bufferedAmount,
345 ClosingHandshakeCompletionStatus status,
346 unsigned short code,
347 const WebString& reason) {
348 // Store code and reason.
349 close_code_ = code;
350 std::string reason_string = reason.utf8();
351 close_reason_ = new StringVar(pp::Module::Get()->pp_module(), reason_string);
352
353 // TODO(toyoshim): Set close_was_clean_.
354
355 // Handle state transition and invoking callback.
356 DCHECK_NE(PP_WEBSOCKETREADYSTATE_CLOSED_DEV, state_);
357 PP_WebSocketReadyState_Dev state = state_;
358 state_ = PP_WEBSOCKETREADYSTATE_CLOSED_DEV;
359
360 if (state == PP_WEBSOCKETREADYSTATE_CONNECTING_DEV)
361 PP_RunAndClearCompletionCallback(&connect_callback_, PP_OK);
362
363 if (state == PP_WEBSOCKETREADYSTATE_CLOSING_DEV)
364 PP_RunAndClearCompletionCallback(&close_callback_, PP_OK);
365 }
366
367 int32_t PPB_WebSocket_Impl::DoReceive() {
368 // TODO(toyoshim): Check state.
369
370 if (!receive_callback_var_)
371 return PP_OK;
372
373 *receive_callback_var_ = received_messages_.front();
374 received_messages_.pop();
375 receive_callback_var_ = NULL;
376 wait_for_receive_ = false;
377 return PP_OK;
96 } 378 }
97 379
98 } // namespace ppapi 380 } // namespace ppapi
99 } // namespace webkit 381 } // namespace webkit
OLDNEW
« no previous file with comments | « webkit/plugins/ppapi/ppb_websocket_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698