OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <string> | 5 #include <string> |
6 #include <vector> | 6 #include <vector> |
7 | 7 |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
(...skipping 2139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2150 ASSERT_TRUE(response != NULL); | 2150 ASSERT_TRUE(response != NULL); |
2151 EXPECT_TRUE(response->headers.get() != NULL); | 2151 EXPECT_TRUE(response->headers.get() != NULL); |
2152 EXPECT_TRUE(response->was_fetched_via_spdy); | 2152 EXPECT_TRUE(response->was_fetched_via_spdy); |
2153 std::string response_data; | 2153 std::string response_data; |
2154 rv = ReadTransaction(trans, &response_data); | 2154 rv = ReadTransaction(trans, &response_data); |
2155 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); | 2155 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); |
2156 | 2156 |
2157 helper.VerifyDataConsumed(); | 2157 helper.VerifyDataConsumed(); |
2158 } | 2158 } |
2159 | 2159 |
2160 // Test that sent data frames and received WINDOW_UPDATE frames change | |
2161 // the send_window_size_ correctly. | |
2162 | |
2163 // WINDOW_UPDATE is different than most other frames in that it can arrive | |
2164 // while the client is still sending the request body. In order to enforce | |
2165 // this scenario, we feed a couple of dummy frames and give a delay of 0 to | |
2166 // socket data provider, so that initial read that is done as soon as the | |
2167 // stream is created, succeeds and schedules another read. This way reads | |
2168 // and writes are interleaved; after doing a full frame write, SpdyStream | |
2169 // will break out of DoLoop and will read and process a WINDOW_UPDATE. | |
2170 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away | |
2171 // since request has not been completely written, therefore we feed | |
2172 // enough number of WINDOW_UPDATEs to finish the first read and cause a | |
2173 // write, leading to a complete write of request body; after that we send | |
2174 // a reply with a body, to cause a graceful shutdown. | |
2175 | |
2176 // TODO(agayev): develop a socket data provider where both, reads and | |
2177 // writes are ordered so that writing tests like these are easy and rewrite | |
2178 // all these tests using it. Right now we are working around the | |
2179 // limitations as described above and it's not deterministic, tests may | |
2180 // fail under specific circumstances. | |
2181 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) { | |
2182 if (GetParam().protocol < kProtoSPDY3) | |
2183 return; | |
2184 | |
2185 static int kFrameCount = 2; | |
2186 scoped_ptr<std::string> content( | |
2187 new std::string(kMaxSpdyFrameChunkSize, 'a')); | |
2188 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
2189 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0)); | |
2190 scoped_ptr<SpdyFrame> body( | |
2191 spdy_util_.ConstructSpdyBodyFrame( | |
2192 1, content->c_str(), content->size(), false)); | |
2193 scoped_ptr<SpdyFrame> body_end( | |
2194 spdy_util_.ConstructSpdyBodyFrame( | |
2195 1, content->c_str(), content->size(), true)); | |
2196 | |
2197 MockWrite writes[] = { | |
2198 CreateMockWrite(*req, 0), | |
2199 CreateMockWrite(*body, 1), | |
2200 CreateMockWrite(*body_end, 2), | |
2201 }; | |
2202 | |
2203 static const int32 kDeltaWindowSize = 0xff; | |
2204 static const int kDeltaCount = 4; | |
2205 scoped_ptr<SpdyFrame> window_update( | |
2206 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); | |
2207 scoped_ptr<SpdyFrame> window_update_dummy( | |
2208 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize)); | |
2209 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
2210 MockRead reads[] = { | |
2211 CreateMockRead(*window_update_dummy, 3), | |
2212 CreateMockRead(*window_update_dummy, 4), | |
2213 CreateMockRead(*window_update_dummy, 5), | |
2214 CreateMockRead(*window_update, 6), // Four updates, therefore window | |
2215 CreateMockRead(*window_update, 7), // size should increase by | |
2216 CreateMockRead(*window_update, 8), // kDeltaWindowSize * 4 | |
2217 CreateMockRead(*window_update, 9), | |
2218 CreateMockRead(*resp, 10), | |
2219 CreateMockRead(*body_end, 11), | |
2220 MockRead(ASYNC, 0, 0, 12) // EOF | |
2221 }; | |
2222 | |
2223 DeterministicSocketData data(reads, arraysize(reads), | |
2224 writes, arraysize(writes)); | |
2225 | |
2226 ScopedVector<UploadElementReader> element_readers; | |
2227 for (int i = 0; i < kFrameCount; ++i) { | |
2228 element_readers.push_back( | |
2229 new UploadBytesElementReader(content->c_str(), content->size())); | |
2230 } | |
2231 UploadDataStream upload_data_stream(&element_readers, 0); | |
2232 | |
2233 // Setup the request | |
2234 HttpRequestInfo request; | |
2235 request.method = "POST"; | |
2236 request.url = GURL(kDefaultURL); | |
2237 request.upload_data_stream = &upload_data_stream; | |
2238 | |
2239 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
2240 BoundNetLog(), GetParam(), NULL); | |
2241 helper.SetDeterministic(); | |
2242 helper.AddDeterministicData(&data); | |
2243 helper.RunPreTestSetup(); | |
2244 | |
2245 HttpNetworkTransaction* trans = helper.trans(); | |
2246 | |
2247 TestCompletionCallback callback; | |
2248 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2249 | |
2250 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2251 | |
2252 data.RunFor(11); | |
2253 | |
2254 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
2255 ASSERT_TRUE(stream != NULL); | |
2256 ASSERT_TRUE(stream->stream() != NULL); | |
2257 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize) + | |
2258 kDeltaWindowSize * kDeltaCount - | |
2259 kMaxSpdyFrameChunkSize * kFrameCount, | |
2260 stream->stream()->send_window_size()); | |
2261 | |
2262 data.RunFor(1); | |
2263 | |
2264 rv = callback.WaitForResult(); | |
2265 EXPECT_EQ(OK, rv); | |
2266 | |
2267 helper.VerifyDataConsumed(); | |
2268 } | |
2269 | |
2270 // Test that received data frames and sent WINDOW_UPDATE frames change | |
2271 // the recv_window_size_ correctly. | |
2272 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) { | |
2273 if (GetParam().protocol < kProtoSPDY3) | |
2274 return; | |
2275 | |
2276 // Set the data in the body frame large enough to trigger sending a | |
2277 // WINDOW_UPDATE by the stream. | |
2278 const std::string body_data(kSpdyStreamInitialWindowSize / 2 + 1, 'x'); | |
2279 | |
2280 scoped_ptr<SpdyFrame> req( | |
2281 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2282 scoped_ptr<SpdyFrame> session_window_update( | |
2283 spdy_util_.ConstructSpdyWindowUpdate(0, body_data.size())); | |
2284 scoped_ptr<SpdyFrame> window_update( | |
2285 spdy_util_.ConstructSpdyWindowUpdate(1, body_data.size())); | |
2286 | |
2287 std::vector<MockWrite> writes; | |
2288 writes.push_back(CreateMockWrite(*req)); | |
2289 if (GetParam().protocol >= kProtoSPDY31) | |
2290 writes.push_back(CreateMockWrite(*session_window_update)); | |
2291 writes.push_back(CreateMockWrite(*window_update)); | |
2292 | |
2293 scoped_ptr<SpdyFrame> resp( | |
2294 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2295 scoped_ptr<SpdyFrame> body_no_fin( | |
2296 spdy_util_.ConstructSpdyBodyFrame( | |
2297 1, body_data.data(), body_data.size(), false)); | |
2298 scoped_ptr<SpdyFrame> body_fin( | |
2299 spdy_util_.ConstructSpdyBodyFrame(1, NULL, 0, true)); | |
2300 MockRead reads[] = { | |
2301 CreateMockRead(*resp), | |
2302 CreateMockRead(*body_no_fin), | |
2303 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause | |
2304 CreateMockRead(*body_fin), | |
2305 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause | |
2306 MockRead(ASYNC, 0, 0) // EOF | |
2307 }; | |
2308 | |
2309 DelayedSocketData data(1, reads, arraysize(reads), | |
2310 vector_as_array(&writes), writes.size()); | |
2311 | |
2312 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2313 BoundNetLog(), GetParam(), NULL); | |
2314 helper.AddData(&data); | |
2315 helper.RunPreTestSetup(); | |
2316 HttpNetworkTransaction* trans = helper.trans(); | |
2317 | |
2318 TestCompletionCallback callback; | |
2319 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2320 | |
2321 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2322 rv = callback.WaitForResult(); | |
2323 EXPECT_EQ(OK, rv); | |
2324 | |
2325 SpdyHttpStream* stream = | |
2326 static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
2327 ASSERT_TRUE(stream != NULL); | |
2328 ASSERT_TRUE(stream->stream() != NULL); | |
2329 | |
2330 EXPECT_EQ( | |
2331 static_cast<int>(kSpdyStreamInitialWindowSize - body_data.size()), | |
2332 stream->stream()->recv_window_size()); | |
2333 | |
2334 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2335 ASSERT_TRUE(response != NULL); | |
2336 ASSERT_TRUE(response->headers.get() != NULL); | |
2337 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
2338 EXPECT_TRUE(response->was_fetched_via_spdy); | |
2339 | |
2340 // Issue a read which will cause a WINDOW_UPDATE to be sent and window | |
2341 // size increased to default. | |
2342 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(body_data.size())); | |
2343 rv = trans->Read(buf.get(), body_data.size(), CompletionCallback()); | |
2344 EXPECT_EQ(static_cast<int>(body_data.size()), rv); | |
2345 std::string content(buf->data(), buf->data() + body_data.size()); | |
2346 EXPECT_EQ(body_data, content); | |
2347 | |
2348 // Schedule the reading of empty data frame with FIN | |
2349 data.CompleteRead(); | |
2350 | |
2351 // Force write of WINDOW_UPDATE which was scheduled during the above | |
2352 // read. | |
2353 base::MessageLoop::current()->RunUntilIdle(); | |
2354 | |
2355 // Read EOF. | |
2356 data.CompleteRead(); | |
2357 | |
2358 helper.VerifyDataConsumed(); | |
2359 } | |
2360 | |
2361 // Test that WINDOW_UPDATE frame causing overflow is handled correctly. | |
2362 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) { | |
2363 if (GetParam().protocol < kProtoSPDY3) | |
2364 return; | |
2365 | |
2366 // Number of full frames we hope to write (but will not, used to | |
2367 // set content-length header correctly) | |
2368 static int kFrameCount = 3; | |
2369 | |
2370 scoped_ptr<std::string> content( | |
2371 new std::string(kMaxSpdyFrameChunkSize, 'a')); | |
2372 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
2373 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0)); | |
2374 scoped_ptr<SpdyFrame> body( | |
2375 spdy_util_.ConstructSpdyBodyFrame( | |
2376 1, content->c_str(), content->size(), false)); | |
2377 scoped_ptr<SpdyFrame> rst( | |
2378 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR)); | |
2379 | |
2380 // We're not going to write a data frame with FIN, we'll receive a bad | |
2381 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame. | |
2382 MockWrite writes[] = { | |
2383 CreateMockWrite(*req, 0), | |
2384 CreateMockWrite(*body, 2), | |
2385 CreateMockWrite(*rst, 3), | |
2386 }; | |
2387 | |
2388 static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow | |
2389 scoped_ptr<SpdyFrame> window_update( | |
2390 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); | |
2391 MockRead reads[] = { | |
2392 CreateMockRead(*window_update, 1), | |
2393 MockRead(ASYNC, 0, 4) // EOF | |
2394 }; | |
2395 | |
2396 DeterministicSocketData data(reads, arraysize(reads), | |
2397 writes, arraysize(writes)); | |
2398 | |
2399 ScopedVector<UploadElementReader> element_readers; | |
2400 for (int i = 0; i < kFrameCount; ++i) { | |
2401 element_readers.push_back( | |
2402 new UploadBytesElementReader(content->c_str(), content->size())); | |
2403 } | |
2404 UploadDataStream upload_data_stream(&element_readers, 0); | |
2405 | |
2406 // Setup the request | |
2407 HttpRequestInfo request; | |
2408 request.method = "POST"; | |
2409 request.url = GURL("http://www.google.com/"); | |
2410 request.upload_data_stream = &upload_data_stream; | |
2411 | |
2412 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
2413 BoundNetLog(), GetParam(), NULL); | |
2414 helper.SetDeterministic(); | |
2415 helper.RunPreTestSetup(); | |
2416 helper.AddDeterministicData(&data); | |
2417 HttpNetworkTransaction* trans = helper.trans(); | |
2418 | |
2419 TestCompletionCallback callback; | |
2420 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2421 ASSERT_EQ(ERR_IO_PENDING, rv); | |
2422 | |
2423 data.RunFor(5); | |
2424 ASSERT_TRUE(callback.have_result()); | |
2425 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, callback.WaitForResult()); | |
2426 helper.VerifyDataConsumed(); | |
2427 } | |
2428 | |
2429 // Test that after hitting a send window size of 0, the write process | |
2430 // stalls and upon receiving WINDOW_UPDATE frame write resumes. | |
2431 | |
2432 // This test constructs a POST request followed by enough data frames | |
2433 // containing 'a' that would make the window size 0, followed by another | |
2434 // data frame containing default content (which is "hello!") and this frame | |
2435 // also contains a FIN flag. DelayedSocketData is used to enforce all | |
2436 // writes go through before a read could happen. However, the last frame | |
2437 // ("hello!") is not supposed to go through since by the time its turn | |
2438 // arrives, window size is 0. At this point MessageLoop::Run() called via | |
2439 // callback would block. Therefore we call MessageLoop::RunUntilIdle() | |
2440 // which returns after performing all possible writes. We use DCHECKS to | |
2441 // ensure that last data frame is still there and stream has stalled. | |
2442 // After that, next read is artifically enforced, which causes a | |
2443 // WINDOW_UPDATE to be read and I/O process resumes. | |
2444 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) { | |
2445 if (GetParam().protocol < kProtoSPDY3) | |
2446 return; | |
2447 | |
2448 // Number of frames we need to send to zero out the window size: data | |
2449 // frames plus SYN_STREAM plus the last data frame; also we need another | |
2450 // data frame that we will send once the WINDOW_UPDATE is received, | |
2451 // therefore +3. | |
2452 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; | |
2453 | |
2454 // Calculate last frame's size; 0 size data frame is legal. | |
2455 size_t last_frame_size = | |
2456 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; | |
2457 | |
2458 // Construct content for a data frame of maximum size. | |
2459 std::string content(kMaxSpdyFrameChunkSize, 'a'); | |
2460 | |
2461 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
2462 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, | |
2463 LOWEST, NULL, 0)); | |
2464 | |
2465 // Full frames. | |
2466 scoped_ptr<SpdyFrame> body1( | |
2467 spdy_util_.ConstructSpdyBodyFrame( | |
2468 1, content.c_str(), content.size(), false)); | |
2469 | |
2470 // Last frame to zero out the window size. | |
2471 scoped_ptr<SpdyFrame> body2( | |
2472 spdy_util_.ConstructSpdyBodyFrame( | |
2473 1, content.c_str(), last_frame_size, false)); | |
2474 | |
2475 // Data frame to be sent once WINDOW_UPDATE frame is received. | |
2476 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2477 | |
2478 // Fill in mock writes. | |
2479 scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]); | |
2480 size_t i = 0; | |
2481 writes[i] = CreateMockWrite(*req); | |
2482 for (i = 1; i < num_writes - 2; i++) | |
2483 writes[i] = CreateMockWrite(*body1); | |
2484 writes[i++] = CreateMockWrite(*body2); | |
2485 writes[i] = CreateMockWrite(*body3); | |
2486 | |
2487 // Construct read frame, give enough space to upload the rest of the | |
2488 // data. | |
2489 scoped_ptr<SpdyFrame> session_window_update( | |
2490 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize)); | |
2491 scoped_ptr<SpdyFrame> window_update( | |
2492 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize)); | |
2493 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
2494 MockRead reads[] = { | |
2495 CreateMockRead(*session_window_update), | |
2496 CreateMockRead(*session_window_update), | |
2497 CreateMockRead(*window_update), | |
2498 CreateMockRead(*window_update), | |
2499 CreateMockRead(*reply), | |
2500 CreateMockRead(*body2), | |
2501 CreateMockRead(*body3), | |
2502 MockRead(ASYNC, 0, 0) // EOF | |
2503 }; | |
2504 | |
2505 // Skip the session window updates unless we're using SPDY/3.1 and | |
2506 // above. | |
2507 size_t read_offset = (GetParam().protocol >= kProtoSPDY31) ? 0 : 2; | |
2508 size_t num_reads = arraysize(reads) - read_offset; | |
2509 | |
2510 // Force all writes to happen before any read, last write will not | |
2511 // actually queue a frame, due to window size being 0. | |
2512 DelayedSocketData data(num_writes, reads + read_offset, num_reads, | |
2513 writes.get(), num_writes); | |
2514 | |
2515 ScopedVector<UploadElementReader> element_readers; | |
2516 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); | |
2517 upload_data_string.append(kUploadData, kUploadDataSize); | |
2518 element_readers.push_back(new UploadBytesElementReader( | |
2519 upload_data_string.c_str(), upload_data_string.size())); | |
2520 UploadDataStream upload_data_stream(&element_readers, 0); | |
2521 | |
2522 HttpRequestInfo request; | |
2523 request.method = "POST"; | |
2524 request.url = GURL("http://www.google.com/"); | |
2525 request.upload_data_stream = &upload_data_stream; | |
2526 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
2527 BoundNetLog(), GetParam(), NULL); | |
2528 helper.AddData(&data); | |
2529 helper.RunPreTestSetup(); | |
2530 | |
2531 HttpNetworkTransaction* trans = helper.trans(); | |
2532 | |
2533 TestCompletionCallback callback; | |
2534 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2535 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2536 | |
2537 base::MessageLoop::current()->RunUntilIdle(); // Write as much as we can. | |
2538 | |
2539 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
2540 ASSERT_TRUE(stream != NULL); | |
2541 ASSERT_TRUE(stream->stream() != NULL); | |
2542 EXPECT_EQ(0, stream->stream()->send_window_size()); | |
2543 // All the body data should have been read. | |
2544 // TODO(satorux): This is because of the weirdness in reading the request | |
2545 // body in OnSendBodyComplete(). See crbug.com/113107. | |
2546 EXPECT_TRUE(upload_data_stream.IsEOF()); | |
2547 // But the body is not yet fully sent (kUploadData is not yet sent) | |
2548 // since we're send-stalled. | |
2549 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); | |
2550 | |
2551 data.ForceNextRead(); // Read in WINDOW_UPDATE frame. | |
2552 rv = callback.WaitForResult(); | |
2553 helper.VerifyDataConsumed(); | |
2554 } | |
2555 | |
2556 // Test we correctly handle the case where the SETTINGS frame results in | |
2557 // unstalling the send window. | |
2558 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) { | |
2559 if (GetParam().protocol < kProtoSPDY3) | |
2560 return; | |
2561 | |
2562 // Number of frames we need to send to zero out the window size: data | |
2563 // frames plus SYN_STREAM plus the last data frame; also we need another | |
2564 // data frame that we will send once the SETTING is received, therefore +3. | |
2565 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; | |
2566 | |
2567 // Calculate last frame's size; 0 size data frame is legal. | |
2568 size_t last_frame_size = | |
2569 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; | |
2570 | |
2571 // Construct content for a data frame of maximum size. | |
2572 std::string content(kMaxSpdyFrameChunkSize, 'a'); | |
2573 | |
2574 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
2575 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, | |
2576 LOWEST, NULL, 0)); | |
2577 | |
2578 // Full frames. | |
2579 scoped_ptr<SpdyFrame> body1( | |
2580 spdy_util_.ConstructSpdyBodyFrame( | |
2581 1, content.c_str(), content.size(), false)); | |
2582 | |
2583 // Last frame to zero out the window size. | |
2584 scoped_ptr<SpdyFrame> body2( | |
2585 spdy_util_.ConstructSpdyBodyFrame( | |
2586 1, content.c_str(), last_frame_size, false)); | |
2587 | |
2588 // Data frame to be sent once SETTINGS frame is received. | |
2589 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2590 | |
2591 // Fill in mock reads/writes. | |
2592 std::vector<MockRead> reads; | |
2593 std::vector<MockWrite> writes; | |
2594 size_t i = 0; | |
2595 writes.push_back(CreateMockWrite(*req, i++)); | |
2596 while (i < num_writes - 2) | |
2597 writes.push_back(CreateMockWrite(*body1, i++)); | |
2598 writes.push_back(CreateMockWrite(*body2, i++)); | |
2599 | |
2600 // Construct read frame for SETTINGS that gives enough space to upload the | |
2601 // rest of the data. | |
2602 SettingsMap settings; | |
2603 settings[SETTINGS_INITIAL_WINDOW_SIZE] = | |
2604 SettingsFlagsAndValue( | |
2605 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize * 2); | |
2606 scoped_ptr<SpdyFrame> settings_frame_large( | |
2607 spdy_util_.ConstructSpdySettings(settings)); | |
2608 | |
2609 reads.push_back(CreateMockRead(*settings_frame_large, i++)); | |
2610 | |
2611 scoped_ptr<SpdyFrame> session_window_update( | |
2612 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize)); | |
2613 if (GetParam().protocol >= kProtoSPDY31) | |
2614 reads.push_back(CreateMockRead(*session_window_update, i++)); | |
2615 | |
2616 writes.push_back(CreateMockWrite(*body3, i++)); | |
2617 | |
2618 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
2619 reads.push_back(CreateMockRead(*reply, i++)); | |
2620 reads.push_back(CreateMockRead(*body2, i++)); | |
2621 reads.push_back(CreateMockRead(*body3, i++)); | |
2622 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF | |
2623 | |
2624 // Force all writes to happen before any read, last write will not | |
2625 // actually queue a frame, due to window size being 0. | |
2626 DeterministicSocketData data(vector_as_array(&reads), reads.size(), | |
2627 vector_as_array(&writes), writes.size()); | |
2628 | |
2629 ScopedVector<UploadElementReader> element_readers; | |
2630 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); | |
2631 upload_data_string.append(kUploadData, kUploadDataSize); | |
2632 element_readers.push_back(new UploadBytesElementReader( | |
2633 upload_data_string.c_str(), upload_data_string.size())); | |
2634 UploadDataStream upload_data_stream(&element_readers, 0); | |
2635 | |
2636 HttpRequestInfo request; | |
2637 request.method = "POST"; | |
2638 request.url = GURL("http://www.google.com/"); | |
2639 request.upload_data_stream = &upload_data_stream; | |
2640 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
2641 BoundNetLog(), GetParam(), NULL); | |
2642 helper.SetDeterministic(); | |
2643 helper.RunPreTestSetup(); | |
2644 helper.AddDeterministicData(&data); | |
2645 | |
2646 HttpNetworkTransaction* trans = helper.trans(); | |
2647 | |
2648 TestCompletionCallback callback; | |
2649 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2650 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2651 | |
2652 data.RunFor(num_writes - 1); // Write as much as we can. | |
2653 | |
2654 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
2655 ASSERT_TRUE(stream != NULL); | |
2656 ASSERT_TRUE(stream->stream() != NULL); | |
2657 EXPECT_EQ(0, stream->stream()->send_window_size()); | |
2658 | |
2659 // All the body data should have been read. | |
2660 // TODO(satorux): This is because of the weirdness in reading the request | |
2661 // body in OnSendBodyComplete(). See crbug.com/113107. | |
2662 EXPECT_TRUE(upload_data_stream.IsEOF()); | |
2663 // But the body is not yet fully sent (kUploadData is not yet sent) | |
2664 // since we're send-stalled. | |
2665 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); | |
2666 | |
2667 data.RunFor(6); // Read in SETTINGS frame to unstall. | |
2668 rv = callback.WaitForResult(); | |
2669 helper.VerifyDataConsumed(); | |
2670 // If stream is NULL, that means it was unstalled and closed. | |
2671 EXPECT_TRUE(stream->stream() == NULL); | |
2672 } | |
2673 | |
2674 // Test we correctly handle the case where the SETTINGS frame results in a | |
2675 // negative send window size. | |
2676 TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) { | |
2677 if (GetParam().protocol < kProtoSPDY3) | |
2678 return; | |
2679 | |
2680 // Number of frames we need to send to zero out the window size: data | |
2681 // frames plus SYN_STREAM plus the last data frame; also we need another | |
2682 // data frame that we will send once the SETTING is received, therefore +3. | |
2683 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; | |
2684 | |
2685 // Calculate last frame's size; 0 size data frame is legal. | |
2686 size_t last_frame_size = | |
2687 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; | |
2688 | |
2689 // Construct content for a data frame of maximum size. | |
2690 std::string content(kMaxSpdyFrameChunkSize, 'a'); | |
2691 | |
2692 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
2693 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, | |
2694 LOWEST, NULL, 0)); | |
2695 | |
2696 // Full frames. | |
2697 scoped_ptr<SpdyFrame> body1( | |
2698 spdy_util_.ConstructSpdyBodyFrame( | |
2699 1, content.c_str(), content.size(), false)); | |
2700 | |
2701 // Last frame to zero out the window size. | |
2702 scoped_ptr<SpdyFrame> body2( | |
2703 spdy_util_.ConstructSpdyBodyFrame( | |
2704 1, content.c_str(), last_frame_size, false)); | |
2705 | |
2706 // Data frame to be sent once SETTINGS frame is received. | |
2707 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2708 | |
2709 // Fill in mock reads/writes. | |
2710 std::vector<MockRead> reads; | |
2711 std::vector<MockWrite> writes; | |
2712 size_t i = 0; | |
2713 writes.push_back(CreateMockWrite(*req, i++)); | |
2714 while (i < num_writes - 2) | |
2715 writes.push_back(CreateMockWrite(*body1, i++)); | |
2716 writes.push_back(CreateMockWrite(*body2, i++)); | |
2717 | |
2718 // Construct read frame for SETTINGS that makes the send_window_size | |
2719 // negative. | |
2720 SettingsMap new_settings; | |
2721 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = | |
2722 SettingsFlagsAndValue( | |
2723 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize / 2); | |
2724 scoped_ptr<SpdyFrame> settings_frame_small( | |
2725 spdy_util_.ConstructSpdySettings(new_settings)); | |
2726 // Construct read frames for WINDOW_UPDATE that makes the send_window_size | |
2727 // positive. | |
2728 scoped_ptr<SpdyFrame> session_window_update_init_size( | |
2729 spdy_util_.ConstructSpdyWindowUpdate(0, kSpdyStreamInitialWindowSize)); | |
2730 scoped_ptr<SpdyFrame> window_update_init_size( | |
2731 spdy_util_.ConstructSpdyWindowUpdate(1, kSpdyStreamInitialWindowSize)); | |
2732 | |
2733 reads.push_back(CreateMockRead(*settings_frame_small, i++)); | |
2734 | |
2735 if (GetParam().protocol >= kProtoSPDY3) | |
2736 reads.push_back(CreateMockRead(*session_window_update_init_size, i++)); | |
2737 | |
2738 reads.push_back(CreateMockRead(*window_update_init_size, i++)); | |
2739 | |
2740 writes.push_back(CreateMockWrite(*body3, i++)); | |
2741 | |
2742 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
2743 reads.push_back(CreateMockRead(*reply, i++)); | |
2744 reads.push_back(CreateMockRead(*body2, i++)); | |
2745 reads.push_back(CreateMockRead(*body3, i++)); | |
2746 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF | |
2747 | |
2748 // Force all writes to happen before any read, last write will not | |
2749 // actually queue a frame, due to window size being 0. | |
2750 DeterministicSocketData data(vector_as_array(&reads), reads.size(), | |
2751 vector_as_array(&writes), writes.size()); | |
2752 | |
2753 ScopedVector<UploadElementReader> element_readers; | |
2754 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); | |
2755 upload_data_string.append(kUploadData, kUploadDataSize); | |
2756 element_readers.push_back(new UploadBytesElementReader( | |
2757 upload_data_string.c_str(), upload_data_string.size())); | |
2758 UploadDataStream upload_data_stream(&element_readers, 0); | |
2759 | |
2760 HttpRequestInfo request; | |
2761 request.method = "POST"; | |
2762 request.url = GURL("http://www.google.com/"); | |
2763 request.upload_data_stream = &upload_data_stream; | |
2764 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
2765 BoundNetLog(), GetParam(), NULL); | |
2766 helper.SetDeterministic(); | |
2767 helper.RunPreTestSetup(); | |
2768 helper.AddDeterministicData(&data); | |
2769 | |
2770 HttpNetworkTransaction* trans = helper.trans(); | |
2771 | |
2772 TestCompletionCallback callback; | |
2773 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2774 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2775 | |
2776 data.RunFor(num_writes - 1); // Write as much as we can. | |
2777 | |
2778 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
2779 ASSERT_TRUE(stream != NULL); | |
2780 ASSERT_TRUE(stream->stream() != NULL); | |
2781 EXPECT_EQ(0, stream->stream()->send_window_size()); | |
2782 | |
2783 // All the body data should have been read. | |
2784 // TODO(satorux): This is because of the weirdness in reading the request | |
2785 // body in OnSendBodyComplete(). See crbug.com/113107. | |
2786 EXPECT_TRUE(upload_data_stream.IsEOF()); | |
2787 // But the body is not yet fully sent (kUploadData is not yet sent) | |
2788 // since we're send-stalled. | |
2789 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); | |
2790 | |
2791 // Read in WINDOW_UPDATE or SETTINGS frame. | |
2792 data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 8 : 7); | |
2793 rv = callback.WaitForResult(); | |
2794 helper.VerifyDataConsumed(); | |
2795 } | |
2796 | |
2797 TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) { | 2160 TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) { |
2798 // Construct the request. | 2161 // Construct the request. |
2799 scoped_ptr<SpdyFrame> req( | 2162 scoped_ptr<SpdyFrame> req( |
2800 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | 2163 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
2801 scoped_ptr<SpdyFrame> rst( | 2164 scoped_ptr<SpdyFrame> rst( |
2802 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | 2165 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); |
2803 MockWrite writes[] = { | 2166 MockWrite writes[] = { |
2804 CreateMockWrite(*req), | 2167 CreateMockWrite(*req), |
2805 CreateMockWrite(*rst), | 2168 CreateMockWrite(*rst), |
2806 }; | 2169 }; |
(...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3901 } | 3264 } |
3902 } | 3265 } |
3903 | 3266 |
3904 // Verify that various SynReply headers parse vary fields correctly | 3267 // Verify that various SynReply headers parse vary fields correctly |
3905 // through the HTTP layer, and the response matches the request. | 3268 // through the HTTP layer, and the response matches the request. |
3906 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) { | 3269 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) { |
3907 static const SpdyHeaderInfo syn_reply_info = { | 3270 static const SpdyHeaderInfo syn_reply_info = { |
3908 SYN_REPLY, // Syn Reply | 3271 SYN_REPLY, // Syn Reply |
3909 1, // Stream ID | 3272 1, // Stream ID |
3910 0, // Associated Stream ID | 3273 0, // Associated Stream ID |
| 3274 ConvertRequestPriorityToSpdyPriority( |
| 3275 LOWEST, spdy_util_.spdy_version()), |
| 3276 kSpdyCredentialSlotUnused, |
| 3277 CONTROL_FLAG_NONE, // Control Flags |
| 3278 false, // Compressed |
| 3279 RST_STREAM_INVALID, // Status |
| 3280 NULL, // Data |
| 3281 0, // Data Length |
| 3282 DATA_FLAG_NONE // Data Flags |
| 3283 }; |
| 3284 // Modify the following data to change/add test cases: |
| 3285 struct SynReplyTests { |
| 3286 const SpdyHeaderInfo* syn_reply; |
| 3287 bool vary_matches; |
| 3288 int num_headers[2]; |
| 3289 const char* extra_headers[2][16]; |
| 3290 } test_cases[] = { |
| 3291 // Test the case of a multi-valued cookie. When the value is delimited |
| 3292 // with NUL characters, it needs to be unfolded into multiple headers. |
| 3293 { |
| 3294 &syn_reply_info, |
| 3295 true, |
| 3296 { 1, 4 }, |
| 3297 { { "cookie", "val1,val2", |
| 3298 NULL |
| 3299 }, |
| 3300 { "vary", "cookie", |
| 3301 spdy_util_.GetStatusKey(), "200", |
| 3302 spdy_util_.GetPathKey(), "/index.php", |
| 3303 spdy_util_.GetVersionKey(), "HTTP/1.1", |
| 3304 NULL |
| 3305 } |
| 3306 } |
| 3307 }, { // Multiple vary fields. |
| 3308 &syn_reply_info, |
| 3309 true, |
| 3310 { 2, 5 }, |
| 3311 { { "friend", "barney", |
| 3312 "enemy", "snaggletooth", |
| 3313 NULL |
| 3314 }, |
| 3315 { "vary", "friend", |
| 3316 "vary", "enemy", |
| 3317 spdy_util_.GetStatusKey(), "200", |
| 3318 spdy_util_.GetPathKey(), "/index.php", |
| 3319 spdy_util_.GetVersionKey(), "HTTP/1.1", |
| 3320 NULL |
| 3321 } |
| 3322 } |
| 3323 }, { // Test a '*' vary field. |
| 3324 &syn_reply_info, |
| 3325 false, |
| 3326 { 1, 4 }, |
| 3327 { { "cookie", "val1,val2", |
| 3328 NULL |
| 3329 }, |
| 3330 { "vary", "*", |
| 3331 spdy_util_.GetStatusKey(), "200", |
| 3332 spdy_util_.GetPathKey(), "/index.php", |
| 3333 spdy_util_.GetVersionKey(), "HTTP/1.1", |
| 3334 NULL |
| 3335 } |
| 3336 } |
| 3337 }, { // Multiple comma-separated vary fields. |
| 3338 &syn_reply_info, |
| 3339 true, |
| 3340 { 2, 4 }, |
| 3341 { { "friend", "barney", |
| 3342 "enemy", "snaggletooth", |
| 3343 NULL |
| 3344 }, |
| 3345 { "vary", "friend,enemy", |
| 3346 spdy_util_.GetStatusKey(), "200", |
| 3347 spdy_util_.GetPathKey(), "/index.php", |
| 3348 spdy_util_.GetVersionKey(), "HTTP/1.1", |
| 3349 NULL |
| 3350 } |
| 3351 } |
| 3352 } |
| 3353 }; |
| 3354 |
| 3355 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 3356 // Construct the request. |
| 3357 scoped_ptr<SpdyFrame> frame_req( |
| 3358 spdy_util_.ConstructSpdyGet(test_cases[i].extra_headers[0], |
| 3359 test_cases[i].num_headers[0], |
| 3360 false, 1, LOWEST, true)); |
| 3361 |
| 3362 MockWrite writes[] = { |
| 3363 CreateMockWrite(*frame_req), |
| 3364 }; |
| 3365 |
| 3366 // Construct the reply. |
| 3367 scoped_ptr<SpdyFrame> frame_reply( |
| 3368 spdy_util_.ConstructSpdyFrame(*test_cases[i].syn_reply, |
| 3369 test_cases[i].extra_headers[1], |
| 3370 test_cases[i].num_headers[1], |
| 3371 NULL, |
| 3372 0)); |
| 3373 |
| 3374 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 3375 MockRead reads[] = { |
| 3376 CreateMockRead(*frame_reply), |
| 3377 CreateMockRead(*body), |
| 3378 MockRead(ASYNC, 0, 0) // EOF |
| 3379 }; |
| 3380 |
| 3381 // Attach the headers to the request. |
| 3382 int header_count = test_cases[i].num_headers[0]; |
| 3383 |
| 3384 HttpRequestInfo request = CreateGetRequest(); |
| 3385 for (int ct = 0; ct < header_count; ct++) { |
| 3386 const char* header_key = test_cases[i].extra_headers[0][ct * 2]; |
| 3387 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1]; |
| 3388 request.extra_headers.SetHeader(header_key, header_value); |
| 3389 } |
| 3390 |
| 3391 DelayedSocketData data(1, reads, arraysize(reads), |
| 3392 writes, arraysize(writes)); |
| 3393 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, |
| 3394 BoundNetLog(), GetParam(), NULL); |
| 3395 helper.RunToCompletion(&data); |
| 3396 TransactionHelperResult out = helper.output(); |
| 3397 |
| 3398 EXPECT_EQ(OK, out.rv) << i; |
| 3399 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i; |
| 3400 EXPECT_EQ("hello!", out.response_data) << i; |
| 3401 |
| 3402 // Test the response information. |
| 3403 EXPECT_TRUE(out.response_info.response_time > |
| 3404 out.response_info.request_time) << i; |
| 3405 base::TimeDelta test_delay = out.response_info.response_time - |
| 3406 out.response_info.request_time; |
| 3407 base::TimeDelta min_expected_delay; |
| 3408 min_expected_delay.FromMilliseconds(10); |
| 3409 EXPECT_GT(test_delay.InMillisecondsF(), |
| 3410 min_expected_delay.InMillisecondsF()) << i; |
| 3411 EXPECT_EQ(out.response_info.vary_data.is_valid(), |
| 3412 test_cases[i].vary_matches) << i; |
| 3413 |
| 3414 // Check the headers. |
| 3415 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; |
| 3416 ASSERT_TRUE(headers.get() != NULL) << i; |
| 3417 void* iter = NULL; |
| 3418 std::string name, value, lines; |
| 3419 while (headers->EnumerateHeaderLines(&iter, &name, &value)) { |
| 3420 lines.append(name); |
| 3421 lines.append(": "); |
| 3422 lines.append(value); |
| 3423 lines.append("\n"); |
| 3424 } |
| 3425 |
| 3426 // Construct the expected header reply string. |
| 3427 SpdyHeaderBlock reply_headers; |
| 3428 AppendToHeaderBlock(test_cases[i].extra_headers[1], |
| 3429 test_cases[i].num_headers[1], |
| 3430 &reply_headers); |
| 3431 std::string expected_reply = |
| 3432 spdy_util_.ConstructSpdyReplyString(reply_headers); |
| 3433 EXPECT_EQ(expected_reply, lines) << i; |
| 3434 } |
| 3435 } |
| 3436 |
| 3437 // Verify that we don't crash on invalid SynReply responses. |
| 3438 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) { |
| 3439 const SpdyHeaderInfo kSynStartHeader = { |
| 3440 SYN_REPLY, // Kind = SynReply |
| 3441 1, // Stream ID |
| 3442 0, // Associated stream ID |
| 3443 ConvertRequestPriorityToSpdyPriority( |
| 3444 LOWEST, spdy_util_.spdy_version()), |
| 3445 kSpdyCredentialSlotUnused, |
| 3446 CONTROL_FLAG_NONE, // Control Flags |
| 3447 false, // Compressed |
| 3448 RST_STREAM_INVALID, // Status |
| 3449 NULL, // Data |
| 3450 0, // Length |
| 3451 DATA_FLAG_NONE // Data Flags |
| 3452 }; |
| 3453 |
| 3454 struct InvalidSynReplyTests { |
| 3455 int num_headers; |
| 3456 const char* headers[10]; |
| 3457 } test_cases[] = { |
| 3458 // SYN_REPLY missing status header |
| 3459 { 4, |
| 3460 { "cookie", "val1", |
| 3461 "cookie", "val2", |
| 3462 spdy_util_.GetPathKey(), "/index.php", |
| 3463 spdy_util_.GetVersionKey(), "HTTP/1.1", |
| 3464 NULL |
| 3465 }, |
| 3466 }, |
| 3467 // SYN_REPLY missing version header |
| 3468 { 2, |
| 3469 { "status", "200", |
| 3470 spdy_util_.GetPathKey(), "/index.php", |
| 3471 NULL |
| 3472 }, |
| 3473 }, |
| 3474 // SYN_REPLY with no headers |
| 3475 { 0, { NULL }, }, |
| 3476 }; |
| 3477 |
| 3478 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 3479 scoped_ptr<SpdyFrame> req( |
| 3480 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 3481 scoped_ptr<SpdyFrame> rst( |
| 3482 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); |
| 3483 MockWrite writes[] = { |
| 3484 CreateMockWrite(*req), |
| 3485 CreateMockWrite(*rst), |
| 3486 }; |
| 3487 |
| 3488 scoped_ptr<SpdyFrame> resp( |
| 3489 spdy_util_.ConstructSpdyFrame(kSynStartHeader, |
| 3490 NULL, 0, |
| 3491 test_cases[i].headers, |
| 3492 test_cases[i].num_headers)); |
| 3493 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 3494 MockRead reads[] = { |
| 3495 CreateMockRead(*resp), |
| 3496 MockRead(ASYNC, 0, 0) // EOF |
| 3497 }; |
| 3498 |
| 3499 DelayedSocketData data(1, reads, arraysize(reads), |
| 3500 writes, arraysize(writes)); |
| 3501 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3502 BoundNetLog(), GetParam(), NULL); |
| 3503 helper.RunToCompletion(&data); |
| 3504 TransactionHelperResult out = helper.output(); |
| 3505 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); |
| 3506 } |
| 3507 } |
| 3508 |
| 3509 // Verify that we don't crash on some corrupt frames. |
| 3510 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) { |
| 3511 // This is the length field that's too short. |
| 3512 scoped_ptr<SpdyFrame> syn_reply_wrong_length( |
| 3513 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 3514 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
| 3515 size_t right_size = |
| 3516 (spdy_util_.spdy_version() < SPDY4) ? |
| 3517 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize() : |
| 3518 syn_reply_wrong_length->size(); |
| 3519 size_t wrong_size = right_size - 4; |
| 3520 test::SetFrameLength(syn_reply_wrong_length.get(), |
| 3521 wrong_size, |
| 3522 spdy_util_.spdy_version()); |
| 3523 |
| 3524 struct SynReplyTests { |
| 3525 const SpdyFrame* syn_reply; |
| 3526 } test_cases[] = { |
| 3527 { syn_reply_wrong_length.get(), }, |
| 3528 }; |
| 3529 |
| 3530 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { |
| 3531 scoped_ptr<SpdyFrame> req( |
| 3532 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 3533 MockWrite writes[] = { CreateMockWrite(*req), MockWrite(ASYNC, 0, 0) // EOF |
| 3534 }; |
| 3535 |
| 3536 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 3537 MockRead reads[] = { |
| 3538 MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size), |
| 3539 CreateMockRead(*body), |
| 3540 MockRead(ASYNC, 0, 0) // EOF |
| 3541 }; |
| 3542 |
| 3543 DelayedSocketData data(1, reads, arraysize(reads), |
| 3544 writes, arraysize(writes)); |
| 3545 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3546 BoundNetLog(), GetParam(), NULL); |
| 3547 helper.RunToCompletion(&data); |
| 3548 TransactionHelperResult out = helper.output(); |
| 3549 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); |
| 3550 } |
| 3551 } |
| 3552 |
| 3553 // Test that we shutdown correctly on write errors. |
| 3554 TEST_P(SpdyNetworkTransactionTest, WriteError) { |
| 3555 scoped_ptr<SpdyFrame> req( |
| 3556 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 3557 MockWrite writes[] = { |
| 3558 // We'll write 10 bytes successfully |
| 3559 MockWrite(ASYNC, req->data(), 10), |
| 3560 // Followed by ERROR! |
| 3561 MockWrite(ASYNC, ERR_FAILED), |
| 3562 }; |
| 3563 |
| 3564 DelayedSocketData data(2, NULL, 0, |
| 3565 writes, arraysize(writes)); |
| 3566 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3567 BoundNetLog(), GetParam(), NULL); |
| 3568 helper.RunToCompletion(&data); |
| 3569 TransactionHelperResult out = helper.output(); |
| 3570 EXPECT_EQ(ERR_FAILED, out.rv); |
| 3571 data.Reset(); |
| 3572 } |
| 3573 |
| 3574 // Test that partial writes work. |
| 3575 TEST_P(SpdyNetworkTransactionTest, PartialWrite) { |
| 3576 // Chop the SYN_STREAM frame into 5 chunks. |
| 3577 scoped_ptr<SpdyFrame> req( |
| 3578 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 3579 const int kChunks = 5; |
| 3580 scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks)); |
| 3581 |
| 3582 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 3583 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 3584 MockRead reads[] = { |
| 3585 CreateMockRead(*resp), |
| 3586 CreateMockRead(*body), |
| 3587 MockRead(ASYNC, 0, 0) // EOF |
| 3588 }; |
| 3589 |
| 3590 DelayedSocketData data(kChunks, reads, arraysize(reads), |
| 3591 writes.get(), kChunks); |
| 3592 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3593 BoundNetLog(), GetParam(), NULL); |
| 3594 helper.RunToCompletion(&data); |
| 3595 TransactionHelperResult out = helper.output(); |
| 3596 EXPECT_EQ(OK, out.rv); |
| 3597 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); |
| 3598 EXPECT_EQ("hello!", out.response_data); |
| 3599 } |
| 3600 |
| 3601 // In this test, we enable compression, but get a uncompressed SynReply from |
| 3602 // the server. Verify that teardown is all clean. |
| 3603 TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) { |
| 3604 scoped_ptr<SpdyFrame> compressed( |
| 3605 spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true)); |
| 3606 scoped_ptr<SpdyFrame> rst( |
| 3607 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); |
| 3608 MockWrite writes[] = { |
| 3609 CreateMockWrite(*compressed), |
| 3610 }; |
| 3611 |
| 3612 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 3613 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 3614 MockRead reads[] = { |
| 3615 CreateMockRead(*resp), |
| 3616 }; |
| 3617 |
| 3618 DelayedSocketData data(1, reads, arraysize(reads), |
| 3619 writes, arraysize(writes)); |
| 3620 SpdySessionDependencies* session_deps = |
| 3621 CreateSpdySessionDependencies(GetParam()); |
| 3622 session_deps->enable_compression = true; |
| 3623 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3624 BoundNetLog(), GetParam(), session_deps); |
| 3625 helper.RunToCompletion(&data); |
| 3626 TransactionHelperResult out = helper.output(); |
| 3627 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); |
| 3628 data.Reset(); |
| 3629 } |
| 3630 |
| 3631 // Test that the NetLog contains good data for a simple GET request. |
| 3632 TEST_P(SpdyNetworkTransactionTest, NetLog) { |
| 3633 static const char* const kExtraHeaders[] = { |
| 3634 "user-agent", "Chrome", |
| 3635 }; |
| 3636 scoped_ptr<SpdyFrame> req( |
| 3637 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true)); |
| 3638 MockWrite writes[] = { CreateMockWrite(*req) }; |
| 3639 |
| 3640 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 3641 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 3642 MockRead reads[] = { |
| 3643 CreateMockRead(*resp), |
| 3644 CreateMockRead(*body), |
| 3645 MockRead(ASYNC, 0, 0) // EOF |
| 3646 }; |
| 3647 |
| 3648 CapturingBoundNetLog log; |
| 3649 |
| 3650 DelayedSocketData data(1, reads, arraysize(reads), |
| 3651 writes, arraysize(writes)); |
| 3652 NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(), |
| 3653 DEFAULT_PRIORITY, |
| 3654 log.bound(), GetParam(), NULL); |
| 3655 helper.RunToCompletion(&data); |
| 3656 TransactionHelperResult out = helper.output(); |
| 3657 EXPECT_EQ(OK, out.rv); |
| 3658 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); |
| 3659 EXPECT_EQ("hello!", out.response_data); |
| 3660 |
| 3661 // Check that the NetLog was filled reasonably. |
| 3662 // This test is intentionally non-specific about the exact ordering of the |
| 3663 // log; instead we just check to make sure that certain events exist, and that |
| 3664 // they are in the right order. |
| 3665 net::CapturingNetLog::CapturedEntryList entries; |
| 3666 log.GetEntries(&entries); |
| 3667 |
| 3668 EXPECT_LT(0u, entries.size()); |
| 3669 int pos = 0; |
| 3670 pos = net::ExpectLogContainsSomewhere(entries, 0, |
| 3671 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, |
| 3672 net::NetLog::PHASE_BEGIN); |
| 3673 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, |
| 3674 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, |
| 3675 net::NetLog::PHASE_END); |
| 3676 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, |
| 3677 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, |
| 3678 net::NetLog::PHASE_BEGIN); |
| 3679 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, |
| 3680 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, |
| 3681 net::NetLog::PHASE_END); |
| 3682 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, |
| 3683 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, |
| 3684 net::NetLog::PHASE_BEGIN); |
| 3685 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, |
| 3686 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, |
| 3687 net::NetLog::PHASE_END); |
| 3688 |
| 3689 // Check that we logged all the headers correctly |
| 3690 pos = net::ExpectLogContainsSomewhere( |
| 3691 entries, 0, |
| 3692 net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM, |
| 3693 net::NetLog::PHASE_NONE); |
| 3694 |
| 3695 base::ListValue* header_list; |
| 3696 ASSERT_TRUE(entries[pos].params.get()); |
| 3697 ASSERT_TRUE(entries[pos].params->GetList("headers", &header_list)); |
| 3698 |
| 3699 std::vector<std::string> expected; |
| 3700 expected.push_back(std::string(spdy_util_.GetHostKey()) + ": www.google.com"); |
| 3701 expected.push_back(std::string(spdy_util_.GetPathKey()) + ": /"); |
| 3702 expected.push_back(std::string(spdy_util_.GetSchemeKey()) + ": http"); |
| 3703 expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1"); |
| 3704 expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET"); |
| 3705 expected.push_back("user-agent: Chrome"); |
| 3706 EXPECT_EQ(expected.size(), header_list->GetSize()); |
| 3707 for (std::vector<std::string>::const_iterator it = expected.begin(); |
| 3708 it != expected.end(); |
| 3709 ++it) { |
| 3710 base::StringValue header(*it); |
| 3711 EXPECT_NE(header_list->end(), header_list->Find(header)) << |
| 3712 "Header not found: " << *it; |
| 3713 } |
| 3714 } |
| 3715 |
| 3716 // Since we buffer the IO from the stream to the renderer, this test verifies |
| 3717 // that when we read out the maximum amount of data (e.g. we received 50 bytes |
| 3718 // on the network, but issued a Read for only 5 of those bytes) that the data |
| 3719 // flow still works correctly. |
| 3720 TEST_P(SpdyNetworkTransactionTest, BufferFull) { |
| 3721 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
| 3722 |
| 3723 scoped_ptr<SpdyFrame> req( |
| 3724 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 3725 MockWrite writes[] = { CreateMockWrite(*req) }; |
| 3726 |
| 3727 // 2 data frames in a single read. |
| 3728 scoped_ptr<SpdyFrame> data_frame_1( |
| 3729 framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE)); |
| 3730 scoped_ptr<SpdyFrame> data_frame_2( |
| 3731 framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE)); |
| 3732 const SpdyFrame* data_frames[2] = { |
| 3733 data_frame_1.get(), |
| 3734 data_frame_2.get(), |
| 3735 }; |
| 3736 char combined_data_frames[100]; |
| 3737 int combined_data_frames_len = |
| 3738 CombineFrames(data_frames, arraysize(data_frames), |
| 3739 combined_data_frames, arraysize(combined_data_frames)); |
| 3740 scoped_ptr<SpdyFrame> last_frame( |
| 3741 framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN)); |
| 3742 |
| 3743 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 3744 MockRead reads[] = { |
| 3745 CreateMockRead(*resp), |
| 3746 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause |
| 3747 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), |
| 3748 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause |
| 3749 CreateMockRead(*last_frame), |
| 3750 MockRead(ASYNC, 0, 0) // EOF |
| 3751 }; |
| 3752 |
| 3753 DelayedSocketData data(1, reads, arraysize(reads), |
| 3754 writes, arraysize(writes)); |
| 3755 |
| 3756 TestCompletionCallback callback; |
| 3757 |
| 3758 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3759 BoundNetLog(), GetParam(), NULL); |
| 3760 helper.RunPreTestSetup(); |
| 3761 helper.AddData(&data); |
| 3762 HttpNetworkTransaction* trans = helper.trans(); |
| 3763 int rv = trans->Start( |
| 3764 &CreateGetRequest(), callback.callback(), BoundNetLog()); |
| 3765 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 3766 |
| 3767 TransactionHelperResult out = helper.output(); |
| 3768 out.rv = callback.WaitForResult(); |
| 3769 EXPECT_EQ(out.rv, OK); |
| 3770 |
| 3771 const HttpResponseInfo* response = trans->GetResponseInfo(); |
| 3772 EXPECT_TRUE(response->headers.get() != NULL); |
| 3773 EXPECT_TRUE(response->was_fetched_via_spdy); |
| 3774 out.status_line = response->headers->GetStatusLine(); |
| 3775 out.response_info = *response; // Make a copy so we can verify. |
| 3776 |
| 3777 // Read Data |
| 3778 TestCompletionCallback read_callback; |
| 3779 |
| 3780 std::string content; |
| 3781 do { |
| 3782 // Read small chunks at a time. |
| 3783 const int kSmallReadSize = 3; |
| 3784 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); |
| 3785 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); |
| 3786 if (rv == net::ERR_IO_PENDING) { |
| 3787 data.CompleteRead(); |
| 3788 rv = read_callback.WaitForResult(); |
| 3789 } |
| 3790 if (rv > 0) { |
| 3791 content.append(buf->data(), rv); |
| 3792 } else if (rv < 0) { |
| 3793 NOTREACHED(); |
| 3794 } |
| 3795 } while (rv > 0); |
| 3796 |
| 3797 out.response_data.swap(content); |
| 3798 |
| 3799 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the |
| 3800 // MockClientSocketFactory) are still alive. |
| 3801 base::MessageLoop::current()->RunUntilIdle(); |
| 3802 |
| 3803 // Verify that we consumed all test data. |
| 3804 helper.VerifyDataConsumed(); |
| 3805 |
| 3806 EXPECT_EQ(OK, out.rv); |
| 3807 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); |
| 3808 EXPECT_EQ("goodbye world", out.response_data); |
| 3809 } |
| 3810 |
| 3811 // Verify that basic buffering works; when multiple data frames arrive |
| 3812 // at the same time, ensure that we don't notify a read completion for |
| 3813 // each data frame individually. |
| 3814 TEST_P(SpdyNetworkTransactionTest, Buffering) { |
| 3815 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
| 3816 |
| 3817 scoped_ptr<SpdyFrame> req( |
| 3818 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 3819 MockWrite writes[] = { CreateMockWrite(*req) }; |
| 3820 |
| 3821 // 4 data frames in a single read. |
| 3822 scoped_ptr<SpdyFrame> data_frame( |
| 3823 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); |
| 3824 scoped_ptr<SpdyFrame> data_frame_fin( |
| 3825 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); |
| 3826 const SpdyFrame* data_frames[4] = { |
| 3827 data_frame.get(), |
| 3828 data_frame.get(), |
| 3829 data_frame.get(), |
| 3830 data_frame_fin.get() |
| 3831 }; |
| 3832 char combined_data_frames[100]; |
| 3833 int combined_data_frames_len = |
| 3834 CombineFrames(data_frames, arraysize(data_frames), |
| 3835 combined_data_frames, arraysize(combined_data_frames)); |
| 3836 |
| 3837 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 3838 MockRead reads[] = { |
| 3839 CreateMockRead(*resp), |
| 3840 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause |
| 3841 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), |
| 3842 MockRead(ASYNC, 0, 0) // EOF |
| 3843 }; |
| 3844 |
| 3845 DelayedSocketData data(1, reads, arraysize(reads), |
| 3846 writes, arraysize(writes)); |
| 3847 |
| 3848 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3849 BoundNetLog(), GetParam(), NULL); |
| 3850 helper.RunPreTestSetup(); |
| 3851 helper.AddData(&data); |
| 3852 HttpNetworkTransaction* trans = helper.trans(); |
| 3853 |
| 3854 TestCompletionCallback callback; |
| 3855 int rv = trans->Start( |
| 3856 &CreateGetRequest(), callback.callback(), BoundNetLog()); |
| 3857 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 3858 |
| 3859 TransactionHelperResult out = helper.output(); |
| 3860 out.rv = callback.WaitForResult(); |
| 3861 EXPECT_EQ(out.rv, OK); |
| 3862 |
| 3863 const HttpResponseInfo* response = trans->GetResponseInfo(); |
| 3864 EXPECT_TRUE(response->headers.get() != NULL); |
| 3865 EXPECT_TRUE(response->was_fetched_via_spdy); |
| 3866 out.status_line = response->headers->GetStatusLine(); |
| 3867 out.response_info = *response; // Make a copy so we can verify. |
| 3868 |
| 3869 // Read Data |
| 3870 TestCompletionCallback read_callback; |
| 3871 |
| 3872 std::string content; |
| 3873 int reads_completed = 0; |
| 3874 do { |
| 3875 // Read small chunks at a time. |
| 3876 const int kSmallReadSize = 14; |
| 3877 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); |
| 3878 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); |
| 3879 if (rv == net::ERR_IO_PENDING) { |
| 3880 data.CompleteRead(); |
| 3881 rv = read_callback.WaitForResult(); |
| 3882 } |
| 3883 if (rv > 0) { |
| 3884 EXPECT_EQ(kSmallReadSize, rv); |
| 3885 content.append(buf->data(), rv); |
| 3886 } else if (rv < 0) { |
| 3887 FAIL() << "Unexpected read error: " << rv; |
| 3888 } |
| 3889 reads_completed++; |
| 3890 } while (rv > 0); |
| 3891 |
| 3892 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes. |
| 3893 |
| 3894 out.response_data.swap(content); |
| 3895 |
| 3896 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the |
| 3897 // MockClientSocketFactory) are still alive. |
| 3898 base::MessageLoop::current()->RunUntilIdle(); |
| 3899 |
| 3900 // Verify that we consumed all test data. |
| 3901 helper.VerifyDataConsumed(); |
| 3902 |
| 3903 EXPECT_EQ(OK, out.rv); |
| 3904 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); |
| 3905 EXPECT_EQ("messagemessagemessagemessage", out.response_data); |
| 3906 } |
| 3907 |
| 3908 // Verify the case where we buffer data but read it after it has been buffered. |
| 3909 TEST_P(SpdyNetworkTransactionTest, BufferedAll) { |
| 3910 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
| 3911 |
| 3912 scoped_ptr<SpdyFrame> req( |
| 3913 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 3914 MockWrite writes[] = { CreateMockWrite(*req) }; |
| 3915 |
| 3916 // 5 data frames in a single read. |
| 3917 scoped_ptr<SpdyFrame> syn_reply( |
| 3918 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 3919 // turn off FIN bit |
| 3920 test::SetFrameFlags( |
| 3921 syn_reply.get(), CONTROL_FLAG_NONE, spdy_util_.spdy_version()); |
| 3922 scoped_ptr<SpdyFrame> data_frame( |
| 3923 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); |
| 3924 scoped_ptr<SpdyFrame> data_frame_fin( |
| 3925 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); |
| 3926 const SpdyFrame* frames[5] = { |
| 3927 syn_reply.get(), |
| 3928 data_frame.get(), |
| 3929 data_frame.get(), |
| 3930 data_frame.get(), |
| 3931 data_frame_fin.get() |
| 3932 }; |
| 3933 char combined_frames[200]; |
| 3934 int combined_frames_len = |
| 3935 CombineFrames(frames, arraysize(frames), |
| 3936 combined_frames, arraysize(combined_frames)); |
| 3937 |
| 3938 MockRead reads[] = { |
| 3939 MockRead(ASYNC, combined_frames, combined_frames_len), |
| 3940 MockRead(ASYNC, 0, 0) // EOF |
| 3941 }; |
| 3942 |
| 3943 DelayedSocketData data(1, reads, arraysize(reads), |
| 3944 writes, arraysize(writes)); |
| 3945 |
| 3946 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 3947 BoundNetLog(), GetParam(), NULL); |
| 3948 helper.RunPreTestSetup(); |
| 3949 helper.AddData(&data); |
| 3950 HttpNetworkTransaction* trans = helper.trans(); |
| 3951 |
| 3952 TestCompletionCallback callback; |
| 3953 int rv = trans->Start( |
| 3954 &CreateGetRequest(), callback.callback(), BoundNetLog()); |
| 3955 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 3956 |
| 3957 TransactionHelperResult out = helper.output(); |
| 3958 out.rv = callback.WaitForResult(); |
| 3959 EXPECT_EQ(out.rv, OK); |
| 3960 |
| 3961 const HttpResponseInfo* response = trans->GetResponseInfo(); |
| 3962 EXPECT_TRUE(response->headers.get() != NULL); |
| 3963 EXPECT_TRUE(response->was_fetched_via_spdy); |
| 3964 out.status_line = response->headers->GetStatusLine(); |
| 3965 out.response_info = *response; // Make a copy so we can verify. |
| 3966 |
| 3967 // Read Data |
| 3968 TestCompletionCallback read_callback; |
| 3969 |
| 3970 std::string content; |
| 3971 int reads_completed = 0; |
| 3972 do { |
| 3973 // Read small chunks at a time. |
| 3974 const int kSmallReadSize = 14; |
| 3975 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); |
| 3976 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); |
| 3977 if (rv > 0) { |
| 3978 EXPECT_EQ(kSmallReadSize, rv); |
| 3979 content.append(buf->data(), rv); |
| 3980 } else if (rv < 0) { |
| 3981 FAIL() << "Unexpected read error: " << rv; |
| 3982 } |
| 3983 reads_completed++; |
| 3984 } while (rv > 0); |
| 3985 |
| 3986 EXPECT_EQ(3, reads_completed); |
| 3987 |
| 3988 out.response_data.swap(content); |
| 3989 |
| 3990 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the |
| 3991 // MockClientSocketFactory) are still alive. |
| 3992 base::MessageLoop::current()->RunUntilIdle(); |
| 3993 |
| 3994 // Verify that we consumed all test data. |
| 3995 helper.VerifyDataConsumed(); |
| 3996 |
| 3997 EXPECT_EQ(OK, out.rv); |
| 3998 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); |
| 3999 EXPECT_EQ("messagemessagemessagemessage", out.response_data); |
| 4000 } |
| 4001 |
| 4002 // Verify the case where we buffer data and close the connection. |
| 4003 TEST_P(SpdyNetworkTransactionTest, BufferedClosed) { |
| 4004 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
| 4005 |
| 4006 scoped_ptr<SpdyFrame> req( |
| 4007 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 4008 MockWrite writes[] = { CreateMockWrite(*req) }; |
| 4009 |
| 4010 // All data frames in a single read. |
| 4011 // NOTE: We don't FIN the stream. |
| 4012 scoped_ptr<SpdyFrame> data_frame( |
| 4013 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); |
| 4014 const SpdyFrame* data_frames[4] = { |
| 4015 data_frame.get(), |
| 4016 data_frame.get(), |
| 4017 data_frame.get(), |
| 4018 data_frame.get() |
| 4019 }; |
| 4020 char combined_data_frames[100]; |
| 4021 int combined_data_frames_len = |
| 4022 CombineFrames(data_frames, arraysize(data_frames), |
| 4023 combined_data_frames, arraysize(combined_data_frames)); |
| 4024 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 4025 MockRead reads[] = { |
| 4026 CreateMockRead(*resp), |
| 4027 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait |
| 4028 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), |
| 4029 MockRead(ASYNC, 0, 0) // EOF |
| 4030 }; |
| 4031 |
| 4032 DelayedSocketData data(1, reads, arraysize(reads), |
| 4033 writes, arraysize(writes)); |
| 4034 |
| 4035 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 4036 BoundNetLog(), GetParam(), NULL); |
| 4037 helper.RunPreTestSetup(); |
| 4038 helper.AddData(&data); |
| 4039 HttpNetworkTransaction* trans = helper.trans(); |
| 4040 |
| 4041 TestCompletionCallback callback; |
| 4042 |
| 4043 int rv = trans->Start( |
| 4044 &CreateGetRequest(), callback.callback(), BoundNetLog()); |
| 4045 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 4046 |
| 4047 TransactionHelperResult out = helper.output(); |
| 4048 out.rv = callback.WaitForResult(); |
| 4049 EXPECT_EQ(out.rv, OK); |
| 4050 |
| 4051 const HttpResponseInfo* response = trans->GetResponseInfo(); |
| 4052 EXPECT_TRUE(response->headers.get() != NULL); |
| 4053 EXPECT_TRUE(response->was_fetched_via_spdy); |
| 4054 out.status_line = response->headers->GetStatusLine(); |
| 4055 out.response_info = *response; // Make a copy so we can verify. |
| 4056 |
| 4057 // Read Data |
| 4058 TestCompletionCallback read_callback; |
| 4059 |
| 4060 std::string content; |
| 4061 int reads_completed = 0; |
| 4062 do { |
| 4063 // Read small chunks at a time. |
| 4064 const int kSmallReadSize = 14; |
| 4065 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); |
| 4066 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); |
| 4067 if (rv == net::ERR_IO_PENDING) { |
| 4068 data.CompleteRead(); |
| 4069 rv = read_callback.WaitForResult(); |
| 4070 } |
| 4071 if (rv > 0) { |
| 4072 content.append(buf->data(), rv); |
| 4073 } else if (rv < 0) { |
| 4074 // This test intentionally closes the connection, and will get an error. |
| 4075 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); |
| 4076 break; |
| 4077 } |
| 4078 reads_completed++; |
| 4079 } while (rv > 0); |
| 4080 |
| 4081 EXPECT_EQ(0, reads_completed); |
| 4082 |
| 4083 out.response_data.swap(content); |
| 4084 |
| 4085 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the |
| 4086 // MockClientSocketFactory) are still alive. |
| 4087 base::MessageLoop::current()->RunUntilIdle(); |
| 4088 |
| 4089 // Verify that we consumed all test data. |
| 4090 helper.VerifyDataConsumed(); |
| 4091 } |
| 4092 |
| 4093 // Verify the case where we buffer data and cancel the transaction. |
| 4094 TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) { |
| 4095 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
| 4096 |
| 4097 scoped_ptr<SpdyFrame> req( |
| 4098 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 4099 MockWrite writes[] = { CreateMockWrite(*req) }; |
| 4100 |
| 4101 // NOTE: We don't FIN the stream. |
| 4102 scoped_ptr<SpdyFrame> data_frame( |
| 4103 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); |
| 4104 |
| 4105 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 4106 MockRead reads[] = { |
| 4107 CreateMockRead(*resp), |
| 4108 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait |
| 4109 CreateMockRead(*data_frame), |
| 4110 MockRead(ASYNC, 0, 0) // EOF |
| 4111 }; |
| 4112 |
| 4113 DelayedSocketData data(1, reads, arraysize(reads), |
| 4114 writes, arraysize(writes)); |
| 4115 |
| 4116 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 4117 BoundNetLog(), GetParam(), NULL); |
| 4118 helper.RunPreTestSetup(); |
| 4119 helper.AddData(&data); |
| 4120 HttpNetworkTransaction* trans = helper.trans(); |
| 4121 TestCompletionCallback callback; |
| 4122 |
| 4123 int rv = trans->Start( |
| 4124 &CreateGetRequest(), callback.callback(), BoundNetLog()); |
| 4125 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 4126 |
| 4127 TransactionHelperResult out = helper.output(); |
| 4128 out.rv = callback.WaitForResult(); |
| 4129 EXPECT_EQ(out.rv, OK); |
| 4130 |
| 4131 const HttpResponseInfo* response = trans->GetResponseInfo(); |
| 4132 EXPECT_TRUE(response->headers.get() != NULL); |
| 4133 EXPECT_TRUE(response->was_fetched_via_spdy); |
| 4134 out.status_line = response->headers->GetStatusLine(); |
| 4135 out.response_info = *response; // Make a copy so we can verify. |
| 4136 |
| 4137 // Read Data |
| 4138 TestCompletionCallback read_callback; |
| 4139 |
| 4140 do { |
| 4141 const int kReadSize = 256; |
| 4142 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize)); |
| 4143 rv = trans->Read(buf.get(), kReadSize, read_callback.callback()); |
| 4144 if (rv == net::ERR_IO_PENDING) { |
| 4145 // Complete the read now, which causes buffering to start. |
| 4146 data.CompleteRead(); |
| 4147 // Destroy the transaction, causing the stream to get cancelled |
| 4148 // and orphaning the buffered IO task. |
| 4149 helper.ResetTrans(); |
| 4150 break; |
| 4151 } |
| 4152 // We shouldn't get here in this test. |
| 4153 FAIL() << "Unexpected read: " << rv; |
| 4154 } while (rv > 0); |
| 4155 |
| 4156 // Flush the MessageLoop; this will cause the buffered IO task |
| 4157 // to run for the final time. |
| 4158 base::MessageLoop::current()->RunUntilIdle(); |
| 4159 |
| 4160 // Verify that we consumed all test data. |
| 4161 helper.VerifyDataConsumed(); |
| 4162 } |
| 4163 |
| 4164 // Test that if the server requests persistence of settings, that we save |
| 4165 // the settings in the HttpServerProperties. |
| 4166 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) { |
| 4167 static const SpdyHeaderInfo kSynReplyInfo = { |
| 4168 SYN_REPLY, // Syn Reply |
| 4169 1, // Stream ID |
| 4170 0, // Associated Stream ID |
3911 ConvertRequestPriorityToSpdyPriority( | 4171 ConvertRequestPriorityToSpdyPriority( |
3912 LOWEST, spdy_util_.spdy_version()), | 4172 LOWEST, spdy_util_.spdy_version()), |
3913 kSpdyCredentialSlotUnused, | 4173 kSpdyCredentialSlotUnused, |
3914 CONTROL_FLAG_NONE, // Control Flags | 4174 CONTROL_FLAG_NONE, // Control Flags |
3915 false, // Compressed | 4175 false, // Compressed |
3916 RST_STREAM_INVALID, // Status | 4176 RST_STREAM_INVALID, // Status |
3917 NULL, // Data | 4177 NULL, // Data |
3918 0, // Data Length | 4178 0, // Data Length |
3919 DATA_FLAG_NONE // Data Flags | 4179 DATA_FLAG_NONE // Data Flags |
3920 }; | 4180 }; |
3921 // Modify the following data to change/add test cases: | |
3922 struct SynReplyTests { | |
3923 const SpdyHeaderInfo* syn_reply; | |
3924 bool vary_matches; | |
3925 int num_headers[2]; | |
3926 const char* extra_headers[2][16]; | |
3927 } test_cases[] = { | |
3928 // Test the case of a multi-valued cookie. When the value is delimited | |
3929 // with NUL characters, it needs to be unfolded into multiple headers. | |
3930 { | |
3931 &syn_reply_info, | |
3932 true, | |
3933 { 1, 4 }, | |
3934 { { "cookie", "val1,val2", | |
3935 NULL | |
3936 }, | |
3937 { "vary", "cookie", | |
3938 spdy_util_.GetStatusKey(), "200", | |
3939 spdy_util_.GetPathKey(), "/index.php", | |
3940 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3941 NULL | |
3942 } | |
3943 } | |
3944 }, { // Multiple vary fields. | |
3945 &syn_reply_info, | |
3946 true, | |
3947 { 2, 5 }, | |
3948 { { "friend", "barney", | |
3949 "enemy", "snaggletooth", | |
3950 NULL | |
3951 }, | |
3952 { "vary", "friend", | |
3953 "vary", "enemy", | |
3954 spdy_util_.GetStatusKey(), "200", | |
3955 spdy_util_.GetPathKey(), "/index.php", | |
3956 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3957 NULL | |
3958 } | |
3959 } | |
3960 }, { // Test a '*' vary field. | |
3961 &syn_reply_info, | |
3962 false, | |
3963 { 1, 4 }, | |
3964 { { "cookie", "val1,val2", | |
3965 NULL | |
3966 }, | |
3967 { "vary", "*", | |
3968 spdy_util_.GetStatusKey(), "200", | |
3969 spdy_util_.GetPathKey(), "/index.php", | |
3970 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3971 NULL | |
3972 } | |
3973 } | |
3974 }, { // Multiple comma-separated vary fields. | |
3975 &syn_reply_info, | |
3976 true, | |
3977 { 2, 4 }, | |
3978 { { "friend", "barney", | |
3979 "enemy", "snaggletooth", | |
3980 NULL | |
3981 }, | |
3982 { "vary", "friend,enemy", | |
3983 spdy_util_.GetStatusKey(), "200", | |
3984 spdy_util_.GetPathKey(), "/index.php", | |
3985 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3986 NULL | |
3987 } | |
3988 } | |
3989 } | |
3990 }; | |
3991 | |
3992 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { | |
3993 // Construct the request. | |
3994 scoped_ptr<SpdyFrame> frame_req( | |
3995 spdy_util_.ConstructSpdyGet(test_cases[i].extra_headers[0], | |
3996 test_cases[i].num_headers[0], | |
3997 false, 1, LOWEST, true)); | |
3998 | |
3999 MockWrite writes[] = { | |
4000 CreateMockWrite(*frame_req), | |
4001 }; | |
4002 | |
4003 // Construct the reply. | |
4004 scoped_ptr<SpdyFrame> frame_reply( | |
4005 spdy_util_.ConstructSpdyFrame(*test_cases[i].syn_reply, | |
4006 test_cases[i].extra_headers[1], | |
4007 test_cases[i].num_headers[1], | |
4008 NULL, | |
4009 0)); | |
4010 | |
4011 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4012 MockRead reads[] = { | |
4013 CreateMockRead(*frame_reply), | |
4014 CreateMockRead(*body), | |
4015 MockRead(ASYNC, 0, 0) // EOF | |
4016 }; | |
4017 | |
4018 // Attach the headers to the request. | |
4019 int header_count = test_cases[i].num_headers[0]; | |
4020 | |
4021 HttpRequestInfo request = CreateGetRequest(); | |
4022 for (int ct = 0; ct < header_count; ct++) { | |
4023 const char* header_key = test_cases[i].extra_headers[0][ct * 2]; | |
4024 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1]; | |
4025 request.extra_headers.SetHeader(header_key, header_value); | |
4026 } | |
4027 | |
4028 DelayedSocketData data(1, reads, arraysize(reads), | |
4029 writes, arraysize(writes)); | |
4030 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
4031 BoundNetLog(), GetParam(), NULL); | |
4032 helper.RunToCompletion(&data); | |
4033 TransactionHelperResult out = helper.output(); | |
4034 | |
4035 EXPECT_EQ(OK, out.rv) << i; | |
4036 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i; | |
4037 EXPECT_EQ("hello!", out.response_data) << i; | |
4038 | |
4039 // Test the response information. | |
4040 EXPECT_TRUE(out.response_info.response_time > | |
4041 out.response_info.request_time) << i; | |
4042 base::TimeDelta test_delay = out.response_info.response_time - | |
4043 out.response_info.request_time; | |
4044 base::TimeDelta min_expected_delay; | |
4045 min_expected_delay.FromMilliseconds(10); | |
4046 EXPECT_GT(test_delay.InMillisecondsF(), | |
4047 min_expected_delay.InMillisecondsF()) << i; | |
4048 EXPECT_EQ(out.response_info.vary_data.is_valid(), | |
4049 test_cases[i].vary_matches) << i; | |
4050 | |
4051 // Check the headers. | |
4052 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; | |
4053 ASSERT_TRUE(headers.get() != NULL) << i; | |
4054 void* iter = NULL; | |
4055 std::string name, value, lines; | |
4056 while (headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
4057 lines.append(name); | |
4058 lines.append(": "); | |
4059 lines.append(value); | |
4060 lines.append("\n"); | |
4061 } | |
4062 | |
4063 // Construct the expected header reply string. | |
4064 SpdyHeaderBlock reply_headers; | |
4065 AppendToHeaderBlock(test_cases[i].extra_headers[1], | |
4066 test_cases[i].num_headers[1], | |
4067 &reply_headers); | |
4068 std::string expected_reply = | |
4069 spdy_util_.ConstructSpdyReplyString(reply_headers); | |
4070 EXPECT_EQ(expected_reply, lines) << i; | |
4071 } | |
4072 } | |
4073 | |
4074 // Verify that we don't crash on invalid SynReply responses. | |
4075 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) { | |
4076 const SpdyHeaderInfo kSynStartHeader = { | |
4077 SYN_REPLY, // Kind = SynReply | |
4078 1, // Stream ID | |
4079 0, // Associated stream ID | |
4080 ConvertRequestPriorityToSpdyPriority( | |
4081 LOWEST, spdy_util_.spdy_version()), | |
4082 kSpdyCredentialSlotUnused, | |
4083 CONTROL_FLAG_NONE, // Control Flags | |
4084 false, // Compressed | |
4085 RST_STREAM_INVALID, // Status | |
4086 NULL, // Data | |
4087 0, // Length | |
4088 DATA_FLAG_NONE // Data Flags | |
4089 }; | |
4090 | |
4091 struct InvalidSynReplyTests { | |
4092 int num_headers; | |
4093 const char* headers[10]; | |
4094 } test_cases[] = { | |
4095 // SYN_REPLY missing status header | |
4096 { 4, | |
4097 { "cookie", "val1", | |
4098 "cookie", "val2", | |
4099 spdy_util_.GetPathKey(), "/index.php", | |
4100 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
4101 NULL | |
4102 }, | |
4103 }, | |
4104 // SYN_REPLY missing version header | |
4105 { 2, | |
4106 { "status", "200", | |
4107 spdy_util_.GetPathKey(), "/index.php", | |
4108 NULL | |
4109 }, | |
4110 }, | |
4111 // SYN_REPLY with no headers | |
4112 { 0, { NULL }, }, | |
4113 }; | |
4114 | |
4115 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { | |
4116 scoped_ptr<SpdyFrame> req( | |
4117 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4118 scoped_ptr<SpdyFrame> rst( | |
4119 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
4120 MockWrite writes[] = { | |
4121 CreateMockWrite(*req), | |
4122 CreateMockWrite(*rst), | |
4123 }; | |
4124 | |
4125 scoped_ptr<SpdyFrame> resp( | |
4126 spdy_util_.ConstructSpdyFrame(kSynStartHeader, | |
4127 NULL, 0, | |
4128 test_cases[i].headers, | |
4129 test_cases[i].num_headers)); | |
4130 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4131 MockRead reads[] = { | |
4132 CreateMockRead(*resp), | |
4133 MockRead(ASYNC, 0, 0) // EOF | |
4134 }; | |
4135 | |
4136 DelayedSocketData data(1, reads, arraysize(reads), | |
4137 writes, arraysize(writes)); | |
4138 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4139 BoundNetLog(), GetParam(), NULL); | |
4140 helper.RunToCompletion(&data); | |
4141 TransactionHelperResult out = helper.output(); | |
4142 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
4143 } | |
4144 } | |
4145 | |
4146 // Verify that we don't crash on some corrupt frames. | |
4147 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) { | |
4148 // This is the length field that's too short. | |
4149 scoped_ptr<SpdyFrame> syn_reply_wrong_length( | |
4150 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4151 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4152 size_t right_size = | |
4153 (spdy_util_.spdy_version() < SPDY4) ? | |
4154 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize() : | |
4155 syn_reply_wrong_length->size(); | |
4156 size_t wrong_size = right_size - 4; | |
4157 test::SetFrameLength(syn_reply_wrong_length.get(), | |
4158 wrong_size, | |
4159 spdy_util_.spdy_version()); | |
4160 | |
4161 struct SynReplyTests { | |
4162 const SpdyFrame* syn_reply; | |
4163 } test_cases[] = { | |
4164 { syn_reply_wrong_length.get(), }, | |
4165 }; | |
4166 | |
4167 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { | |
4168 scoped_ptr<SpdyFrame> req( | |
4169 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4170 MockWrite writes[] = { CreateMockWrite(*req), MockWrite(ASYNC, 0, 0) // EOF | |
4171 }; | |
4172 | |
4173 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4174 MockRead reads[] = { | |
4175 MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size), | |
4176 CreateMockRead(*body), | |
4177 MockRead(ASYNC, 0, 0) // EOF | |
4178 }; | |
4179 | |
4180 DelayedSocketData data(1, reads, arraysize(reads), | |
4181 writes, arraysize(writes)); | |
4182 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4183 BoundNetLog(), GetParam(), NULL); | |
4184 helper.RunToCompletion(&data); | |
4185 TransactionHelperResult out = helper.output(); | |
4186 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
4187 } | |
4188 } | |
4189 | |
4190 // Test that we shutdown correctly on write errors. | |
4191 TEST_P(SpdyNetworkTransactionTest, WriteError) { | |
4192 scoped_ptr<SpdyFrame> req( | |
4193 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4194 MockWrite writes[] = { | |
4195 // We'll write 10 bytes successfully | |
4196 MockWrite(ASYNC, req->data(), 10), | |
4197 // Followed by ERROR! | |
4198 MockWrite(ASYNC, ERR_FAILED), | |
4199 }; | |
4200 | |
4201 DelayedSocketData data(2, NULL, 0, | |
4202 writes, arraysize(writes)); | |
4203 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4204 BoundNetLog(), GetParam(), NULL); | |
4205 helper.RunToCompletion(&data); | |
4206 TransactionHelperResult out = helper.output(); | |
4207 EXPECT_EQ(ERR_FAILED, out.rv); | |
4208 data.Reset(); | |
4209 } | |
4210 | |
4211 // Test that partial writes work. | |
4212 TEST_P(SpdyNetworkTransactionTest, PartialWrite) { | |
4213 // Chop the SYN_STREAM frame into 5 chunks. | |
4214 scoped_ptr<SpdyFrame> req( | |
4215 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4216 const int kChunks = 5; | |
4217 scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks)); | |
4218 | |
4219 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4220 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4221 MockRead reads[] = { | |
4222 CreateMockRead(*resp), | |
4223 CreateMockRead(*body), | |
4224 MockRead(ASYNC, 0, 0) // EOF | |
4225 }; | |
4226 | |
4227 DelayedSocketData data(kChunks, reads, arraysize(reads), | |
4228 writes.get(), kChunks); | |
4229 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4230 BoundNetLog(), GetParam(), NULL); | |
4231 helper.RunToCompletion(&data); | |
4232 TransactionHelperResult out = helper.output(); | |
4233 EXPECT_EQ(OK, out.rv); | |
4234 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4235 EXPECT_EQ("hello!", out.response_data); | |
4236 } | |
4237 | |
4238 // In this test, we enable compression, but get a uncompressed SynReply from | |
4239 // the server. Verify that teardown is all clean. | |
4240 TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) { | |
4241 scoped_ptr<SpdyFrame> compressed( | |
4242 spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true)); | |
4243 scoped_ptr<SpdyFrame> rst( | |
4244 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
4245 MockWrite writes[] = { | |
4246 CreateMockWrite(*compressed), | |
4247 }; | |
4248 | |
4249 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4250 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4251 MockRead reads[] = { | |
4252 CreateMockRead(*resp), | |
4253 }; | |
4254 | |
4255 DelayedSocketData data(1, reads, arraysize(reads), | |
4256 writes, arraysize(writes)); | |
4257 SpdySessionDependencies* session_deps = | |
4258 CreateSpdySessionDependencies(GetParam()); | |
4259 session_deps->enable_compression = true; | |
4260 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4261 BoundNetLog(), GetParam(), session_deps); | |
4262 helper.RunToCompletion(&data); | |
4263 TransactionHelperResult out = helper.output(); | |
4264 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
4265 data.Reset(); | |
4266 } | |
4267 | |
4268 // Test that the NetLog contains good data for a simple GET request. | |
4269 TEST_P(SpdyNetworkTransactionTest, NetLog) { | |
4270 static const char* const kExtraHeaders[] = { | |
4271 "user-agent", "Chrome", | |
4272 }; | |
4273 scoped_ptr<SpdyFrame> req( | |
4274 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true)); | |
4275 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4276 | |
4277 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4278 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4279 MockRead reads[] = { | |
4280 CreateMockRead(*resp), | |
4281 CreateMockRead(*body), | |
4282 MockRead(ASYNC, 0, 0) // EOF | |
4283 }; | |
4284 | |
4285 CapturingBoundNetLog log; | |
4286 | |
4287 DelayedSocketData data(1, reads, arraysize(reads), | |
4288 writes, arraysize(writes)); | |
4289 NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(), | |
4290 DEFAULT_PRIORITY, | |
4291 log.bound(), GetParam(), NULL); | |
4292 helper.RunToCompletion(&data); | |
4293 TransactionHelperResult out = helper.output(); | |
4294 EXPECT_EQ(OK, out.rv); | |
4295 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4296 EXPECT_EQ("hello!", out.response_data); | |
4297 | |
4298 // Check that the NetLog was filled reasonably. | |
4299 // This test is intentionally non-specific about the exact ordering of the | |
4300 // log; instead we just check to make sure that certain events exist, and that | |
4301 // they are in the right order. | |
4302 net::CapturingNetLog::CapturedEntryList entries; | |
4303 log.GetEntries(&entries); | |
4304 | |
4305 EXPECT_LT(0u, entries.size()); | |
4306 int pos = 0; | |
4307 pos = net::ExpectLogContainsSomewhere(entries, 0, | |
4308 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, | |
4309 net::NetLog::PHASE_BEGIN); | |
4310 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
4311 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, | |
4312 net::NetLog::PHASE_END); | |
4313 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
4314 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, | |
4315 net::NetLog::PHASE_BEGIN); | |
4316 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
4317 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, | |
4318 net::NetLog::PHASE_END); | |
4319 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
4320 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, | |
4321 net::NetLog::PHASE_BEGIN); | |
4322 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
4323 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, | |
4324 net::NetLog::PHASE_END); | |
4325 | |
4326 // Check that we logged all the headers correctly | |
4327 pos = net::ExpectLogContainsSomewhere( | |
4328 entries, 0, | |
4329 net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM, | |
4330 net::NetLog::PHASE_NONE); | |
4331 | |
4332 base::ListValue* header_list; | |
4333 ASSERT_TRUE(entries[pos].params.get()); | |
4334 ASSERT_TRUE(entries[pos].params->GetList("headers", &header_list)); | |
4335 | |
4336 std::vector<std::string> expected; | |
4337 expected.push_back(std::string(spdy_util_.GetHostKey()) + ": www.google.com"); | |
4338 expected.push_back(std::string(spdy_util_.GetPathKey()) + ": /"); | |
4339 expected.push_back(std::string(spdy_util_.GetSchemeKey()) + ": http"); | |
4340 expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1"); | |
4341 expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET"); | |
4342 expected.push_back("user-agent: Chrome"); | |
4343 EXPECT_EQ(expected.size(), header_list->GetSize()); | |
4344 for (std::vector<std::string>::const_iterator it = expected.begin(); | |
4345 it != expected.end(); | |
4346 ++it) { | |
4347 base::StringValue header(*it); | |
4348 EXPECT_NE(header_list->end(), header_list->Find(header)) << | |
4349 "Header not found: " << *it; | |
4350 } | |
4351 } | |
4352 | |
4353 // Since we buffer the IO from the stream to the renderer, this test verifies | |
4354 // that when we read out the maximum amount of data (e.g. we received 50 bytes | |
4355 // on the network, but issued a Read for only 5 of those bytes) that the data | |
4356 // flow still works correctly. | |
4357 TEST_P(SpdyNetworkTransactionTest, BufferFull) { | |
4358 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4359 | |
4360 scoped_ptr<SpdyFrame> req( | |
4361 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4362 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4363 | |
4364 // 2 data frames in a single read. | |
4365 scoped_ptr<SpdyFrame> data_frame_1( | |
4366 framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE)); | |
4367 scoped_ptr<SpdyFrame> data_frame_2( | |
4368 framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE)); | |
4369 const SpdyFrame* data_frames[2] = { | |
4370 data_frame_1.get(), | |
4371 data_frame_2.get(), | |
4372 }; | |
4373 char combined_data_frames[100]; | |
4374 int combined_data_frames_len = | |
4375 CombineFrames(data_frames, arraysize(data_frames), | |
4376 combined_data_frames, arraysize(combined_data_frames)); | |
4377 scoped_ptr<SpdyFrame> last_frame( | |
4378 framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN)); | |
4379 | |
4380 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4381 MockRead reads[] = { | |
4382 CreateMockRead(*resp), | |
4383 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
4384 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
4385 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
4386 CreateMockRead(*last_frame), | |
4387 MockRead(ASYNC, 0, 0) // EOF | |
4388 }; | |
4389 | |
4390 DelayedSocketData data(1, reads, arraysize(reads), | |
4391 writes, arraysize(writes)); | |
4392 | |
4393 TestCompletionCallback callback; | |
4394 | |
4395 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4396 BoundNetLog(), GetParam(), NULL); | |
4397 helper.RunPreTestSetup(); | |
4398 helper.AddData(&data); | |
4399 HttpNetworkTransaction* trans = helper.trans(); | |
4400 int rv = trans->Start( | |
4401 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4402 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4403 | |
4404 TransactionHelperResult out = helper.output(); | |
4405 out.rv = callback.WaitForResult(); | |
4406 EXPECT_EQ(out.rv, OK); | |
4407 | |
4408 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4409 EXPECT_TRUE(response->headers.get() != NULL); | |
4410 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4411 out.status_line = response->headers->GetStatusLine(); | |
4412 out.response_info = *response; // Make a copy so we can verify. | |
4413 | |
4414 // Read Data | |
4415 TestCompletionCallback read_callback; | |
4416 | |
4417 std::string content; | |
4418 do { | |
4419 // Read small chunks at a time. | |
4420 const int kSmallReadSize = 3; | |
4421 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4422 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
4423 if (rv == net::ERR_IO_PENDING) { | |
4424 data.CompleteRead(); | |
4425 rv = read_callback.WaitForResult(); | |
4426 } | |
4427 if (rv > 0) { | |
4428 content.append(buf->data(), rv); | |
4429 } else if (rv < 0) { | |
4430 NOTREACHED(); | |
4431 } | |
4432 } while (rv > 0); | |
4433 | |
4434 out.response_data.swap(content); | |
4435 | |
4436 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4437 // MockClientSocketFactory) are still alive. | |
4438 base::MessageLoop::current()->RunUntilIdle(); | |
4439 | |
4440 // Verify that we consumed all test data. | |
4441 helper.VerifyDataConsumed(); | |
4442 | |
4443 EXPECT_EQ(OK, out.rv); | |
4444 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4445 EXPECT_EQ("goodbye world", out.response_data); | |
4446 } | |
4447 | |
4448 // Verify that basic buffering works; when multiple data frames arrive | |
4449 // at the same time, ensure that we don't notify a read completion for | |
4450 // each data frame individually. | |
4451 TEST_P(SpdyNetworkTransactionTest, Buffering) { | |
4452 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4453 | |
4454 scoped_ptr<SpdyFrame> req( | |
4455 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4456 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4457 | |
4458 // 4 data frames in a single read. | |
4459 scoped_ptr<SpdyFrame> data_frame( | |
4460 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
4461 scoped_ptr<SpdyFrame> data_frame_fin( | |
4462 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); | |
4463 const SpdyFrame* data_frames[4] = { | |
4464 data_frame.get(), | |
4465 data_frame.get(), | |
4466 data_frame.get(), | |
4467 data_frame_fin.get() | |
4468 }; | |
4469 char combined_data_frames[100]; | |
4470 int combined_data_frames_len = | |
4471 CombineFrames(data_frames, arraysize(data_frames), | |
4472 combined_data_frames, arraysize(combined_data_frames)); | |
4473 | |
4474 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4475 MockRead reads[] = { | |
4476 CreateMockRead(*resp), | |
4477 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
4478 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
4479 MockRead(ASYNC, 0, 0) // EOF | |
4480 }; | |
4481 | |
4482 DelayedSocketData data(1, reads, arraysize(reads), | |
4483 writes, arraysize(writes)); | |
4484 | |
4485 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4486 BoundNetLog(), GetParam(), NULL); | |
4487 helper.RunPreTestSetup(); | |
4488 helper.AddData(&data); | |
4489 HttpNetworkTransaction* trans = helper.trans(); | |
4490 | |
4491 TestCompletionCallback callback; | |
4492 int rv = trans->Start( | |
4493 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4494 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4495 | |
4496 TransactionHelperResult out = helper.output(); | |
4497 out.rv = callback.WaitForResult(); | |
4498 EXPECT_EQ(out.rv, OK); | |
4499 | |
4500 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4501 EXPECT_TRUE(response->headers.get() != NULL); | |
4502 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4503 out.status_line = response->headers->GetStatusLine(); | |
4504 out.response_info = *response; // Make a copy so we can verify. | |
4505 | |
4506 // Read Data | |
4507 TestCompletionCallback read_callback; | |
4508 | |
4509 std::string content; | |
4510 int reads_completed = 0; | |
4511 do { | |
4512 // Read small chunks at a time. | |
4513 const int kSmallReadSize = 14; | |
4514 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4515 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
4516 if (rv == net::ERR_IO_PENDING) { | |
4517 data.CompleteRead(); | |
4518 rv = read_callback.WaitForResult(); | |
4519 } | |
4520 if (rv > 0) { | |
4521 EXPECT_EQ(kSmallReadSize, rv); | |
4522 content.append(buf->data(), rv); | |
4523 } else if (rv < 0) { | |
4524 FAIL() << "Unexpected read error: " << rv; | |
4525 } | |
4526 reads_completed++; | |
4527 } while (rv > 0); | |
4528 | |
4529 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes. | |
4530 | |
4531 out.response_data.swap(content); | |
4532 | |
4533 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4534 // MockClientSocketFactory) are still alive. | |
4535 base::MessageLoop::current()->RunUntilIdle(); | |
4536 | |
4537 // Verify that we consumed all test data. | |
4538 helper.VerifyDataConsumed(); | |
4539 | |
4540 EXPECT_EQ(OK, out.rv); | |
4541 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4542 EXPECT_EQ("messagemessagemessagemessage", out.response_data); | |
4543 } | |
4544 | |
4545 // Verify the case where we buffer data but read it after it has been buffered. | |
4546 TEST_P(SpdyNetworkTransactionTest, BufferedAll) { | |
4547 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4548 | |
4549 scoped_ptr<SpdyFrame> req( | |
4550 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4551 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4552 | |
4553 // 5 data frames in a single read. | |
4554 scoped_ptr<SpdyFrame> syn_reply( | |
4555 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4556 // turn off FIN bit | |
4557 test::SetFrameFlags( | |
4558 syn_reply.get(), CONTROL_FLAG_NONE, spdy_util_.spdy_version()); | |
4559 scoped_ptr<SpdyFrame> data_frame( | |
4560 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
4561 scoped_ptr<SpdyFrame> data_frame_fin( | |
4562 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); | |
4563 const SpdyFrame* frames[5] = { | |
4564 syn_reply.get(), | |
4565 data_frame.get(), | |
4566 data_frame.get(), | |
4567 data_frame.get(), | |
4568 data_frame_fin.get() | |
4569 }; | |
4570 char combined_frames[200]; | |
4571 int combined_frames_len = | |
4572 CombineFrames(frames, arraysize(frames), | |
4573 combined_frames, arraysize(combined_frames)); | |
4574 | |
4575 MockRead reads[] = { | |
4576 MockRead(ASYNC, combined_frames, combined_frames_len), | |
4577 MockRead(ASYNC, 0, 0) // EOF | |
4578 }; | |
4579 | |
4580 DelayedSocketData data(1, reads, arraysize(reads), | |
4581 writes, arraysize(writes)); | |
4582 | |
4583 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4584 BoundNetLog(), GetParam(), NULL); | |
4585 helper.RunPreTestSetup(); | |
4586 helper.AddData(&data); | |
4587 HttpNetworkTransaction* trans = helper.trans(); | |
4588 | |
4589 TestCompletionCallback callback; | |
4590 int rv = trans->Start( | |
4591 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4592 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4593 | |
4594 TransactionHelperResult out = helper.output(); | |
4595 out.rv = callback.WaitForResult(); | |
4596 EXPECT_EQ(out.rv, OK); | |
4597 | |
4598 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4599 EXPECT_TRUE(response->headers.get() != NULL); | |
4600 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4601 out.status_line = response->headers->GetStatusLine(); | |
4602 out.response_info = *response; // Make a copy so we can verify. | |
4603 | |
4604 // Read Data | |
4605 TestCompletionCallback read_callback; | |
4606 | |
4607 std::string content; | |
4608 int reads_completed = 0; | |
4609 do { | |
4610 // Read small chunks at a time. | |
4611 const int kSmallReadSize = 14; | |
4612 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4613 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
4614 if (rv > 0) { | |
4615 EXPECT_EQ(kSmallReadSize, rv); | |
4616 content.append(buf->data(), rv); | |
4617 } else if (rv < 0) { | |
4618 FAIL() << "Unexpected read error: " << rv; | |
4619 } | |
4620 reads_completed++; | |
4621 } while (rv > 0); | |
4622 | |
4623 EXPECT_EQ(3, reads_completed); | |
4624 | |
4625 out.response_data.swap(content); | |
4626 | |
4627 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4628 // MockClientSocketFactory) are still alive. | |
4629 base::MessageLoop::current()->RunUntilIdle(); | |
4630 | |
4631 // Verify that we consumed all test data. | |
4632 helper.VerifyDataConsumed(); | |
4633 | |
4634 EXPECT_EQ(OK, out.rv); | |
4635 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4636 EXPECT_EQ("messagemessagemessagemessage", out.response_data); | |
4637 } | |
4638 | |
4639 // Verify the case where we buffer data and close the connection. | |
4640 TEST_P(SpdyNetworkTransactionTest, BufferedClosed) { | |
4641 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4642 | |
4643 scoped_ptr<SpdyFrame> req( | |
4644 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4645 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4646 | |
4647 // All data frames in a single read. | |
4648 // NOTE: We don't FIN the stream. | |
4649 scoped_ptr<SpdyFrame> data_frame( | |
4650 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
4651 const SpdyFrame* data_frames[4] = { | |
4652 data_frame.get(), | |
4653 data_frame.get(), | |
4654 data_frame.get(), | |
4655 data_frame.get() | |
4656 }; | |
4657 char combined_data_frames[100]; | |
4658 int combined_data_frames_len = | |
4659 CombineFrames(data_frames, arraysize(data_frames), | |
4660 combined_data_frames, arraysize(combined_data_frames)); | |
4661 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4662 MockRead reads[] = { | |
4663 CreateMockRead(*resp), | |
4664 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait | |
4665 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
4666 MockRead(ASYNC, 0, 0) // EOF | |
4667 }; | |
4668 | |
4669 DelayedSocketData data(1, reads, arraysize(reads), | |
4670 writes, arraysize(writes)); | |
4671 | |
4672 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4673 BoundNetLog(), GetParam(), NULL); | |
4674 helper.RunPreTestSetup(); | |
4675 helper.AddData(&data); | |
4676 HttpNetworkTransaction* trans = helper.trans(); | |
4677 | |
4678 TestCompletionCallback callback; | |
4679 | |
4680 int rv = trans->Start( | |
4681 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4682 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4683 | |
4684 TransactionHelperResult out = helper.output(); | |
4685 out.rv = callback.WaitForResult(); | |
4686 EXPECT_EQ(out.rv, OK); | |
4687 | |
4688 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4689 EXPECT_TRUE(response->headers.get() != NULL); | |
4690 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4691 out.status_line = response->headers->GetStatusLine(); | |
4692 out.response_info = *response; // Make a copy so we can verify. | |
4693 | |
4694 // Read Data | |
4695 TestCompletionCallback read_callback; | |
4696 | |
4697 std::string content; | |
4698 int reads_completed = 0; | |
4699 do { | |
4700 // Read small chunks at a time. | |
4701 const int kSmallReadSize = 14; | |
4702 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4703 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
4704 if (rv == net::ERR_IO_PENDING) { | |
4705 data.CompleteRead(); | |
4706 rv = read_callback.WaitForResult(); | |
4707 } | |
4708 if (rv > 0) { | |
4709 content.append(buf->data(), rv); | |
4710 } else if (rv < 0) { | |
4711 // This test intentionally closes the connection, and will get an error. | |
4712 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); | |
4713 break; | |
4714 } | |
4715 reads_completed++; | |
4716 } while (rv > 0); | |
4717 | |
4718 EXPECT_EQ(0, reads_completed); | |
4719 | |
4720 out.response_data.swap(content); | |
4721 | |
4722 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4723 // MockClientSocketFactory) are still alive. | |
4724 base::MessageLoop::current()->RunUntilIdle(); | |
4725 | |
4726 // Verify that we consumed all test data. | |
4727 helper.VerifyDataConsumed(); | |
4728 } | |
4729 | |
4730 // Verify the case where we buffer data and cancel the transaction. | |
4731 TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) { | |
4732 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4733 | |
4734 scoped_ptr<SpdyFrame> req( | |
4735 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4736 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4737 | |
4738 // NOTE: We don't FIN the stream. | |
4739 scoped_ptr<SpdyFrame> data_frame( | |
4740 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
4741 | |
4742 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4743 MockRead reads[] = { | |
4744 CreateMockRead(*resp), | |
4745 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait | |
4746 CreateMockRead(*data_frame), | |
4747 MockRead(ASYNC, 0, 0) // EOF | |
4748 }; | |
4749 | |
4750 DelayedSocketData data(1, reads, arraysize(reads), | |
4751 writes, arraysize(writes)); | |
4752 | |
4753 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4754 BoundNetLog(), GetParam(), NULL); | |
4755 helper.RunPreTestSetup(); | |
4756 helper.AddData(&data); | |
4757 HttpNetworkTransaction* trans = helper.trans(); | |
4758 TestCompletionCallback callback; | |
4759 | |
4760 int rv = trans->Start( | |
4761 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4762 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4763 | |
4764 TransactionHelperResult out = helper.output(); | |
4765 out.rv = callback.WaitForResult(); | |
4766 EXPECT_EQ(out.rv, OK); | |
4767 | |
4768 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4769 EXPECT_TRUE(response->headers.get() != NULL); | |
4770 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4771 out.status_line = response->headers->GetStatusLine(); | |
4772 out.response_info = *response; // Make a copy so we can verify. | |
4773 | |
4774 // Read Data | |
4775 TestCompletionCallback read_callback; | |
4776 | |
4777 do { | |
4778 const int kReadSize = 256; | |
4779 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize)); | |
4780 rv = trans->Read(buf.get(), kReadSize, read_callback.callback()); | |
4781 if (rv == net::ERR_IO_PENDING) { | |
4782 // Complete the read now, which causes buffering to start. | |
4783 data.CompleteRead(); | |
4784 // Destroy the transaction, causing the stream to get cancelled | |
4785 // and orphaning the buffered IO task. | |
4786 helper.ResetTrans(); | |
4787 break; | |
4788 } | |
4789 // We shouldn't get here in this test. | |
4790 FAIL() << "Unexpected read: " << rv; | |
4791 } while (rv > 0); | |
4792 | |
4793 // Flush the MessageLoop; this will cause the buffered IO task | |
4794 // to run for the final time. | |
4795 base::MessageLoop::current()->RunUntilIdle(); | |
4796 | |
4797 // Verify that we consumed all test data. | |
4798 helper.VerifyDataConsumed(); | |
4799 } | |
4800 | |
4801 // Test that if the server requests persistence of settings, that we save | |
4802 // the settings in the HttpServerProperties. | |
4803 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) { | |
4804 static const SpdyHeaderInfo kSynReplyInfo = { | |
4805 SYN_REPLY, // Syn Reply | |
4806 1, // Stream ID | |
4807 0, // Associated Stream ID | |
4808 ConvertRequestPriorityToSpdyPriority( | |
4809 LOWEST, spdy_util_.spdy_version()), | |
4810 kSpdyCredentialSlotUnused, | |
4811 CONTROL_FLAG_NONE, // Control Flags | |
4812 false, // Compressed | |
4813 RST_STREAM_INVALID, // Status | |
4814 NULL, // Data | |
4815 0, // Data Length | |
4816 DATA_FLAG_NONE // Data Flags | |
4817 }; | |
4818 | 4181 |
4819 BoundNetLog net_log; | 4182 BoundNetLog net_log; |
4820 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | 4183 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
4821 net_log, GetParam(), NULL); | 4184 net_log, GetParam(), NULL); |
4822 helper.RunPreTestSetup(); | 4185 helper.RunPreTestSetup(); |
4823 | 4186 |
4824 // Verify that no settings exist initially. | 4187 // Verify that no settings exist initially. |
4825 HostPortPair host_port_pair("www.google.com", helper.port()); | 4188 HostPortPair host_port_pair("www.google.com", helper.port()); |
4826 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); | 4189 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); |
4827 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( | 4190 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( |
(...skipping 1549 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6377 | 5740 |
6378 // And now we can allow everything else to run to completion. | 5741 // And now we can allow everything else to run to completion. |
6379 data.SetStop(10); | 5742 data.SetStop(10); |
6380 data.Run(); | 5743 data.Run(); |
6381 EXPECT_EQ(OK, callback2.WaitForResult()); | 5744 EXPECT_EQ(OK, callback2.WaitForResult()); |
6382 EXPECT_EQ(OK, callback3.WaitForResult()); | 5745 EXPECT_EQ(OK, callback3.WaitForResult()); |
6383 | 5746 |
6384 helper.VerifyDataConsumed(); | 5747 helper.VerifyDataConsumed(); |
6385 } | 5748 } |
6386 | 5749 |
| 5750 // The tests below are only for SPDY/3 and above. |
| 5751 |
| 5752 // Test that sent data frames and received WINDOW_UPDATE frames change |
| 5753 // the send_window_size_ correctly. |
| 5754 |
| 5755 // WINDOW_UPDATE is different than most other frames in that it can arrive |
| 5756 // while the client is still sending the request body. In order to enforce |
| 5757 // this scenario, we feed a couple of dummy frames and give a delay of 0 to |
| 5758 // socket data provider, so that initial read that is done as soon as the |
| 5759 // stream is created, succeeds and schedules another read. This way reads |
| 5760 // and writes are interleaved; after doing a full frame write, SpdyStream |
| 5761 // will break out of DoLoop and will read and process a WINDOW_UPDATE. |
| 5762 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away |
| 5763 // since request has not been completely written, therefore we feed |
| 5764 // enough number of WINDOW_UPDATEs to finish the first read and cause a |
| 5765 // write, leading to a complete write of request body; after that we send |
| 5766 // a reply with a body, to cause a graceful shutdown. |
| 5767 |
| 5768 // TODO(agayev): develop a socket data provider where both, reads and |
| 5769 // writes are ordered so that writing tests like these are easy and rewrite |
| 5770 // all these tests using it. Right now we are working around the |
| 5771 // limitations as described above and it's not deterministic, tests may |
| 5772 // fail under specific circumstances. |
| 5773 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) { |
| 5774 if (GetParam().protocol < kProtoSPDY3) |
| 5775 return; |
| 5776 |
| 5777 static int kFrameCount = 2; |
| 5778 scoped_ptr<std::string> content( |
| 5779 new std::string(kMaxSpdyFrameChunkSize, 'a')); |
| 5780 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( |
| 5781 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0)); |
| 5782 scoped_ptr<SpdyFrame> body( |
| 5783 spdy_util_.ConstructSpdyBodyFrame( |
| 5784 1, content->c_str(), content->size(), false)); |
| 5785 scoped_ptr<SpdyFrame> body_end( |
| 5786 spdy_util_.ConstructSpdyBodyFrame( |
| 5787 1, content->c_str(), content->size(), true)); |
| 5788 |
| 5789 MockWrite writes[] = { |
| 5790 CreateMockWrite(*req, 0), |
| 5791 CreateMockWrite(*body, 1), |
| 5792 CreateMockWrite(*body_end, 2), |
| 5793 }; |
| 5794 |
| 5795 static const int32 kDeltaWindowSize = 0xff; |
| 5796 static const int kDeltaCount = 4; |
| 5797 scoped_ptr<SpdyFrame> window_update( |
| 5798 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); |
| 5799 scoped_ptr<SpdyFrame> window_update_dummy( |
| 5800 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize)); |
| 5801 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
| 5802 MockRead reads[] = { |
| 5803 CreateMockRead(*window_update_dummy, 3), |
| 5804 CreateMockRead(*window_update_dummy, 4), |
| 5805 CreateMockRead(*window_update_dummy, 5), |
| 5806 CreateMockRead(*window_update, 6), // Four updates, therefore window |
| 5807 CreateMockRead(*window_update, 7), // size should increase by |
| 5808 CreateMockRead(*window_update, 8), // kDeltaWindowSize * 4 |
| 5809 CreateMockRead(*window_update, 9), |
| 5810 CreateMockRead(*resp, 10), |
| 5811 CreateMockRead(*body_end, 11), |
| 5812 MockRead(ASYNC, 0, 0, 12) // EOF |
| 5813 }; |
| 5814 |
| 5815 DeterministicSocketData data(reads, arraysize(reads), |
| 5816 writes, arraysize(writes)); |
| 5817 |
| 5818 ScopedVector<UploadElementReader> element_readers; |
| 5819 for (int i = 0; i < kFrameCount; ++i) { |
| 5820 element_readers.push_back( |
| 5821 new UploadBytesElementReader(content->c_str(), content->size())); |
| 5822 } |
| 5823 UploadDataStream upload_data_stream(&element_readers, 0); |
| 5824 |
| 5825 // Setup the request |
| 5826 HttpRequestInfo request; |
| 5827 request.method = "POST"; |
| 5828 request.url = GURL(kDefaultURL); |
| 5829 request.upload_data_stream = &upload_data_stream; |
| 5830 |
| 5831 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, |
| 5832 BoundNetLog(), GetParam(), NULL); |
| 5833 helper.SetDeterministic(); |
| 5834 helper.AddDeterministicData(&data); |
| 5835 helper.RunPreTestSetup(); |
| 5836 |
| 5837 HttpNetworkTransaction* trans = helper.trans(); |
| 5838 |
| 5839 TestCompletionCallback callback; |
| 5840 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); |
| 5841 |
| 5842 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 5843 |
| 5844 data.RunFor(11); |
| 5845 |
| 5846 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); |
| 5847 ASSERT_TRUE(stream != NULL); |
| 5848 ASSERT_TRUE(stream->stream() != NULL); |
| 5849 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize) + |
| 5850 kDeltaWindowSize * kDeltaCount - |
| 5851 kMaxSpdyFrameChunkSize * kFrameCount, |
| 5852 stream->stream()->send_window_size()); |
| 5853 |
| 5854 data.RunFor(1); |
| 5855 |
| 5856 rv = callback.WaitForResult(); |
| 5857 EXPECT_EQ(OK, rv); |
| 5858 |
| 5859 helper.VerifyDataConsumed(); |
| 5860 } |
| 5861 |
| 5862 // Test that received data frames and sent WINDOW_UPDATE frames change |
| 5863 // the recv_window_size_ correctly. |
| 5864 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) { |
| 5865 if (GetParam().protocol < kProtoSPDY3) |
| 5866 return; |
| 5867 |
| 5868 // Set the data in the body frame large enough to trigger sending a |
| 5869 // WINDOW_UPDATE by the stream. |
| 5870 const std::string body_data(kSpdyStreamInitialWindowSize / 2 + 1, 'x'); |
| 5871 |
| 5872 scoped_ptr<SpdyFrame> req( |
| 5873 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| 5874 scoped_ptr<SpdyFrame> session_window_update( |
| 5875 spdy_util_.ConstructSpdyWindowUpdate(0, body_data.size())); |
| 5876 scoped_ptr<SpdyFrame> window_update( |
| 5877 spdy_util_.ConstructSpdyWindowUpdate(1, body_data.size())); |
| 5878 |
| 5879 std::vector<MockWrite> writes; |
| 5880 writes.push_back(CreateMockWrite(*req)); |
| 5881 if (GetParam().protocol >= kProtoSPDY31) |
| 5882 writes.push_back(CreateMockWrite(*session_window_update)); |
| 5883 writes.push_back(CreateMockWrite(*window_update)); |
| 5884 |
| 5885 scoped_ptr<SpdyFrame> resp( |
| 5886 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
| 5887 scoped_ptr<SpdyFrame> body_no_fin( |
| 5888 spdy_util_.ConstructSpdyBodyFrame( |
| 5889 1, body_data.data(), body_data.size(), false)); |
| 5890 scoped_ptr<SpdyFrame> body_fin( |
| 5891 spdy_util_.ConstructSpdyBodyFrame(1, NULL, 0, true)); |
| 5892 MockRead reads[] = { |
| 5893 CreateMockRead(*resp), |
| 5894 CreateMockRead(*body_no_fin), |
| 5895 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause |
| 5896 CreateMockRead(*body_fin), |
| 5897 MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause |
| 5898 MockRead(ASYNC, 0, 0) // EOF |
| 5899 }; |
| 5900 |
| 5901 DelayedSocketData data(1, reads, arraysize(reads), |
| 5902 vector_as_array(&writes), writes.size()); |
| 5903 |
| 5904 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, |
| 5905 BoundNetLog(), GetParam(), NULL); |
| 5906 helper.AddData(&data); |
| 5907 helper.RunPreTestSetup(); |
| 5908 HttpNetworkTransaction* trans = helper.trans(); |
| 5909 |
| 5910 TestCompletionCallback callback; |
| 5911 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); |
| 5912 |
| 5913 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 5914 rv = callback.WaitForResult(); |
| 5915 EXPECT_EQ(OK, rv); |
| 5916 |
| 5917 SpdyHttpStream* stream = |
| 5918 static_cast<SpdyHttpStream*>(trans->stream_.get()); |
| 5919 ASSERT_TRUE(stream != NULL); |
| 5920 ASSERT_TRUE(stream->stream() != NULL); |
| 5921 |
| 5922 EXPECT_EQ( |
| 5923 static_cast<int>(kSpdyStreamInitialWindowSize - body_data.size()), |
| 5924 stream->stream()->recv_window_size()); |
| 5925 |
| 5926 const HttpResponseInfo* response = trans->GetResponseInfo(); |
| 5927 ASSERT_TRUE(response != NULL); |
| 5928 ASSERT_TRUE(response->headers.get() != NULL); |
| 5929 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); |
| 5930 EXPECT_TRUE(response->was_fetched_via_spdy); |
| 5931 |
| 5932 // Issue a read which will cause a WINDOW_UPDATE to be sent and window |
| 5933 // size increased to default. |
| 5934 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(body_data.size())); |
| 5935 rv = trans->Read(buf.get(), body_data.size(), CompletionCallback()); |
| 5936 EXPECT_EQ(static_cast<int>(body_data.size()), rv); |
| 5937 std::string content(buf->data(), buf->data() + body_data.size()); |
| 5938 EXPECT_EQ(body_data, content); |
| 5939 |
| 5940 // Schedule the reading of empty data frame with FIN |
| 5941 data.CompleteRead(); |
| 5942 |
| 5943 // Force write of WINDOW_UPDATE which was scheduled during the above |
| 5944 // read. |
| 5945 base::MessageLoop::current()->RunUntilIdle(); |
| 5946 |
| 5947 // Read EOF. |
| 5948 data.CompleteRead(); |
| 5949 |
| 5950 helper.VerifyDataConsumed(); |
| 5951 } |
| 5952 |
| 5953 // Test that WINDOW_UPDATE frame causing overflow is handled correctly. |
| 5954 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) { |
| 5955 if (GetParam().protocol < kProtoSPDY3) |
| 5956 return; |
| 5957 |
| 5958 // Number of full frames we hope to write (but will not, used to |
| 5959 // set content-length header correctly) |
| 5960 static int kFrameCount = 3; |
| 5961 |
| 5962 scoped_ptr<std::string> content( |
| 5963 new std::string(kMaxSpdyFrameChunkSize, 'a')); |
| 5964 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( |
| 5965 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0)); |
| 5966 scoped_ptr<SpdyFrame> body( |
| 5967 spdy_util_.ConstructSpdyBodyFrame( |
| 5968 1, content->c_str(), content->size(), false)); |
| 5969 scoped_ptr<SpdyFrame> rst( |
| 5970 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR)); |
| 5971 |
| 5972 // We're not going to write a data frame with FIN, we'll receive a bad |
| 5973 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame. |
| 5974 MockWrite writes[] = { |
| 5975 CreateMockWrite(*req, 0), |
| 5976 CreateMockWrite(*body, 2), |
| 5977 CreateMockWrite(*rst, 3), |
| 5978 }; |
| 5979 |
| 5980 static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow |
| 5981 scoped_ptr<SpdyFrame> window_update( |
| 5982 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); |
| 5983 MockRead reads[] = { |
| 5984 CreateMockRead(*window_update, 1), |
| 5985 MockRead(ASYNC, 0, 4) // EOF |
| 5986 }; |
| 5987 |
| 5988 DeterministicSocketData data(reads, arraysize(reads), |
| 5989 writes, arraysize(writes)); |
| 5990 |
| 5991 ScopedVector<UploadElementReader> element_readers; |
| 5992 for (int i = 0; i < kFrameCount; ++i) { |
| 5993 element_readers.push_back( |
| 5994 new UploadBytesElementReader(content->c_str(), content->size())); |
| 5995 } |
| 5996 UploadDataStream upload_data_stream(&element_readers, 0); |
| 5997 |
| 5998 // Setup the request |
| 5999 HttpRequestInfo request; |
| 6000 request.method = "POST"; |
| 6001 request.url = GURL("http://www.google.com/"); |
| 6002 request.upload_data_stream = &upload_data_stream; |
| 6003 |
| 6004 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, |
| 6005 BoundNetLog(), GetParam(), NULL); |
| 6006 helper.SetDeterministic(); |
| 6007 helper.RunPreTestSetup(); |
| 6008 helper.AddDeterministicData(&data); |
| 6009 HttpNetworkTransaction* trans = helper.trans(); |
| 6010 |
| 6011 TestCompletionCallback callback; |
| 6012 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); |
| 6013 ASSERT_EQ(ERR_IO_PENDING, rv); |
| 6014 |
| 6015 data.RunFor(5); |
| 6016 ASSERT_TRUE(callback.have_result()); |
| 6017 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, callback.WaitForResult()); |
| 6018 helper.VerifyDataConsumed(); |
| 6019 } |
| 6020 |
| 6021 // Test that after hitting a send window size of 0, the write process |
| 6022 // stalls and upon receiving WINDOW_UPDATE frame write resumes. |
| 6023 |
| 6024 // This test constructs a POST request followed by enough data frames |
| 6025 // containing 'a' that would make the window size 0, followed by another |
| 6026 // data frame containing default content (which is "hello!") and this frame |
| 6027 // also contains a FIN flag. DelayedSocketData is used to enforce all |
| 6028 // writes go through before a read could happen. However, the last frame |
| 6029 // ("hello!") is not supposed to go through since by the time its turn |
| 6030 // arrives, window size is 0. At this point MessageLoop::Run() called via |
| 6031 // callback would block. Therefore we call MessageLoop::RunUntilIdle() |
| 6032 // which returns after performing all possible writes. We use DCHECKS to |
| 6033 // ensure that last data frame is still there and stream has stalled. |
| 6034 // After that, next read is artifically enforced, which causes a |
| 6035 // WINDOW_UPDATE to be read and I/O process resumes. |
| 6036 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) { |
| 6037 if (GetParam().protocol < kProtoSPDY3) |
| 6038 return; |
| 6039 |
| 6040 // Number of frames we need to send to zero out the window size: data |
| 6041 // frames plus SYN_STREAM plus the last data frame; also we need another |
| 6042 // data frame that we will send once the WINDOW_UPDATE is received, |
| 6043 // therefore +3. |
| 6044 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; |
| 6045 |
| 6046 // Calculate last frame's size; 0 size data frame is legal. |
| 6047 size_t last_frame_size = |
| 6048 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; |
| 6049 |
| 6050 // Construct content for a data frame of maximum size. |
| 6051 std::string content(kMaxSpdyFrameChunkSize, 'a'); |
| 6052 |
| 6053 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( |
| 6054 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, |
| 6055 LOWEST, NULL, 0)); |
| 6056 |
| 6057 // Full frames. |
| 6058 scoped_ptr<SpdyFrame> body1( |
| 6059 spdy_util_.ConstructSpdyBodyFrame( |
| 6060 1, content.c_str(), content.size(), false)); |
| 6061 |
| 6062 // Last frame to zero out the window size. |
| 6063 scoped_ptr<SpdyFrame> body2( |
| 6064 spdy_util_.ConstructSpdyBodyFrame( |
| 6065 1, content.c_str(), last_frame_size, false)); |
| 6066 |
| 6067 // Data frame to be sent once WINDOW_UPDATE frame is received. |
| 6068 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 6069 |
| 6070 // Fill in mock writes. |
| 6071 scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]); |
| 6072 size_t i = 0; |
| 6073 writes[i] = CreateMockWrite(*req); |
| 6074 for (i = 1; i < num_writes - 2; i++) |
| 6075 writes[i] = CreateMockWrite(*body1); |
| 6076 writes[i++] = CreateMockWrite(*body2); |
| 6077 writes[i] = CreateMockWrite(*body3); |
| 6078 |
| 6079 // Construct read frame, give enough space to upload the rest of the |
| 6080 // data. |
| 6081 scoped_ptr<SpdyFrame> session_window_update( |
| 6082 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize)); |
| 6083 scoped_ptr<SpdyFrame> window_update( |
| 6084 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize)); |
| 6085 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
| 6086 MockRead reads[] = { |
| 6087 CreateMockRead(*session_window_update), |
| 6088 CreateMockRead(*session_window_update), |
| 6089 CreateMockRead(*window_update), |
| 6090 CreateMockRead(*window_update), |
| 6091 CreateMockRead(*reply), |
| 6092 CreateMockRead(*body2), |
| 6093 CreateMockRead(*body3), |
| 6094 MockRead(ASYNC, 0, 0) // EOF |
| 6095 }; |
| 6096 |
| 6097 // Skip the session window updates unless we're using SPDY/3.1 and |
| 6098 // above. |
| 6099 size_t read_offset = (GetParam().protocol >= kProtoSPDY31) ? 0 : 2; |
| 6100 size_t num_reads = arraysize(reads) - read_offset; |
| 6101 |
| 6102 // Force all writes to happen before any read, last write will not |
| 6103 // actually queue a frame, due to window size being 0. |
| 6104 DelayedSocketData data(num_writes, reads + read_offset, num_reads, |
| 6105 writes.get(), num_writes); |
| 6106 |
| 6107 ScopedVector<UploadElementReader> element_readers; |
| 6108 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); |
| 6109 upload_data_string.append(kUploadData, kUploadDataSize); |
| 6110 element_readers.push_back(new UploadBytesElementReader( |
| 6111 upload_data_string.c_str(), upload_data_string.size())); |
| 6112 UploadDataStream upload_data_stream(&element_readers, 0); |
| 6113 |
| 6114 HttpRequestInfo request; |
| 6115 request.method = "POST"; |
| 6116 request.url = GURL("http://www.google.com/"); |
| 6117 request.upload_data_stream = &upload_data_stream; |
| 6118 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, |
| 6119 BoundNetLog(), GetParam(), NULL); |
| 6120 helper.AddData(&data); |
| 6121 helper.RunPreTestSetup(); |
| 6122 |
| 6123 HttpNetworkTransaction* trans = helper.trans(); |
| 6124 |
| 6125 TestCompletionCallback callback; |
| 6126 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); |
| 6127 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 6128 |
| 6129 base::MessageLoop::current()->RunUntilIdle(); // Write as much as we can. |
| 6130 |
| 6131 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); |
| 6132 ASSERT_TRUE(stream != NULL); |
| 6133 ASSERT_TRUE(stream->stream() != NULL); |
| 6134 EXPECT_EQ(0, stream->stream()->send_window_size()); |
| 6135 // All the body data should have been read. |
| 6136 // TODO(satorux): This is because of the weirdness in reading the request |
| 6137 // body in OnSendBodyComplete(). See crbug.com/113107. |
| 6138 EXPECT_TRUE(upload_data_stream.IsEOF()); |
| 6139 // But the body is not yet fully sent (kUploadData is not yet sent) |
| 6140 // since we're send-stalled. |
| 6141 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); |
| 6142 |
| 6143 data.ForceNextRead(); // Read in WINDOW_UPDATE frame. |
| 6144 rv = callback.WaitForResult(); |
| 6145 helper.VerifyDataConsumed(); |
| 6146 } |
| 6147 |
| 6148 // Test we correctly handle the case where the SETTINGS frame results in |
| 6149 // unstalling the send window. |
| 6150 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) { |
| 6151 if (GetParam().protocol < kProtoSPDY3) |
| 6152 return; |
| 6153 |
| 6154 // Number of frames we need to send to zero out the window size: data |
| 6155 // frames plus SYN_STREAM plus the last data frame; also we need another |
| 6156 // data frame that we will send once the SETTING is received, therefore +3. |
| 6157 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; |
| 6158 |
| 6159 // Calculate last frame's size; 0 size data frame is legal. |
| 6160 size_t last_frame_size = |
| 6161 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; |
| 6162 |
| 6163 // Construct content for a data frame of maximum size. |
| 6164 std::string content(kMaxSpdyFrameChunkSize, 'a'); |
| 6165 |
| 6166 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( |
| 6167 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, |
| 6168 LOWEST, NULL, 0)); |
| 6169 |
| 6170 // Full frames. |
| 6171 scoped_ptr<SpdyFrame> body1( |
| 6172 spdy_util_.ConstructSpdyBodyFrame( |
| 6173 1, content.c_str(), content.size(), false)); |
| 6174 |
| 6175 // Last frame to zero out the window size. |
| 6176 scoped_ptr<SpdyFrame> body2( |
| 6177 spdy_util_.ConstructSpdyBodyFrame( |
| 6178 1, content.c_str(), last_frame_size, false)); |
| 6179 |
| 6180 // Data frame to be sent once SETTINGS frame is received. |
| 6181 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 6182 |
| 6183 // Fill in mock reads/writes. |
| 6184 std::vector<MockRead> reads; |
| 6185 std::vector<MockWrite> writes; |
| 6186 size_t i = 0; |
| 6187 writes.push_back(CreateMockWrite(*req, i++)); |
| 6188 while (i < num_writes - 2) |
| 6189 writes.push_back(CreateMockWrite(*body1, i++)); |
| 6190 writes.push_back(CreateMockWrite(*body2, i++)); |
| 6191 |
| 6192 // Construct read frame for SETTINGS that gives enough space to upload the |
| 6193 // rest of the data. |
| 6194 SettingsMap settings; |
| 6195 settings[SETTINGS_INITIAL_WINDOW_SIZE] = |
| 6196 SettingsFlagsAndValue( |
| 6197 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize * 2); |
| 6198 scoped_ptr<SpdyFrame> settings_frame_large( |
| 6199 spdy_util_.ConstructSpdySettings(settings)); |
| 6200 |
| 6201 reads.push_back(CreateMockRead(*settings_frame_large, i++)); |
| 6202 |
| 6203 scoped_ptr<SpdyFrame> session_window_update( |
| 6204 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize)); |
| 6205 if (GetParam().protocol >= kProtoSPDY31) |
| 6206 reads.push_back(CreateMockRead(*session_window_update, i++)); |
| 6207 |
| 6208 writes.push_back(CreateMockWrite(*body3, i++)); |
| 6209 |
| 6210 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
| 6211 reads.push_back(CreateMockRead(*reply, i++)); |
| 6212 reads.push_back(CreateMockRead(*body2, i++)); |
| 6213 reads.push_back(CreateMockRead(*body3, i++)); |
| 6214 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF |
| 6215 |
| 6216 // Force all writes to happen before any read, last write will not |
| 6217 // actually queue a frame, due to window size being 0. |
| 6218 DeterministicSocketData data(vector_as_array(&reads), reads.size(), |
| 6219 vector_as_array(&writes), writes.size()); |
| 6220 |
| 6221 ScopedVector<UploadElementReader> element_readers; |
| 6222 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); |
| 6223 upload_data_string.append(kUploadData, kUploadDataSize); |
| 6224 element_readers.push_back(new UploadBytesElementReader( |
| 6225 upload_data_string.c_str(), upload_data_string.size())); |
| 6226 UploadDataStream upload_data_stream(&element_readers, 0); |
| 6227 |
| 6228 HttpRequestInfo request; |
| 6229 request.method = "POST"; |
| 6230 request.url = GURL("http://www.google.com/"); |
| 6231 request.upload_data_stream = &upload_data_stream; |
| 6232 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, |
| 6233 BoundNetLog(), GetParam(), NULL); |
| 6234 helper.SetDeterministic(); |
| 6235 helper.RunPreTestSetup(); |
| 6236 helper.AddDeterministicData(&data); |
| 6237 |
| 6238 HttpNetworkTransaction* trans = helper.trans(); |
| 6239 |
| 6240 TestCompletionCallback callback; |
| 6241 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); |
| 6242 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 6243 |
| 6244 data.RunFor(num_writes - 1); // Write as much as we can. |
| 6245 |
| 6246 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); |
| 6247 ASSERT_TRUE(stream != NULL); |
| 6248 ASSERT_TRUE(stream->stream() != NULL); |
| 6249 EXPECT_EQ(0, stream->stream()->send_window_size()); |
| 6250 |
| 6251 // All the body data should have been read. |
| 6252 // TODO(satorux): This is because of the weirdness in reading the request |
| 6253 // body in OnSendBodyComplete(). See crbug.com/113107. |
| 6254 EXPECT_TRUE(upload_data_stream.IsEOF()); |
| 6255 // But the body is not yet fully sent (kUploadData is not yet sent) |
| 6256 // since we're send-stalled. |
| 6257 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); |
| 6258 |
| 6259 data.RunFor(6); // Read in SETTINGS frame to unstall. |
| 6260 rv = callback.WaitForResult(); |
| 6261 helper.VerifyDataConsumed(); |
| 6262 // If stream is NULL, that means it was unstalled and closed. |
| 6263 EXPECT_TRUE(stream->stream() == NULL); |
| 6264 } |
| 6265 |
| 6266 // Test we correctly handle the case where the SETTINGS frame results in a |
| 6267 // negative send window size. |
| 6268 TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) { |
| 6269 if (GetParam().protocol < kProtoSPDY3) |
| 6270 return; |
| 6271 |
| 6272 // Number of frames we need to send to zero out the window size: data |
| 6273 // frames plus SYN_STREAM plus the last data frame; also we need another |
| 6274 // data frame that we will send once the SETTING is received, therefore +3. |
| 6275 size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; |
| 6276 |
| 6277 // Calculate last frame's size; 0 size data frame is legal. |
| 6278 size_t last_frame_size = |
| 6279 kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; |
| 6280 |
| 6281 // Construct content for a data frame of maximum size. |
| 6282 std::string content(kMaxSpdyFrameChunkSize, 'a'); |
| 6283 |
| 6284 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( |
| 6285 kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, |
| 6286 LOWEST, NULL, 0)); |
| 6287 |
| 6288 // Full frames. |
| 6289 scoped_ptr<SpdyFrame> body1( |
| 6290 spdy_util_.ConstructSpdyBodyFrame( |
| 6291 1, content.c_str(), content.size(), false)); |
| 6292 |
| 6293 // Last frame to zero out the window size. |
| 6294 scoped_ptr<SpdyFrame> body2( |
| 6295 spdy_util_.ConstructSpdyBodyFrame( |
| 6296 1, content.c_str(), last_frame_size, false)); |
| 6297 |
| 6298 // Data frame to be sent once SETTINGS frame is received. |
| 6299 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); |
| 6300 |
| 6301 // Fill in mock reads/writes. |
| 6302 std::vector<MockRead> reads; |
| 6303 std::vector<MockWrite> writes; |
| 6304 size_t i = 0; |
| 6305 writes.push_back(CreateMockWrite(*req, i++)); |
| 6306 while (i < num_writes - 2) |
| 6307 writes.push_back(CreateMockWrite(*body1, i++)); |
| 6308 writes.push_back(CreateMockWrite(*body2, i++)); |
| 6309 |
| 6310 // Construct read frame for SETTINGS that makes the send_window_size |
| 6311 // negative. |
| 6312 SettingsMap new_settings; |
| 6313 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = |
| 6314 SettingsFlagsAndValue( |
| 6315 SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize / 2); |
| 6316 scoped_ptr<SpdyFrame> settings_frame_small( |
| 6317 spdy_util_.ConstructSpdySettings(new_settings)); |
| 6318 // Construct read frames for WINDOW_UPDATE that makes the send_window_size |
| 6319 // positive. |
| 6320 scoped_ptr<SpdyFrame> session_window_update_init_size( |
| 6321 spdy_util_.ConstructSpdyWindowUpdate(0, kSpdyStreamInitialWindowSize)); |
| 6322 scoped_ptr<SpdyFrame> window_update_init_size( |
| 6323 spdy_util_.ConstructSpdyWindowUpdate(1, kSpdyStreamInitialWindowSize)); |
| 6324 |
| 6325 reads.push_back(CreateMockRead(*settings_frame_small, i++)); |
| 6326 |
| 6327 if (GetParam().protocol >= kProtoSPDY3) |
| 6328 reads.push_back(CreateMockRead(*session_window_update_init_size, i++)); |
| 6329 |
| 6330 reads.push_back(CreateMockRead(*window_update_init_size, i++)); |
| 6331 |
| 6332 writes.push_back(CreateMockWrite(*body3, i++)); |
| 6333 |
| 6334 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
| 6335 reads.push_back(CreateMockRead(*reply, i++)); |
| 6336 reads.push_back(CreateMockRead(*body2, i++)); |
| 6337 reads.push_back(CreateMockRead(*body3, i++)); |
| 6338 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF |
| 6339 |
| 6340 // Force all writes to happen before any read, last write will not |
| 6341 // actually queue a frame, due to window size being 0. |
| 6342 DeterministicSocketData data(vector_as_array(&reads), reads.size(), |
| 6343 vector_as_array(&writes), writes.size()); |
| 6344 |
| 6345 ScopedVector<UploadElementReader> element_readers; |
| 6346 std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); |
| 6347 upload_data_string.append(kUploadData, kUploadDataSize); |
| 6348 element_readers.push_back(new UploadBytesElementReader( |
| 6349 upload_data_string.c_str(), upload_data_string.size())); |
| 6350 UploadDataStream upload_data_stream(&element_readers, 0); |
| 6351 |
| 6352 HttpRequestInfo request; |
| 6353 request.method = "POST"; |
| 6354 request.url = GURL("http://www.google.com/"); |
| 6355 request.upload_data_stream = &upload_data_stream; |
| 6356 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, |
| 6357 BoundNetLog(), GetParam(), NULL); |
| 6358 helper.SetDeterministic(); |
| 6359 helper.RunPreTestSetup(); |
| 6360 helper.AddDeterministicData(&data); |
| 6361 |
| 6362 HttpNetworkTransaction* trans = helper.trans(); |
| 6363 |
| 6364 TestCompletionCallback callback; |
| 6365 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); |
| 6366 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 6367 |
| 6368 data.RunFor(num_writes - 1); // Write as much as we can. |
| 6369 |
| 6370 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); |
| 6371 ASSERT_TRUE(stream != NULL); |
| 6372 ASSERT_TRUE(stream->stream() != NULL); |
| 6373 EXPECT_EQ(0, stream->stream()->send_window_size()); |
| 6374 |
| 6375 // All the body data should have been read. |
| 6376 // TODO(satorux): This is because of the weirdness in reading the request |
| 6377 // body in OnSendBodyComplete(). See crbug.com/113107. |
| 6378 EXPECT_TRUE(upload_data_stream.IsEOF()); |
| 6379 // But the body is not yet fully sent (kUploadData is not yet sent) |
| 6380 // since we're send-stalled. |
| 6381 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); |
| 6382 |
| 6383 // Read in WINDOW_UPDATE or SETTINGS frame. |
| 6384 data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 8 : 7); |
| 6385 rv = callback.WaitForResult(); |
| 6386 helper.VerifyDataConsumed(); |
| 6387 } |
| 6388 |
6387 } // namespace net | 6389 } // namespace net |
OLD | NEW |