| 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 |