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
3 // found in the LICENSE file.
5 #include "net/http/http_network_layer.h"
7 #include "base/strings/stringprintf.h"
8 #include "net/base/net_log.h"
9 #include "net/cert/mock_cert_verifier.h"
10 #include "net/dns/mock_host_resolver.h"
11 #include "net/http/http_network_session.h"
12 #include "net/http/http_server_properties_impl.h"
13 #include "net/http/http_transaction_unittest.h"
14 #include "net/http/transport_security_state.h"
15 #include "net/proxy/proxy_service.h"
16 #include "net/socket/socket_test_util.h"
17 #include "net/spdy/spdy_session_pool.h"
18 #include "net/ssl/ssl_config_service_defaults.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "testing/platform_test.h"
26 class HttpNetworkLayerTest : public PlatformTest {
28 HttpNetworkLayerTest() : ssl_config_service_(new SSLConfigServiceDefaults) {}
30 virtual void SetUp() {
31 ConfigureTestDependencies(ProxyService::CreateDirect());
34 void ConfigureTestDependencies(ProxyService* proxy_service) {
35 cert_verifier_.reset(new MockCertVerifier);
36 transport_security_state_.reset(new TransportSecurityState);
37 proxy_service_.reset(proxy_service);
38 HttpNetworkSession::Params session_params;
39 session_params.client_socket_factory = &mock_socket_factory_;
40 session_params.host_resolver = &host_resolver_;
41 session_params.cert_verifier = cert_verifier_.get();
42 session_params.transport_security_state = transport_security_state_.get();
43 session_params.proxy_service = proxy_service_.get();
44 session_params.ssl_config_service = ssl_config_service_.get();
45 session_params.http_server_properties =
46 http_server_properties_.GetWeakPtr();
47 network_session_ = new HttpNetworkSession(session_params);
48 factory_.reset(new HttpNetworkLayer(network_session_.get()));
51 #if defined (SPDY_PROXY_AUTH_ORIGIN)
52 std::string GetChromeProxy() {
53 return HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString();
57 void ExecuteRequestExpectingContentAndHeader(const std::string& content,
58 const std::string& header,
59 const std::string& value) {
60 TestCompletionCallback callback;
62 HttpRequestInfo request_info;
63 request_info.url = GURL("http://www.google.com/");
64 request_info.method = "GET";
65 request_info.load_flags = LOAD_NORMAL;
67 scoped_ptr<HttpTransaction> trans;
68 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
71 rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
72 if (rv == ERR_IO_PENDING)
73 rv = callback.WaitForResult();
77 rv = ReadTransaction(trans.get(), &contents);
79 EXPECT_EQ(content, contents);
81 if (!header.empty()) {
82 // We also have a server header here that isn't set by the proxy.
83 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue(
88 // Check that |proxy_count| proxies are in the retry list.
89 // These will be, in order, |bad_proxy| and |bad_proxy2|".
90 void TestBadProxies(unsigned int proxy_count, const std::string& bad_proxy,
91 const std::string& bad_proxy2) {
92 const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info();
93 ASSERT_EQ(proxy_count, retry_info.size());
94 ASSERT_TRUE(retry_info.find(bad_proxy) != retry_info.end());
96 ASSERT_TRUE(retry_info.find(bad_proxy2) != retry_info.end());
99 // Simulates a request through a proxy which returns a bypass, which is then
100 // retried through a second proxy that doesn't bypass.
101 // Checks that the expected requests were issued, the expected content was
102 // recieved, and the first proxy |bad_proxy| was marked as bad.
103 void TestProxyFallback(const std::string& bad_proxy) {
104 MockRead data_reads[] = {
105 MockRead("HTTP/1.1 200 OK\r\n"
106 "Connection: proxy-bypass\r\n\r\n"),
107 MockRead("Bypass message"),
108 MockRead(SYNCHRONOUS, OK),
110 TestProxyFallbackWithMockReads(bad_proxy, data_reads,
111 arraysize(data_reads));
114 void TestProxyFallbackWithMockReads(const std::string& bad_proxy,
115 MockRead data_reads[],
116 int data_reads_size) {
117 MockWrite data_writes[] = {
118 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
119 "Host: www.google.com\r\n"
120 "Proxy-Connection: keep-alive\r\n\r\n"),
123 StaticSocketDataProvider data1(data_reads, data_reads_size,
124 data_writes, arraysize(data_writes));
125 mock_socket_factory_.AddSocketDataProvider(&data1);
127 // Second data provider returns the expected content.
128 MockRead data_reads2[] = {
129 MockRead("HTTP/1.0 200 OK\r\n"
130 "Server: not-proxy\r\n\r\n"),
132 MockRead(SYNCHRONOUS, OK),
134 MockWrite data_writes2[] = {
135 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
136 "Host: www.google.com\r\n"
137 "Proxy-Connection: keep-alive\r\n\r\n"),
139 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
140 data_writes2, arraysize(data_writes2));
141 mock_socket_factory_.AddSocketDataProvider(&data2);
143 // Expect that we get "content" and not "Bypass message", and that there's
144 // a "not-proxy" "Server:" header in the final response.
145 ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy");
147 // We should also observe the bad proxy in the retry list.
148 TestBadProxies(1u, bad_proxy, "");
151 // Simulates a request through a proxy which returns a bypass, which is then
152 // retried through a direct connection to the origin site.
153 // Checks that the expected requests were issued, the expected content was
154 // received, and the proxy |bad_proxy| was marked as bad.
155 void TestProxyFallbackToDirect(const std::string& bad_proxy) {
156 MockRead data_reads[] = {
157 MockRead("HTTP/1.1 200 OK\r\n"
158 "Connection: proxy-bypass\r\n\r\n"),
159 MockRead("Bypass message"),
160 MockRead(SYNCHRONOUS, OK),
162 MockWrite data_writes[] = {
163 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
164 "Host: www.google.com\r\n"
165 "Proxy-Connection: keep-alive\r\n\r\n"),
167 StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
168 data_writes, arraysize(data_writes));
169 mock_socket_factory_.AddSocketDataProvider(&data1);
171 // Second data provider returns the expected content.
172 MockRead data_reads2[] = {
173 MockRead("HTTP/1.0 200 OK\r\n"
174 "Server: not-proxy\r\n\r\n"),
176 MockRead(SYNCHRONOUS, OK),
178 MockWrite data_writes2[] = {
179 MockWrite("GET / HTTP/1.1\r\n"
180 "Host: www.google.com\r\n"
181 "Connection: keep-alive\r\n\r\n"),
183 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
184 data_writes2, arraysize(data_writes2));
185 mock_socket_factory_.AddSocketDataProvider(&data2);
187 // Expect that we get "content" and not "Bypass message", and that there's
188 // a "not-proxy" "Server:" header in the final response.
189 ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy");
191 // We should also observe the bad proxy in the retry list.
192 TestBadProxies(1u, bad_proxy, "");
195 // Simulates a request through a proxy which returns a bypass, under a
196 // configuration where there is no valid bypass. |proxy_count| proxies
197 // are expected to be configured.
198 // Checks that the expected requests were issued, the bypass message was the
199 // final received content, and all proxies were marked as bad.
200 void TestProxyFallbackFail(unsigned int proxy_count,
201 const std::string& bad_proxy,
202 const std::string& bad_proxy2) {
203 MockRead data_reads[] = {
204 MockRead("HTTP/1.1 200 OK\r\n"
205 "Connection: proxy-bypass\r\n\r\n"),
206 MockRead("Bypass message"),
207 MockRead(SYNCHRONOUS, OK),
209 MockWrite data_writes[] = {
210 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
211 "Host: www.google.com\r\n"
212 "Proxy-Connection: keep-alive\r\n\r\n"),
214 StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
215 data_writes, arraysize(data_writes));
216 StaticSocketDataProvider data2(data_reads, arraysize(data_reads),
217 data_writes, arraysize(data_writes));
219 mock_socket_factory_.AddSocketDataProvider(&data1);
221 mock_socket_factory_.AddSocketDataProvider(&data2);
223 // Expect that we get "Bypass message", and not "content"..
224 ExecuteRequestExpectingContentAndHeader("Bypass message", "", "");
226 // We should also observe the bad proxy or proxies in the retry list.
227 TestBadProxies(proxy_count, bad_proxy, bad_proxy2);
230 MockClientSocketFactory mock_socket_factory_;
231 MockHostResolver host_resolver_;
232 scoped_ptr<CertVerifier> cert_verifier_;
233 scoped_ptr<TransportSecurityState> transport_security_state_;
234 scoped_ptr<ProxyService> proxy_service_;
235 const scoped_refptr<SSLConfigService> ssl_config_service_;
236 scoped_refptr<HttpNetworkSession> network_session_;
237 scoped_ptr<HttpNetworkLayer> factory_;
238 HttpServerPropertiesImpl http_server_properties_;
241 TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
242 scoped_ptr<HttpTransaction> trans;
243 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
245 EXPECT_TRUE(trans.get() != NULL);
248 TEST_F(HttpNetworkLayerTest, Suspend) {
249 scoped_ptr<HttpTransaction> trans;
250 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
255 factory_->OnSuspend();
257 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
258 EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, rv);
260 ASSERT_TRUE(trans == NULL);
262 factory_->OnResume();
264 rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
268 TEST_F(HttpNetworkLayerTest, GET) {
269 MockRead data_reads[] = {
270 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
271 MockRead("hello world"),
272 MockRead(SYNCHRONOUS, OK),
274 MockWrite data_writes[] = {
275 MockWrite("GET / HTTP/1.1\r\n"
276 "Host: www.google.com\r\n"
277 "Connection: keep-alive\r\n"
278 "User-Agent: Foo/1.0\r\n\r\n"),
280 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
281 data_writes, arraysize(data_writes));
282 mock_socket_factory_.AddSocketDataProvider(&data);
284 TestCompletionCallback callback;
286 HttpRequestInfo request_info;
287 request_info.url = GURL("http://www.google.com/");
288 request_info.method = "GET";
289 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
291 request_info.load_flags = LOAD_NORMAL;
293 scoped_ptr<HttpTransaction> trans;
294 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
297 rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
298 rv = callback.GetResult(rv);
301 std::string contents;
302 rv = ReadTransaction(trans.get(), &contents);
304 EXPECT_EQ("hello world", contents);
307 // Proxy bypass tests. These tests run through various server-induced
308 // proxy-bypass scenarios using both PAC file and fixed proxy params.
309 // The test scenarios are:
310 // - bypass with two proxies configured and the first but not the second
312 // - bypass with one proxy configured and an explicit fallback to direct
314 // - bypass with two proxies configured and both are bypassed
315 // - bypass with one proxy configured which is bypassed with no defined
318 #if defined(SPDY_PROXY_AUTH_ORIGIN)
319 TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassPac) {
320 std::string bad_proxy = GetChromeProxy();
321 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
322 "PROXY " + bad_proxy + "; PROXY good:8080"));
323 TestProxyFallback(bad_proxy);
326 TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassFixed) {
327 std::string bad_proxy = GetChromeProxy();
328 ConfigureTestDependencies(
329 ProxyService::CreateFixed(bad_proxy +", good:8080"));
330 TestProxyFallback(bad_proxy);
333 TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassPac) {
334 std::string bad_proxy = GetChromeProxy();
335 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
336 "PROXY " + bad_proxy + "; DIRECT"));
337 TestProxyFallbackToDirect(bad_proxy);
340 TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassFixed) {
341 std::string bad_proxy = GetChromeProxy();
342 ConfigureTestDependencies(
343 ProxyService::CreateFixed(bad_proxy + ", direct://"));
344 TestProxyFallbackToDirect(bad_proxy);
347 #if defined(DATA_REDUCTION_FALLBACK_HOST)
348 TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassPac) {
349 std::string bad_proxy = GetChromeProxy();
350 std::string bad_proxy2 =
351 HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString();
352 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
353 "PROXY " + bad_proxy + "; PROXY " + bad_proxy2));
354 TestProxyFallbackFail(2u, bad_proxy, bad_proxy2);
357 TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassFixed) {
358 std::string bad_proxy = GetChromeProxy();
359 std::string bad_proxy2 =
360 HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString();
361 ConfigureTestDependencies(ProxyService::CreateFixed(
362 bad_proxy + ", " + bad_proxy2));
363 TestProxyFallbackFail(2u, bad_proxy, bad_proxy2);
367 TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassPac) {
368 std::string bad_proxy = GetChromeProxy();
369 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
370 "PROXY " + bad_proxy));
371 TestProxyFallbackFail(1u, bad_proxy, "");
374 TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassFixed) {
375 std::string bad_proxy = GetChromeProxy();
376 ConfigureTestDependencies(ProxyService::CreateFixed(bad_proxy));
377 TestProxyFallbackFail(1u, bad_proxy, "");
380 TEST_F(HttpNetworkLayerTest, ServerFallbackOnInternalServerError) {
381 // Verify that "500 Internal Server Error" via the data reduction proxy
382 // induces proxy fallback to a second proxy, if configured.
384 // To configure this test, we need to wire up a custom proxy service to use
385 // a pair of proxies. We'll induce fallback via the first and return
386 // the expected data via the second.
387 std::string data_reduction_proxy(
388 HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString());
389 std::string pac_string = base::StringPrintf(
390 "PROXY %s; PROXY good:8080", data_reduction_proxy.data());
391 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(pac_string));
393 MockRead data_reads[] = {
394 MockRead("HTTP/1.1 500 Internal Server Error\r\n\r\n"),
395 MockRead("Bypass message"),
396 MockRead(SYNCHRONOUS, OK),
398 MockWrite data_writes[] = {
399 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
400 "Host: www.google.com\r\n"
401 "Proxy-Connection: keep-alive\r\n\r\n"),
403 StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
404 data_writes, arraysize(data_writes));
405 mock_socket_factory_.AddSocketDataProvider(&data1);
407 // Second data provider returns the expected content.
408 MockRead data_reads2[] = {
409 MockRead("HTTP/1.0 200 OK\r\n"
410 "Server: not-proxy\r\n\r\n"),
412 MockRead(SYNCHRONOUS, OK),
414 MockWrite data_writes2[] = {
415 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
416 "Host: www.google.com\r\n"
417 "Proxy-Connection: keep-alive\r\n\r\n"),
419 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
420 data_writes2, arraysize(data_writes2));
421 mock_socket_factory_.AddSocketDataProvider(&data2);
423 TestCompletionCallback callback;
425 HttpRequestInfo request_info;
426 request_info.url = GURL("http://www.google.com/");
427 request_info.method = "GET";
428 request_info.load_flags = LOAD_NORMAL;
430 scoped_ptr<HttpTransaction> trans;
431 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
434 rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
435 if (rv == ERR_IO_PENDING)
436 rv = callback.WaitForResult();
439 std::string contents;
440 rv = ReadTransaction(trans.get(), &contents);
443 // We should obtain content from the second socket provider write
444 // corresponding to the fallback proxy.
445 EXPECT_EQ("content", contents);
446 // We also have a server header here that isn't set by the proxy.
447 EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue(
448 "server", "not-proxy"));
449 // We should also observe the data reduction proxy in the retry list.
450 ASSERT_TRUE(1u == proxy_service_->proxy_retry_info().size());
451 EXPECT_EQ(data_reduction_proxy,
452 (*proxy_service_->proxy_retry_info().begin()).first);
454 #endif // defined(SPDY_PROXY_AUTH_ORIGIN)
456 TEST_F(HttpNetworkLayerTest, ProxyBypassIgnoredOnDirectConnectionPac) {
457 // Verify that a Connection: proxy-bypass header is ignored when returned
458 // from a directly connected origin server.
459 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult("DIRECT"));
461 MockRead data_reads[] = {
462 MockRead("HTTP/1.1 200 OK\r\n"
463 "Connection: proxy-bypass\r\n\r\n"),
464 MockRead("Bypass message"),
465 MockRead(SYNCHRONOUS, OK),
467 MockWrite data_writes[] = {
468 MockWrite("GET / HTTP/1.1\r\n"
469 "Host: www.google.com\r\n"
470 "Connection: keep-alive\r\n\r\n"),
472 StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
473 data_writes, arraysize(data_writes));
474 mock_socket_factory_.AddSocketDataProvider(&data1);
475 TestCompletionCallback callback;
477 HttpRequestInfo request_info;
478 request_info.url = GURL("http://www.google.com/");
479 request_info.method = "GET";
480 request_info.load_flags = LOAD_NORMAL;
482 scoped_ptr<HttpTransaction> trans;
483 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
486 rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
487 if (rv == ERR_IO_PENDING)
488 rv = callback.WaitForResult();
491 // We should have read the original page data.
492 std::string contents;
493 rv = ReadTransaction(trans.get(), &contents);
495 EXPECT_EQ("Bypass message", contents);
497 // We should have no entries in our bad proxy list.
498 ASSERT_EQ(0u, proxy_service_->proxy_retry_info().size());
501 #if defined(SPDY_PROXY_AUTH_ORIGIN)
502 TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypass) {
503 // Verify that a Chrome-Proxy: bypass=<seconds> header induces proxy
504 // fallback to a second proxy, if configured.
505 std::string bad_proxy = GetChromeProxy();
506 ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
507 "PROXY " + bad_proxy + "; PROXY good:8080"));
509 MockRead data_reads[] = {
510 MockRead("HTTP/1.1 200 OK\r\n"
511 "Connection: keep-alive\r\n"
512 "Chrome-Proxy: bypass=86400\r\n\r\n"),
513 MockRead("Bypass message"),
514 MockRead(SYNCHRONOUS, OK),
517 TestProxyFallbackWithMockReads(bad_proxy, data_reads, arraysize(data_reads));
518 EXPECT_EQ(base::TimeDelta::FromSeconds(86400),
519 (*proxy_service_->proxy_retry_info().begin()).second.current_delay);
521 #endif // defined(SPDY_PROXY_AUTH_ORIGIN)
523 TEST_F(HttpNetworkLayerTest, NetworkVerified) {
524 MockRead data_reads[] = {
525 MockRead("HTTP/1.0 200 OK\r\n\r\n"),
526 MockRead("hello world"),
527 MockRead(SYNCHRONOUS, OK),
529 MockWrite data_writes[] = {
530 MockWrite("GET / HTTP/1.1\r\n"
531 "Host: www.google.com\r\n"
532 "Connection: keep-alive\r\n"
533 "User-Agent: Foo/1.0\r\n\r\n"),
535 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
536 data_writes, arraysize(data_writes));
537 mock_socket_factory_.AddSocketDataProvider(&data);
539 TestCompletionCallback callback;
541 HttpRequestInfo request_info;
542 request_info.url = GURL("http://www.google.com/");
543 request_info.method = "GET";
544 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
546 request_info.load_flags = LOAD_NORMAL;
548 scoped_ptr<HttpTransaction> trans;
549 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
552 rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
553 ASSERT_EQ(OK, callback.GetResult(rv));
555 EXPECT_TRUE(trans->GetResponseInfo()->network_accessed);
558 TEST_F(HttpNetworkLayerTest, NetworkUnVerified) {
559 MockRead data_reads[] = {
560 MockRead(ASYNC, ERR_CONNECTION_RESET),
562 MockWrite data_writes[] = {
563 MockWrite("GET / HTTP/1.1\r\n"
564 "Host: www.google.com\r\n"
565 "Connection: keep-alive\r\n"
566 "User-Agent: Foo/1.0\r\n\r\n"),
568 StaticSocketDataProvider data(data_reads, arraysize(data_reads),
569 data_writes, arraysize(data_writes));
570 mock_socket_factory_.AddSocketDataProvider(&data);
572 TestCompletionCallback callback;
574 HttpRequestInfo request_info;
575 request_info.url = GURL("http://www.google.com/");
576 request_info.method = "GET";
577 request_info.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
579 request_info.load_flags = LOAD_NORMAL;
581 scoped_ptr<HttpTransaction> trans;
582 int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans, NULL);
585 rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
586 ASSERT_EQ(ERR_CONNECTION_RESET, callback.GetResult(rv));
588 // If the response info is null, that means that any consumer won't
589 // see the network accessed bit set.
590 EXPECT_EQ(NULL, trans->GetResponseInfo());