| 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 <stddef.h> | 5 #include <stddef.h> |
| 6 #include <sys/epoll.h> | 6 #include <sys/epoll.h> |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| (...skipping 2162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2173 trailers["some-trailing-header"] = "trailing-header-value"; | 2173 trailers["some-trailing-header"] = "trailing-header-value"; |
| 2174 | 2174 |
| 2175 QuicInMemoryCache::GetInstance()->AddResponse( | 2175 QuicInMemoryCache::GetInstance()->AddResponse( |
| 2176 "www.google.com", "/trailer_url", headers, kBody, trailers); | 2176 "www.google.com", "/trailer_url", headers, kBody, trailers); |
| 2177 | 2177 |
| 2178 EXPECT_EQ(kBody, client_->SendSynchronousRequest("/trailer_url")); | 2178 EXPECT_EQ(kBody, client_->SendSynchronousRequest("/trailer_url")); |
| 2179 EXPECT_EQ(200u, client_->response_headers()->parsed_response_code()); | 2179 EXPECT_EQ(200u, client_->response_headers()->parsed_response_code()); |
| 2180 EXPECT_EQ(trailers, client_->response_trailers()); | 2180 EXPECT_EQ(trailers, client_->response_trailers()); |
| 2181 } | 2181 } |
| 2182 | 2182 |
| 2183 TEST_P(EndToEndTest, ServerPush) { | 2183 class EndToEndTestServerPush : public EndToEndTest { |
| 2184 FLAGS_quic_supports_push_promise = true; | 2184 protected: |
| 2185 const size_t kNumMaxStreams = 10; |
| 2186 |
| 2187 EndToEndTestServerPush() : EndToEndTest() { |
| 2188 FLAGS_quic_supports_push_promise = true; |
| 2189 FLAGS_quic_different_max_num_open_streams = true; |
| 2190 client_config_.SetMaxStreamsPerConnection(kNumMaxStreams, kNumMaxStreams); |
| 2191 } |
| 2192 |
| 2193 // Add a request with its response and |num_resources| push resources into |
| 2194 // cache. |
| 2195 // If |resource_size| == 0, response body of push resources use default string |
| 2196 // concatenating with resource url. Otherwise, generate a string of |
| 2197 // |resource_size| as body. |
| 2198 void AddRequestAndResponseWithServerPush(string host, |
| 2199 string path, |
| 2200 string response_body, |
| 2201 string* push_urls, |
| 2202 const size_t num_resources, |
| 2203 const size_t resource_size) { |
| 2204 bool use_large_response = resource_size != 0; |
| 2205 string large_resource; |
| 2206 if (use_large_response) { |
| 2207 // Generate a response common body larger than flow control window for |
| 2208 // push response. |
| 2209 test::GenerateBody(&large_resource, resource_size); |
| 2210 } |
| 2211 list<QuicInMemoryCache::ServerPushInfo> push_resources; |
| 2212 for (size_t i = 0; i < num_resources; ++i) { |
| 2213 string url = push_urls[i]; |
| 2214 GURL resource_url(url); |
| 2215 string body = use_large_response |
| 2216 ? large_resource |
| 2217 : "This is server push response body for " + url; |
| 2218 SpdyHeaderBlock response_headers; |
| 2219 response_headers[":version"] = "HTTP/1.1"; |
| 2220 response_headers[":status"] = "200"; |
| 2221 response_headers["content-length"] = IntToString(body.size()); |
| 2222 push_resources.push_back(QuicInMemoryCache::ServerPushInfo( |
| 2223 resource_url, response_headers, kV3LowestPriority, body)); |
| 2224 } |
| 2225 |
| 2226 QuicInMemoryCache::GetInstance()->AddSimpleResponseWithServerPushResources( |
| 2227 host, path, 200, response_body, push_resources); |
| 2228 } |
| 2229 }; |
| 2230 |
| 2231 TEST_P(EndToEndTestServerPush, ServerPush) { |
| 2185 ASSERT_TRUE(Initialize()); | 2232 ASSERT_TRUE(Initialize()); |
| 2186 client_->client()->WaitForCryptoHandshakeConfirmed(); | 2233 client_->client()->WaitForCryptoHandshakeConfirmed(); |
| 2187 | 2234 |
| 2188 // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. | 2235 // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. |
| 2189 SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); | 2236 SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); |
| 2190 SetReorderPercentage(30); | 2237 SetReorderPercentage(30); |
| 2191 | 2238 |
| 2192 // Add a response with headers, body, and trailers. | 2239 // Add a response with headers, body, and push resources. |
| 2193 const string kBody = "body content"; | 2240 const string kBody = "body content"; |
| 2194 | 2241 size_t kNumResources = 4; |
| 2195 list<QuicInMemoryCache::ServerPushInfo> push_resources; | |
| 2196 | |
| 2197 string push_urls[] = { | 2242 string push_urls[] = { |
| 2198 "https://google.com/font.woff", "https://google.com/script.js", | 2243 "https://google.com/font.woff", "https://google.com/script.js", |
| 2199 "https://fonts.google.com/font.woff", "https://google.com/logo-hires.jpg", | 2244 "https://fonts.google.com/font.woff", "https://google.com/logo-hires.jpg", |
| 2200 }; | 2245 }; |
| 2201 for (const string& url : push_urls) { | 2246 AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, |
| 2202 GURL resource_url(url); | 2247 push_urls, kNumResources, 0); |
| 2203 string body = "This is server push response body for " + url; | |
| 2204 SpdyHeaderBlock response_headers; | |
| 2205 response_headers[":version"] = "HTTP/1.1"; | |
| 2206 response_headers[":status"] = "200"; | |
| 2207 response_headers["content-length"] = IntToString(body.size()); | |
| 2208 push_resources.push_back(QuicInMemoryCache::ServerPushInfo( | |
| 2209 resource_url, response_headers, kV3LowestPriority, body)); | |
| 2210 } | |
| 2211 | |
| 2212 QuicInMemoryCache::GetInstance()->AddSimpleResponseWithServerPushResources( | |
| 2213 "google.com", "/push_example", 200, kBody, push_resources); | |
| 2214 | 2248 |
| 2215 client_->client()->set_response_listener(new TestResponseListener); | 2249 client_->client()->set_response_listener(new TestResponseListener); |
| 2216 | 2250 |
| 2217 DVLOG(1) << "send request for /push_example"; | 2251 DVLOG(1) << "send request for /push_example"; |
| 2218 EXPECT_EQ(kBody, | 2252 EXPECT_EQ(kBody, client_->SendSynchronousRequest( |
| 2219 client_->SendSynchronousRequest("https://google.com/push_example")); | 2253 "https://example.com/push_example")); |
| 2220 for (const string& url : push_urls) { | 2254 for (const string& url : push_urls) { |
| 2221 DVLOG(1) << "send request for pushed stream on url " << url; | 2255 DVLOG(1) << "send request for pushed stream on url " << url; |
| 2222 string expected_body = "This is server push response body for " + url; | 2256 string expected_body = "This is server push response body for " + url; |
| 2223 string response_body = client_->SendSynchronousRequest(url); | 2257 string response_body = client_->SendSynchronousRequest(url); |
| 2224 DVLOG(1) << "response body " << response_body; | 2258 DVLOG(1) << "response body " << response_body; |
| 2225 EXPECT_EQ(expected_body, response_body); | 2259 EXPECT_EQ(expected_body, response_body); |
| 2226 } | 2260 } |
| 2227 } | 2261 } |
| 2228 | 2262 |
| 2263 TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { |
| 2264 // Tests that sending a request which has 4 push resources will trigger server |
| 2265 // to push those 4 resources and client can handle pushed resources and match |
| 2266 // them with requests later. |
| 2267 ASSERT_TRUE(Initialize()); |
| 2268 |
| 2269 client_->client()->WaitForCryptoHandshakeConfirmed(); |
| 2270 |
| 2271 // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. |
| 2272 SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); |
| 2273 SetReorderPercentage(30); |
| 2274 |
| 2275 // Add a response with headers, body, and push resources. |
| 2276 const string kBody = "body content"; |
| 2277 size_t const kNumResources = 4; |
| 2278 string push_urls[] = { |
| 2279 "https://example.com/font.woff", "https://example.com/script.js", |
| 2280 "https://fonts.example.com/font.woff", |
| 2281 "https://example.com/logo-hires.jpg", |
| 2282 }; |
| 2283 AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, |
| 2284 push_urls, kNumResources, 0); |
| 2285 client_->client()->set_response_listener(new TestResponseListener); |
| 2286 |
| 2287 // Send the first request: this will trigger the server to send all the push |
| 2288 // resources associated with this request, and these will be cached by the |
| 2289 // client. |
| 2290 EXPECT_EQ(kBody, client_->SendSynchronousRequest( |
| 2291 "https://example.com/push_example")); |
| 2292 EXPECT_EQ(1u + kNumResources, client_->num_responses()); |
| 2293 |
| 2294 for (string url : push_urls) { |
| 2295 // Sending subsequent requesets will not actually send anything on the wire, |
| 2296 // as the responses are already in the client's cache. |
| 2297 DVLOG(1) << "send request for pushed stream on url " << url; |
| 2298 string expected_body = "This is server push response body for " + url; |
| 2299 string response_body = client_->SendSynchronousRequest(url); |
| 2300 DVLOG(1) << "response body " << response_body; |
| 2301 EXPECT_EQ(expected_body, response_body); |
| 2302 } |
| 2303 // Expect only original request has been sent and push responses have been |
| 2304 // received as normal response. |
| 2305 EXPECT_EQ(1u, client_->num_requests()); |
| 2306 } |
| 2307 |
| 2308 TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { |
| 2309 // Tests that when streams are not blocked by flow control or congestion |
| 2310 // control, pushing even more resources than max number of open outgoing |
| 2311 // streams should still work because all response streams get closed |
| 2312 // immediately after pushing resources. |
| 2313 ASSERT_TRUE(Initialize()); |
| 2314 client_->client()->WaitForCryptoHandshakeConfirmed(); |
| 2315 |
| 2316 // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. |
| 2317 SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); |
| 2318 SetReorderPercentage(30); |
| 2319 |
| 2320 // Add a response with headers, body, and push resources. |
| 2321 const string kBody = "body content"; |
| 2322 |
| 2323 // One more resource than max number of outgoing stream of this session. |
| 2324 const size_t kNumResources = 1 + kNumMaxStreams; // 11. |
| 2325 string push_urls[11]; |
| 2326 for (uint32_t i = 0; i < kNumResources; ++i) { |
| 2327 push_urls[i] = "https://example.com/push_resources" + base::UintToString(i); |
| 2328 } |
| 2329 AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, |
| 2330 push_urls, kNumResources, 0); |
| 2331 client_->client()->set_response_listener(new TestResponseListener); |
| 2332 |
| 2333 // Send the first request: this will trigger the server to send all the push |
| 2334 // resources associated with this request, and these will be cached by the |
| 2335 // client. |
| 2336 EXPECT_EQ(kBody, client_->SendSynchronousRequest( |
| 2337 "https://example.com/push_example")); |
| 2338 // The responses to the original request and all the promised resources |
| 2339 // should have been received. |
| 2340 EXPECT_EQ(12u, client_->num_responses()); |
| 2341 |
| 2342 for (const string& url : push_urls) { |
| 2343 // Sending subsequent requesets will not actually send anything on the wire, |
| 2344 // as the responses are already in the client's cache. |
| 2345 EXPECT_EQ("This is server push response body for " + url, |
| 2346 client_->SendSynchronousRequest(url)); |
| 2347 } |
| 2348 |
| 2349 // Only 1 request should have been sent. |
| 2350 EXPECT_EQ(1u, client_->num_requests()); |
| 2351 } |
| 2352 |
| 2353 TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { |
| 2354 // Tests that when server tries to send more large resources(large enough to |
| 2355 // be blocked by flow control window or congestion control window) than max |
| 2356 // open outgoing streams , server can open upto max number of outgoing |
| 2357 // streams for them, and the rest will be queued up. |
| 2358 |
| 2359 // Reset flow control windows. |
| 2360 size_t kFlowControlWnd = 20 * 1024; // 20KB. |
| 2361 // Response body is larger than 1 flow controlblock window. |
| 2362 size_t kBodySize = kFlowControlWnd * 2; |
| 2363 set_client_initial_stream_flow_control_receive_window(kFlowControlWnd); |
| 2364 // Make sure conntection level flow control window is large enough not to |
| 2365 // block data being sent out though they will be blocked by stream level one. |
| 2366 set_client_initial_session_flow_control_receive_window( |
| 2367 kBodySize * kNumMaxStreams + 1024); |
| 2368 |
| 2369 ASSERT_TRUE(Initialize()); |
| 2370 client_->client()->WaitForCryptoHandshakeConfirmed(); |
| 2371 |
| 2372 // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. |
| 2373 SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); |
| 2374 SetReorderPercentage(30); |
| 2375 |
| 2376 // Add a response with headers, body, and push resources. |
| 2377 const string kBody = "body content"; |
| 2378 |
| 2379 const size_t kNumResources = kNumMaxStreams + 1; |
| 2380 string push_urls[11]; |
| 2381 for (uint32_t i = 0; i < kNumResources; ++i) { |
| 2382 push_urls[i] = "http://example.com/push_resources" + base::UintToString(i); |
| 2383 } |
| 2384 AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, |
| 2385 push_urls, kNumResources, kBodySize); |
| 2386 |
| 2387 client_->client()->set_response_listener(new TestResponseListener); |
| 2388 |
| 2389 client_->SendRequest("https://example.com/push_example"); |
| 2390 |
| 2391 // Pause after the first response arrives. |
| 2392 while (!client_->response_complete()) { |
| 2393 // Because of priority, the first response arrived should be to original |
| 2394 // request. |
| 2395 client_->WaitForResponse(); |
| 2396 } |
| 2397 |
| 2398 // Check server session to see if it has max number of outgoing streams opened |
| 2399 // though more resources need to be pushed. |
| 2400 server_thread_->Pause(); |
| 2401 QuicDispatcher* dispatcher = |
| 2402 QuicServerPeer::GetDispatcher(server_thread_->server()); |
| 2403 ASSERT_EQ(1u, dispatcher->session_map().size()); |
| 2404 QuicSession* session = dispatcher->session_map().begin()->second; |
| 2405 EXPECT_EQ(kNumMaxStreams, session->GetNumOpenOutgoingStreams()); |
| 2406 server_thread_->Resume(); |
| 2407 |
| 2408 EXPECT_EQ(1u, client_->num_requests()); |
| 2409 EXPECT_EQ(1u, client_->num_responses()); |
| 2410 EXPECT_EQ(kBody, client_->response_body()); |
| 2411 |
| 2412 // "Send" request for a promised resources will not really send out it because |
| 2413 // its response is being pushed(but blocked). And the following ack and |
| 2414 // flow control behavior of SendSynchronousRequests() |
| 2415 // will unblock the stream to finish receiving response. |
| 2416 client_->SendSynchronousRequest(push_urls[0]); |
| 2417 EXPECT_EQ(1u, client_->num_requests()); |
| 2418 EXPECT_EQ(2u, client_->num_responses()); |
| 2419 |
| 2420 // Do same thing for the rest 10 resources. |
| 2421 for (uint32_t i = 1; i < kNumResources; ++i) { |
| 2422 client_->SendSynchronousRequest(push_urls[i]); |
| 2423 } |
| 2424 |
| 2425 // Because of server push, client gets all pushed resources without actually |
| 2426 // sending requests for them. |
| 2427 EXPECT_EQ(1u, client_->num_requests()); |
| 2428 // Including response to original request, 12 responses in total were |
| 2429 // recieved. |
| 2430 EXPECT_EQ(12u, client_->num_responses()); |
| 2431 } |
| 2432 |
| 2229 } // namespace | 2433 } // namespace |
| 2230 } // namespace test | 2434 } // namespace test |
| 2231 } // namespace net | 2435 } // namespace net |
| OLD | NEW |