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

Side by Side Diff: net/websockets/websocket_job_test.cc

Issue 221833002: Test for WebSocketJob being deleted on the stack (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Explicitly confirm that the WebSocketJob object is no longer referenced at the end of each test. Created 6 years, 8 months 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
« no previous file with comments | « net/websockets/websocket_job.cc ('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 2013 The Chromium Authors. All rights reserved. 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 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 "net/websockets/websocket_job.h" 5 #include "net/websockets/websocket_job.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 309
310 private: 310 private:
311 OrderedSocketData* data_; 311 OrderedSocketData* data_;
312 scoped_ptr<SpdySessionDependencies> session_deps_; 312 scoped_ptr<SpdySessionDependencies> session_deps_;
313 scoped_refptr<HttpNetworkSession> http_session_; 313 scoped_refptr<HttpNetworkSession> http_session_;
314 base::WeakPtr<SpdySession> session_; 314 base::WeakPtr<SpdySession> session_;
315 HostPortPair host_port_pair_; 315 HostPortPair host_port_pair_;
316 SpdySessionKey spdy_session_key_; 316 SpdySessionKey spdy_session_key_;
317 }; 317 };
318 318
319 class DeletingSocketStreamDelegate : public SocketStream::Delegate {
320 public:
321 DeletingSocketStreamDelegate()
322 : delete_next_(false) {}
323
324 // Since this class needs to be able to delete |job_|, it must be the only
325 // reference holder (except for temporary references). Provide access to the
326 // pointer for tests to use.
327 WebSocketJob* job() { return job_.get(); }
328
329 void set_job(WebSocketJob* job) { job_ = job; }
330
331 // After calling this, the next call to a method on this delegate will delete
332 // the WebSocketJob object.
333 void set_delete_next(bool delete_next) { delete_next_ = delete_next; }
334
335 void DeleteJobMaybe() {
336 if (delete_next_) {
337 job_->DetachContext();
338 job_->DetachDelegate();
339 job_ = NULL;
340 }
341 }
342
343 // SocketStream::Delegate implementation
344
345 // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost
346
347 virtual void OnConnected(SocketStream* socket,
348 int max_pending_send_allowed) OVERRIDE {
349 DeleteJobMaybe();
350 }
351
352 virtual void OnSentData(SocketStream* socket, int amount_sent) OVERRIDE {
353 DeleteJobMaybe();
354 }
355
356 virtual void OnReceivedData(SocketStream* socket,
357 const char* data,
358 int len) OVERRIDE {
359 DeleteJobMaybe();
360 }
361
362 virtual void OnClose(SocketStream* socket) OVERRIDE { DeleteJobMaybe(); }
363
364 virtual void OnAuthRequired(SocketStream* socket,
365 AuthChallengeInfo* auth_info) OVERRIDE {
366 DeleteJobMaybe();
367 }
368
369 virtual void OnSSLCertificateError(SocketStream* socket,
370 const SSLInfo& ssl_info,
371 bool fatal) OVERRIDE {
372 DeleteJobMaybe();
373 }
374
375 virtual void OnError(const SocketStream* socket, int error) OVERRIDE {
376 DeleteJobMaybe();
377 }
378
379 // CanGetCookies() and CanSetCookies() do not appear to be able to delete the
380 // WebSocketJob object.
381
382 private:
383 scoped_refptr<WebSocketJob> job_;
384 bool delete_next_;
385 };
386
319 } // namespace 387 } // namespace
320 388
321 class WebSocketJobTest : public PlatformTest, 389 class WebSocketJobTest : public PlatformTest,
322 public ::testing::WithParamInterface<NextProto> { 390 public ::testing::WithParamInterface<NextProto> {
323 public: 391 public:
324 WebSocketJobTest() : spdy_util_(GetParam()) {} 392 WebSocketJobTest() : spdy_util_(GetParam()) {}
325 393
326 virtual void SetUp() OVERRIDE { 394 virtual void SetUp() OVERRIDE {
327 stream_type_ = STREAM_INVALID; 395 stream_type_ = STREAM_INVALID;
328 cookie_store_ = new MockCookieStore; 396 cookie_store_ = new MockCookieStore;
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 static const char* const kHandshakeResponseForSpdy[]; 541 static const char* const kHandshakeResponseForSpdy[];
474 static const size_t kHandshakeRequestWithoutCookieLength; 542 static const size_t kHandshakeRequestWithoutCookieLength;
475 static const size_t kHandshakeRequestWithCookieLength; 543 static const size_t kHandshakeRequestWithCookieLength;
476 static const size_t kHandshakeRequestWithFilteredCookieLength; 544 static const size_t kHandshakeRequestWithFilteredCookieLength;
477 static const size_t kHandshakeResponseWithoutCookieLength; 545 static const size_t kHandshakeResponseWithoutCookieLength;
478 static const size_t kHandshakeResponseWithCookieLength; 546 static const size_t kHandshakeResponseWithCookieLength;
479 static const size_t kDataHelloLength; 547 static const size_t kDataHelloLength;
480 static const size_t kDataWorldLength; 548 static const size_t kDataWorldLength;
481 }; 549 };
482 550
551 // Tests using this fixture verify that the WebSocketJob can handle being
552 // deleted while calling back to the delegate correctly. These tests need to be
553 // run under AddressSanitizer or other systems for detecting use-after-free
554 // errors in order to find problems.
555 class WebSocketJobDeleteTest : public ::testing::Test {
556 protected:
557 WebSocketJobDeleteTest()
558 : delegate_(new DeletingSocketStreamDelegate),
559 cookie_store_(new MockCookieStore),
560 context_(new MockURLRequestContext(cookie_store_.get())) {
561 WebSocketJob* websocket = new WebSocketJob(delegate_.get());
562 delegate_->set_job(websocket);
563
564 socket_ = new MockSocketStream(
565 GURL("ws://127.0.0.1/"), websocket, context_.get(), NULL);
566
567 websocket->InitSocketStream(socket_.get());
568 }
569
570 void SetDeleteNext() { return delegate_->set_delete_next(true); }
571 WebSocketJob* job() { return delegate_->job(); }
572
573 scoped_ptr<DeletingSocketStreamDelegate> delegate_;
574 scoped_refptr<MockCookieStore> cookie_store_;
575 scoped_ptr<MockURLRequestContext> context_;
576 scoped_refptr<SocketStream> socket_;
577 };
578
483 const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] = 579 const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] =
484 "GET /demo HTTP/1.1\r\n" 580 "GET /demo HTTP/1.1\r\n"
485 "Host: example.com\r\n" 581 "Host: example.com\r\n"
486 "Upgrade: WebSocket\r\n" 582 "Upgrade: WebSocket\r\n"
487 "Connection: Upgrade\r\n" 583 "Connection: Upgrade\r\n"
488 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" 584 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
489 "Origin: http://example.com\r\n" 585 "Origin: http://example.com\r\n"
490 "Sec-WebSocket-Protocol: sample\r\n" 586 "Sec-WebSocket-Protocol: sample\r\n"
491 "Sec-WebSocket-Version: 13\r\n" 587 "Sec-WebSocket-Version: 13\r\n"
492 "\r\n"; 588 "\r\n";
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after
1115 TEST_P(WebSocketJobTest, ThrottlingSpdy) { 1211 TEST_P(WebSocketJobTest, ThrottlingSpdy) {
1116 WebSocketJob::set_websocket_over_spdy_enabled(false); 1212 WebSocketJob::set_websocket_over_spdy_enabled(false);
1117 TestConnectBySpdy(SPDY_OFF, THROTTLING_ON); 1213 TestConnectBySpdy(SPDY_OFF, THROTTLING_ON);
1118 } 1214 }
1119 1215
1120 TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) { 1216 TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) {
1121 WebSocketJob::set_websocket_over_spdy_enabled(true); 1217 WebSocketJob::set_websocket_over_spdy_enabled(true);
1122 TestConnectBySpdy(SPDY_ON, THROTTLING_ON); 1218 TestConnectBySpdy(SPDY_ON, THROTTLING_ON);
1123 } 1219 }
1124 1220
1221 TEST_F(WebSocketJobDeleteTest, OnClose) {
1222 SetDeleteNext();
1223 // This one is tricky because OnClose() sets WebSocketJob::_socket to NULL,
1224 // so detaching it from within DeletingSocketStreamDelegate::DeleteJobMaybe()
1225 // doesn't work. Detach it first to prevent a DCHECK(!delegate_) failure in
1226 // the SocketStream destructor.
1227 socket_->DetachDelegate();
tyoshino (SeeGerritForStatus) 2014/04/04 04:39:07 is this done by some code before OnClose() is call
Adam Rice 2014/04/04 06:00:36 It appears OnClose() is called by real code only i
tyoshino (SeeGerritForStatus) 2014/04/04 06:04:45 Ah, right! Thanks for explanation.
1228 job()->OnClose(socket_.get());
1229 EXPECT_FALSE(job());
1230 }
1231
1232 TEST_F(WebSocketJobDeleteTest, OnAuthRequired) {
1233 SetDeleteNext();
1234 job()->OnAuthRequired(socket_.get(), NULL);
1235 EXPECT_FALSE(job());
1236 }
1237
1238 TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) {
1239 SSLInfo ssl_info;
1240 SetDeleteNext();
1241 job()->OnSSLCertificateError(socket_.get(), ssl_info, true);
1242 EXPECT_FALSE(job());
1243 }
1244
1245 TEST_F(WebSocketJobDeleteTest, OnError) {
1246 SetDeleteNext();
1247 job()->OnError(socket_.get(), ERR_CONNECTION_RESET);
1248 EXPECT_FALSE(job());
1249 }
1250
1251 TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) {
1252 job()->Connect();
1253 SetDeleteNext();
1254 job()->OnSentSpdyHeaders();
1255 EXPECT_FALSE(job());
1256 }
1257
1258 TEST_F(WebSocketJobDeleteTest, OnSentHandshakeRequest) {
1259 static const char kMinimalRequest[] =
1260 "GET /demo HTTP/1.1\r\n"
1261 "Host: example.com\r\n"
1262 "Upgrade: WebSocket\r\n"
1263 "Connection: Upgrade\r\n"
1264 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
1265 "Origin: http://example.com\r\n"
1266 "Sec-WebSocket-Version: 13\r\n"
1267 "\r\n";
1268 const size_t kMinimalRequestSize = arraysize(kMinimalRequest) - 1;
1269 job()->Connect();
1270 job()->SendData(kMinimalRequest, kMinimalRequestSize);
1271 SetDeleteNext();
1272 job()->OnSentData(socket_.get(), kMinimalRequestSize);
1273 EXPECT_FALSE(job());
1274 }
1275
1276 TEST_F(WebSocketJobDeleteTest, NotifyHeadersComplete) {
1277 static const char kMinimalResponse[] =
1278 "HTTP/1.1 101 Switching Protocols\r\n"
1279 "Upgrade: websocket\r\n"
1280 "Connection: Upgrade\r\n"
1281 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
1282 "\r\n";
1283 job()->Connect();
1284 SetDeleteNext();
1285 job()->OnReceivedData(
1286 socket_.get(), kMinimalResponse, arraysize(kMinimalResponse) - 1);
1287 EXPECT_FALSE(job());
1288 }
1289
1125 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation. 1290 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
1126 // TODO(toyoshim,yutak): Add tests to verify closing handshake. 1291 // TODO(toyoshim,yutak): Add tests to verify closing handshake.
1127 } // namespace net 1292 } // namespace net
OLDNEW
« no previous file with comments | « net/websockets/websocket_job.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698