Home | History | Annotate | Download | only in flip
      1 // Copyright (c) 2009 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.
      4 
      5 #include "net/flip/flip_network_transaction.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/ref_counted.h"
      9 #include "net/base/completion_callback.h"
     10 #include "net/base/load_log_unittest.h"
     11 #include "net/base/mock_host_resolver.h"
     12 #include "net/base/ssl_config_service_defaults.h"
     13 #include "net/base/test_completion_callback.h"
     14 #include "net/base/upload_data.h"
     15 #include "net/flip/flip_protocol.h"
     16 #include "net/http/http_network_session.h"
     17 #include "net/http/http_transaction_unittest.h"
     18 #include "net/proxy/proxy_config_service_fixed.h"
     19 #include "net/socket/socket_test_util.h"
     20 #include "testing/platform_test.h"
     21 
     22 //-----------------------------------------------------------------------------
     23 
     24 namespace net {
     25 
     26 namespace {
     27 
     28 // Create a proxy service which fails on all requests (falls back to direct).
     29 ProxyService* CreateNullProxyService() {
     30   return ProxyService::CreateNull();
     31 }
     32 
     33 // Helper to manage the lifetimes of the dependencies for a
     34 // FlipNetworkTransaction.
     35 class SessionDependencies {
     36  public:
     37   // Default set of dependencies -- "null" proxy service.
     38   SessionDependencies()
     39       : host_resolver(new MockHostResolver),
     40         proxy_service(CreateNullProxyService()),
     41         ssl_config_service(new SSLConfigServiceDefaults),
     42         flip_session_pool(new FlipSessionPool) {
     43     // Note: The CancelledTransaction test does cleanup by running all tasks
     44     // in the message loop (RunAllPending).  Unfortunately, that doesn't clean
     45     // up tasks on the host resolver thread; and TCPConnectJob is currently
     46     // not cancellable.  Using synchronous lookups allows the test to shutdown
     47     // cleanly.  Until we have cancellable TCPConnectJobs, use synchronous
     48     // lookups.
     49     host_resolver->set_synchronous_mode(true);
     50   }
     51 
     52   // Custom proxy service dependency.
     53   explicit SessionDependencies(ProxyService* proxy_service)
     54       : host_resolver(new MockHostResolver),
     55         proxy_service(proxy_service),
     56         ssl_config_service(new SSLConfigServiceDefaults),
     57         flip_session_pool(new FlipSessionPool) {}
     58 
     59   scoped_refptr<MockHostResolverBase> host_resolver;
     60   scoped_refptr<ProxyService> proxy_service;
     61   scoped_refptr<SSLConfigService> ssl_config_service;
     62   MockClientSocketFactory socket_factory;
     63   scoped_refptr<FlipSessionPool> flip_session_pool;
     64 };
     65 
     66 ProxyService* CreateFixedProxyService(const std::string& proxy) {
     67   ProxyConfig proxy_config;
     68   proxy_config.proxy_rules.ParseFromString(proxy);
     69   return ProxyService::CreateFixed(proxy_config);
     70 }
     71 
     72 
     73 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
     74   return new HttpNetworkSession(NULL,
     75                                 session_deps->host_resolver,
     76                                 session_deps->proxy_service,
     77                                 &session_deps->socket_factory,
     78                                 session_deps->ssl_config_service,
     79                                 session_deps->flip_session_pool);
     80 }
     81 
     82 // Chop a frame into an array of MockWrites.
     83 // |data| is the frame to chop.
     84 // |length| is the length of the frame to chop.
     85 // |num_chunks| is the number of chunks to create.
     86 MockWrite* ChopFrame(const char* data, int length, int num_chunks) {
     87   MockWrite* chunks = new MockWrite[num_chunks + 1];
     88   int chunk_size = length / num_chunks;
     89   for (int index = 0; index < num_chunks; index++) {
     90     const char* ptr = data + (index * chunk_size);
     91     if (index == num_chunks - 1)
     92       chunk_size += length % chunk_size;  // The last chunk takes the remainder.
     93     chunks[index] = MockWrite(true, ptr, chunk_size);
     94   }
     95   chunks[num_chunks] = MockWrite(true, 0, 0);
     96   return chunks;
     97 }
     98 
     99 // ----------------------------------------------------------------------------
    100 
    101 static const unsigned char kGetSyn[] = {
    102   0x80, 0x01, 0x00, 0x01,                                        // header
    103   0x01, 0x00, 0x00, 0x45,                                        // FIN, len
    104   0x00, 0x00, 0x00, 0x01,                                        // stream id
    105   0xc0, 0x00, 0x00, 0x03,                                        // 4 headers
    106   0x00, 0x06, 'm', 'e', 't', 'h', 'o', 'd',
    107   0x00, 0x03, 'G', 'E', 'T',
    108   0x00, 0x03, 'u', 'r', 'l',
    109   0x00, 0x16, 'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w',
    110               '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o',
    111               'm', '/',
    112   0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    113   0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    114 };
    115 
    116 static const unsigned char kGetSynCompressed[] = {
    117   0x80, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x43,
    118   0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x78, 0xbb,
    119   0xdf, 0xa2, 0x51, 0xb2, 0x62, 0x60, 0x66, 0x60,
    120   0xcb, 0x05, 0xe6, 0xc3, 0xfc, 0x14, 0x06, 0x66,
    121   0x77, 0xd7, 0x10, 0x06, 0x66, 0x90, 0xa0, 0x58,
    122   0x46, 0x49, 0x49, 0x81, 0x95, 0xbe, 0x3e, 0x30,
    123   0xe2, 0xf5, 0xd2, 0xf3, 0xf3, 0xd3, 0x73, 0x52,
    124   0xf5, 0x92, 0xf3, 0x73, 0xf5, 0x19, 0xd8, 0xa1,
    125   0x1a, 0x19, 0x38, 0x60, 0xe6, 0x01, 0x00, 0x00,
    126   0x00, 0xff, 0xff
    127 };
    128 
    129 static const unsigned char kGetSynReply[] = {
    130   0x80, 0x01, 0x00, 0x02,                                        // header
    131   0x00, 0x00, 0x00, 0x45,
    132   0x00, 0x00, 0x00, 0x01,
    133   0x00, 0x00, 0x00, 0x04,                                        // 4 headers
    134   0x00, 0x05, 'h', 'e', 'l', 'l', 'o',                           // "hello"
    135   0x00, 0x03, 'b', 'y', 'e',                                     // "bye"
    136   0x00, 0x06, 's', 't', 'a', 't', 'u', 's',                      // "status"
    137   0x00, 0x03, '2', '0', '0',                                     // "200"
    138   0x00, 0x03, 'u', 'r', 'l',                                     // "url"
    139   0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',  // "/index...
    140   0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',                 // "version"
    141   0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',            // "HTTP/1.1"
    142 };
    143 
    144 static const unsigned char kGetBodyFrame[] = {
    145   0x00, 0x00, 0x00, 0x01,                                        // header
    146   0x01, 0x00, 0x00, 0x06,                                        // FIN, length
    147   'h', 'e', 'l', 'l', 'o', '!',                                  // "hello"
    148 };
    149 
    150 static const unsigned char kPostSyn[] = {
    151   0x80, 0x01, 0x00, 0x01,                                      // header
    152   0x00, 0x00, 0x00, 0x46,                                      // flags, len
    153   0x00, 0x00, 0x00, 0x01,                                      // stream id
    154   0xc0, 0x00, 0x00, 0x03,                                      // 4 headers
    155   0x00, 0x06, 'm', 'e', 't', 'h', 'o', 'd',
    156   0x00, 0x04, 'P', 'O', 'S', 'T',
    157   0x00, 0x03, 'u', 'r', 'l',
    158   0x00, 0x16, 'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w',
    159               '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o',
    160               'm', '/',
    161   0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    162   0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    163 };
    164 
    165 static const unsigned char kPostUploadFrame[] = {
    166   0x00, 0x00, 0x00, 0x01,                                        // header
    167   0x01, 0x00, 0x00, 0x0c,                                        // FIN flag
    168   'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'
    169 };
    170 
    171 // The response
    172 static const unsigned char kPostSynReply[] = {
    173   0x80, 0x01, 0x00, 0x02,                                        // header
    174   0x00, 0x00, 0x00, 0x45,
    175   0x00, 0x00, 0x00, 0x01,
    176   0x00, 0x00, 0x00, 0x04,                                        // 4 headers
    177   0x00, 0x05, 'h', 'e', 'l', 'l', 'o',                           // "hello"
    178   0x00, 0x03, 'b', 'y', 'e',                                     // "bye"
    179   0x00, 0x06, 's', 't', 'a', 't', 'u', 's',                      // "status"
    180   0x00, 0x03, '2', '0', '0',                                     // "200"
    181   0x00, 0x03, 'u', 'r', 'l',                                     // "url"
    182   // "/index.php"
    183   0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    184   0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',                 // "version"
    185   0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',            // "HTTP/1.1"
    186 };
    187 
    188 static const unsigned char kPostBodyFrame[] = {
    189   0x00, 0x00, 0x00, 0x01,                                        // header
    190   0x01, 0x00, 0x00, 0x06,                                        // FIN, length
    191   'h', 'e', 'l', 'l', 'o', '!',                                  // "hello"
    192 };
    193 
    194 }  // namespace
    195 
    196 // A DataProvider where the client must write a request before the reads (e.g.
    197 // the response) will complete.
    198 class DelayedSocketData : public StaticSocketDataProvider,
    199                           public base::RefCounted<DelayedSocketData> {
    200  public:
    201   // |reads| the list of MockRead completions.
    202   // |write_delay| the number of MockWrites to complete before allowing
    203   //               a MockRead to complete.
    204   // |writes| the list of MockWrite completions.
    205   // Note: All MockReads and MockWrites must be async.
    206   // Note: The MockRead and MockWrite lists musts end with a EOF
    207   //       e.g. a MockRead(true, 0, 0);
    208   DelayedSocketData(MockRead* reads, int write_delay, MockWrite* writes)
    209     : StaticSocketDataProvider(reads, writes),
    210       write_delay_(write_delay),
    211       ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
    212     DCHECK_GE(write_delay_, 0);
    213   }
    214 
    215   // |connect| the result for the connect phase.
    216   // |reads| the list of MockRead completions.
    217   // |write_delay| the number of MockWrites to complete before allowing
    218   //               a MockRead to complete.
    219   // |writes| the list of MockWrite completions.
    220   // Note: All MockReads and MockWrites must be async.
    221   // Note: The MockRead and MockWrite lists musts end with a EOF
    222   //       e.g. a MockRead(true, 0, 0);
    223   DelayedSocketData(const MockConnect& connect, MockRead* reads,
    224                     int write_delay, MockWrite* writes)
    225     : StaticSocketDataProvider(reads, writes),
    226       write_delay_(write_delay),
    227       ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
    228     DCHECK_GE(write_delay_, 0);
    229     set_connect_data(connect);
    230   }
    231 
    232   virtual MockRead GetNextRead() {
    233     if (write_delay_)
    234       return MockRead(true, ERR_IO_PENDING);
    235     return StaticSocketDataProvider::GetNextRead();
    236   }
    237 
    238   virtual MockWriteResult OnWrite(const std::string& data) {
    239     MockWriteResult rv = StaticSocketDataProvider::OnWrite(data);
    240     // Now that our write has completed, we can allow reads to continue.
    241     if (!--write_delay_)
    242       MessageLoop::current()->PostDelayedTask(FROM_HERE,
    243         factory_.NewRunnableMethod(&DelayedSocketData::CompleteRead), 100);
    244     return rv;
    245   }
    246 
    247   virtual void Reset() {
    248     set_socket(NULL);
    249     factory_.RevokeAll();
    250     StaticSocketDataProvider::Reset();
    251   }
    252 
    253   void CompleteRead() {
    254     if (socket())
    255       socket()->OnReadComplete(GetNextRead());
    256   }
    257 
    258  private:
    259   int write_delay_;
    260   ScopedRunnableMethodFactory<DelayedSocketData> factory_;
    261 };
    262 
    263 class FlipNetworkTransactionTest : public PlatformTest {
    264  protected:
    265   virtual void SetUp() {
    266     // By default, all tests turn off compression.
    267     EnableCompression(false);
    268   }
    269 
    270   virtual void TearDown() {
    271     // Empty the current queue.
    272     MessageLoop::current()->RunAllPending();
    273     PlatformTest::TearDown();
    274   }
    275 
    276   void KeepAliveConnectionResendRequestTest(const MockRead& read_failure);
    277 
    278   struct TransactionHelperResult {
    279     int rv;
    280     std::string status_line;
    281     std::string response_data;
    282     HttpResponseInfo response_info;
    283   };
    284 
    285   void EnableCompression(bool enabled) {
    286     flip::FlipFramer::set_enable_compression_default(enabled);
    287   }
    288 
    289   TransactionHelperResult TransactionHelper(const HttpRequestInfo& request,
    290                                             DelayedSocketData* data,
    291                                             LoadLog* log) {
    292     TransactionHelperResult out;
    293 
    294     // We disable SSL for this test.
    295     FlipSession::SetSSLMode(false);
    296 
    297     SessionDependencies session_deps;
    298     scoped_ptr<FlipNetworkTransaction> trans(
    299         new FlipNetworkTransaction(CreateSession(&session_deps)));
    300 
    301     session_deps.socket_factory.AddSocketDataProvider(data);
    302 
    303     TestCompletionCallback callback;
    304 
    305     int rv = trans->Start(&request, &callback, log);
    306     EXPECT_EQ(ERR_IO_PENDING, rv);
    307 
    308     out.rv = callback.WaitForResult();
    309     if (out.rv != OK)
    310       return out;
    311 
    312     const HttpResponseInfo* response = trans->GetResponseInfo();
    313     EXPECT_TRUE(response->headers != NULL);
    314     EXPECT_TRUE(response->was_fetched_via_spdy);
    315     out.status_line = response->headers->GetStatusLine();
    316     out.response_info = *response;  // Make a copy so we can verify.
    317 
    318     rv = ReadTransaction(trans.get(), &out.response_data);
    319     EXPECT_EQ(OK, rv);
    320 
    321     // Verify that we consumed all test data.
    322     EXPECT_TRUE(data->at_read_eof());
    323     EXPECT_TRUE(data->at_write_eof());
    324 
    325     return out;
    326   }
    327 
    328   void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
    329                                              int expected_status);
    330 
    331   void ConnectStatusHelper(const MockRead& status);
    332 };
    333 
    334 //-----------------------------------------------------------------------------
    335 
    336 // Verify FlipNetworkTransaction constructor.
    337 TEST_F(FlipNetworkTransactionTest, Constructor) {
    338   SessionDependencies session_deps;
    339   scoped_refptr<HttpNetworkSession> session =
    340       CreateSession(&session_deps);
    341   scoped_ptr<HttpTransaction> trans(new FlipNetworkTransaction(session));
    342 }
    343 
    344 TEST_F(FlipNetworkTransactionTest, Get) {
    345   MockWrite writes[] = {
    346     MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
    347               arraysize(kGetSyn)),
    348     MockWrite(true, 0, 0)  // EOF
    349   };
    350 
    351   MockRead reads[] = {
    352     MockRead(true, reinterpret_cast<const char*>(kGetSynReply),
    353              arraysize(kGetSynReply)),
    354     MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    355              arraysize(kGetBodyFrame)),
    356     MockRead(true, 0, 0)  // EOF
    357   };
    358 
    359   HttpRequestInfo request;
    360   request.method = "GET";
    361   request.url = GURL("http://www.google.com/");
    362   request.load_flags = 0;
    363   scoped_refptr<DelayedSocketData> data(
    364       new DelayedSocketData(reads, 1, writes));
    365   TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    366   EXPECT_EQ(OK, out.rv);
    367   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
    368   EXPECT_EQ("hello!", out.response_data);
    369 }
    370 
    371 // Test that a simple POST works.
    372 TEST_F(FlipNetworkTransactionTest, Post) {
    373   static const char upload[] = { "hello world" };
    374 
    375   // Setup the request
    376   HttpRequestInfo request;
    377   request.method = "POST";
    378   request.url = GURL("http://www.google.com/");
    379   request.upload_data = new UploadData();
    380   request.upload_data->AppendBytes(upload, sizeof(upload));
    381 
    382   MockWrite writes[] = {
    383     MockWrite(true, reinterpret_cast<const char*>(kPostSyn),
    384               arraysize(kPostSyn)),
    385     MockWrite(true, reinterpret_cast<const char*>(kPostUploadFrame),
    386               arraysize(kPostUploadFrame)),
    387     MockWrite(true, 0, 0)  // EOF
    388   };
    389 
    390   MockRead reads[] = {
    391     MockRead(true, reinterpret_cast<const char*>(kPostSynReply),
    392              arraysize(kPostSynReply)),
    393     MockRead(true, reinterpret_cast<const char*>(kPostBodyFrame),
    394              arraysize(kPostBodyFrame)),
    395     MockRead(true, 0, 0)  // EOF
    396   };
    397 
    398   scoped_refptr<DelayedSocketData> data(
    399       new DelayedSocketData(reads, 2, writes));
    400   TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    401   EXPECT_EQ(OK, out.rv);
    402   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
    403   EXPECT_EQ("hello!", out.response_data);
    404 }
    405 
    406 // Test that a simple POST works.
    407 TEST_F(FlipNetworkTransactionTest, EmptyPost) {
    408 static const unsigned char kEmptyPostSyn[] = {
    409   0x80, 0x01, 0x00, 0x01,                                      // header
    410   0x01, 0x00, 0x00, 0x46,                                      // flags, len
    411   0x00, 0x00, 0x00, 0x01,                                      // stream id
    412   0xc0, 0x00, 0x00, 0x03,                                      // 4 headers
    413   0x00, 0x06, 'm', 'e', 't', 'h', 'o', 'd',
    414   0x00, 0x04, 'P', 'O', 'S', 'T',
    415   0x00, 0x03, 'u', 'r', 'l',
    416   0x00, 0x16, 'h', 't', 't', 'p', ':', '/', '/', 'w', 'w', 'w',
    417               '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o',
    418               'm', '/',
    419   0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    420   0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    421 };
    422 
    423   // Setup the request
    424   HttpRequestInfo request;
    425   request.method = "POST";
    426   request.url = GURL("http://www.google.com/");
    427   // Create an empty UploadData.
    428   request.upload_data = new UploadData();
    429 
    430   MockWrite writes[] = {
    431     MockWrite(true, reinterpret_cast<const char*>(kEmptyPostSyn),
    432               arraysize(kEmptyPostSyn)),
    433     MockWrite(true, 0, 0)  // EOF
    434   };
    435 
    436   MockRead reads[] = {
    437     MockRead(true, reinterpret_cast<const char*>(kPostSynReply),
    438              arraysize(kPostSynReply)),
    439     MockRead(true, reinterpret_cast<const char*>(kPostBodyFrame),
    440              arraysize(kGetBodyFrame)),
    441     MockRead(true, 0, 0)  // EOF
    442   };
    443 
    444   scoped_refptr<DelayedSocketData> data(
    445     new DelayedSocketData(reads, 1, writes));
    446 
    447   TransactionHelperResult out = TransactionHelper(request, data, NULL);
    448   EXPECT_EQ(OK, out.rv);
    449   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
    450   EXPECT_EQ("hello!", out.response_data);
    451 }
    452 
    453 // Test that the transaction doesn't crash when we don't have a reply.
    454 TEST_F(FlipNetworkTransactionTest, ResponseWithoutSynReply) {
    455   MockRead reads[] = {
    456     MockRead(true, reinterpret_cast<const char*>(kPostBodyFrame),
    457              arraysize(kPostBodyFrame)),
    458     MockRead(true, 0, 0)  // EOF
    459   };
    460 
    461   HttpRequestInfo request;
    462   request.method = "GET";
    463   request.url = GURL("http://www.google.com/");
    464   request.load_flags = 0;
    465   scoped_refptr<DelayedSocketData> data(
    466       new DelayedSocketData(reads, 1, NULL));
    467   TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    468   EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
    469 }
    470 
    471 TEST_F(FlipNetworkTransactionTest, CancelledTransaction) {
    472   MockWrite writes[] = {
    473     MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
    474               arraysize(kGetSyn)),
    475     MockRead(true, 0, 0)  // EOF
    476   };
    477 
    478   MockRead reads[] = {
    479     MockRead(true, reinterpret_cast<const char*>(kGetSynReply),
    480              arraysize(kGetSynReply)),
    481     // This following read isn't used by the test, except during the
    482     // RunAllPending() call at the end since the FlipSession survives the
    483     // FlipNetworkTransaction and still tries to continue Read()'ing.  Any
    484     // MockRead will do here.
    485     MockRead(true, 0, 0)  // EOF
    486   };
    487 
    488   HttpRequestInfo request;
    489   request.method = "GET";
    490   request.url = GURL("http://www.google.com/");
    491   request.load_flags = 0;
    492 
    493   // We disable SSL for this test.
    494   FlipSession::SetSSLMode(false);
    495 
    496   SessionDependencies session_deps;
    497   scoped_ptr<FlipNetworkTransaction> trans(
    498       new FlipNetworkTransaction(CreateSession(&session_deps)));
    499 
    500   StaticSocketDataProvider data(reads, writes);
    501   session_deps.socket_factory.AddSocketDataProvider(&data);
    502 
    503   TestCompletionCallback callback;
    504 
    505   int rv = trans->Start(&request, &callback, NULL);
    506   EXPECT_EQ(ERR_IO_PENDING, rv);
    507   trans.reset();  // Cancel the transaction.
    508 
    509   // Flush the MessageLoop while the SessionDependencies (in particular, the
    510   // MockClientSocketFactory) are still alive.
    511   MessageLoop::current()->RunAllPending();
    512 }
    513 
    514 // Verify that various SynReply headers parse correctly through the
    515 // HTTP layer.
    516 TEST_F(FlipNetworkTransactionTest, SynReplyHeaders) {
    517   // This uses a multi-valued cookie header.
    518   static const unsigned char syn_reply1[] = {
    519     0x80, 0x01, 0x00, 0x02,
    520     0x00, 0x00, 0x00, 0x4c,
    521     0x00, 0x00, 0x00, 0x01,
    522     0x00, 0x00, 0x00, 0x04,
    523     0x00, 0x06, 'c', 'o', 'o', 'k', 'i', 'e',
    524     0x00, 0x09, 'v', 'a', 'l', '1', '\0',
    525                 'v', 'a', 'l', '2',
    526     0x00, 0x06, 's', 't', 'a', 't', 'u', 's',
    527     0x00, 0x03, '2', '0', '0',
    528     0x00, 0x03, 'u', 'r', 'l',
    529     0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    530     0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    531     0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    532   };
    533 
    534   // This is the minimalist set of headers.
    535   static const unsigned char syn_reply2[] = {
    536     0x80, 0x01, 0x00, 0x02,
    537     0x00, 0x00, 0x00, 0x39,
    538     0x00, 0x00, 0x00, 0x01,
    539     0x00, 0x00, 0x00, 0x04,
    540     0x00, 0x06, 's', 't', 'a', 't', 'u', 's',
    541     0x00, 0x03, '2', '0', '0',
    542     0x00, 0x03, 'u', 'r', 'l',
    543     0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    544     0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    545     0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    546   };
    547 
    548   // Headers with a comma separated list.
    549   static const unsigned char syn_reply3[] = {
    550     0x80, 0x01, 0x00, 0x02,
    551     0x00, 0x00, 0x00, 0x4c,
    552     0x00, 0x00, 0x00, 0x01,
    553     0x00, 0x00, 0x00, 0x04,
    554     0x00, 0x06, 'c', 'o', 'o', 'k', 'i', 'e',
    555     0x00, 0x09, 'v', 'a', 'l', '1', ',', 'v', 'a', 'l', '2',
    556     0x00, 0x06, 's', 't', 'a', 't', 'u', 's',
    557     0x00, 0x03, '2', '0', '0',
    558     0x00, 0x03, 'u', 'r', 'l',
    559     0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    560     0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    561     0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    562   };
    563 
    564   struct SynReplyTests {
    565     const unsigned char* syn_reply;
    566     int syn_reply_length;
    567     const char* expected_headers;
    568   } test_cases[] = {
    569     // Test the case of a multi-valued cookie.  When the value is delimited
    570     // with NUL characters, it needs to be unfolded into multiple headers.
    571     { syn_reply1, sizeof(syn_reply1),
    572       "cookie: val1\n"
    573       "cookie: val2\n"
    574       "status: 200\n"
    575       "url: /index.php\n"
    576       "version: HTTP/1.1\n"
    577     },
    578     // This is the simplest set of headers possible.
    579     { syn_reply2, sizeof(syn_reply2),
    580       "status: 200\n"
    581       "url: /index.php\n"
    582       "version: HTTP/1.1\n"
    583     },
    584     // Test that a comma delimited list is NOT interpreted as a multi-value
    585     // name/value pair.  The comma-separated list is just a single value.
    586     { syn_reply3, sizeof(syn_reply3),
    587       "cookie: val1,val2\n"
    588       "status: 200\n"
    589       "url: /index.php\n"
    590       "version: HTTP/1.1\n"
    591     }
    592   };
    593 
    594   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    595     MockWrite writes[] = {
    596       MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
    597                 arraysize(kGetSyn)),
    598       MockWrite(true, 0, 0)  // EOF
    599     };
    600 
    601     MockRead reads[] = {
    602       MockRead(true, reinterpret_cast<const char*>(test_cases[i].syn_reply),
    603                test_cases[i].syn_reply_length),
    604       MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    605                arraysize(kGetBodyFrame)),
    606       MockRead(true, 0, 0)  // EOF
    607     };
    608 
    609     HttpRequestInfo request;
    610     request.method = "GET";
    611     request.url = GURL("http://www.google.com/");
    612     request.load_flags = 0;
    613     scoped_refptr<DelayedSocketData> data(
    614         new DelayedSocketData(reads, 1, writes));
    615     TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    616     EXPECT_EQ(OK, out.rv);
    617     EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
    618     EXPECT_EQ("hello!", out.response_data);
    619 
    620     scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
    621     EXPECT_TRUE(headers.get() != NULL);
    622     void* iter = NULL;
    623     std::string name, value, lines;
    624     while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
    625       lines.append(name);
    626       lines.append(": ");
    627       lines.append(value);
    628       lines.append("\n");
    629     }
    630     EXPECT_EQ(std::string(test_cases[i].expected_headers), lines);
    631   }
    632 }
    633 
    634 // Verify that we don't crash on invalid SynReply responses.
    635 TEST_F(FlipNetworkTransactionTest, InvalidSynReply) {
    636   static const unsigned char kSynReplyMissingStatus[] = {
    637     0x80, 0x01, 0x00, 0x02,
    638     0x00, 0x00, 0x00, 0x3f,
    639     0x00, 0x00, 0x00, 0x01,
    640     0x00, 0x00, 0x00, 0x04,
    641     0x00, 0x06, 'c', 'o', 'o', 'k', 'i', 'e',
    642     0x00, 0x09, 'v', 'a', 'l', '1', '\0',
    643                 'v', 'a', 'l', '2',
    644     0x00, 0x03, 'u', 'r', 'l',
    645     0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    646     0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    647     0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    648   };
    649 
    650   static const unsigned char kSynReplyMissingVersion[] = {
    651     0x80, 0x01, 0x00, 0x02,
    652     0x00, 0x00, 0x00, 0x26,
    653     0x00, 0x00, 0x00, 0x01,
    654     0x00, 0x00, 0x00, 0x04,
    655     0x00, 0x06, 's', 't', 'a', 't', 'u', 's',
    656     0x00, 0x03, '2', '0', '0',
    657     0x00, 0x03, 'u', 'r', 'l',
    658     0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    659   };
    660 
    661   struct SynReplyTests {
    662     const unsigned char* syn_reply;
    663     int syn_reply_length;
    664   } test_cases[] = {
    665     { kSynReplyMissingStatus, arraysize(kSynReplyMissingStatus) },
    666     { kSynReplyMissingVersion, arraysize(kSynReplyMissingVersion) }
    667   };
    668 
    669   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    670     MockWrite writes[] = {
    671       MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
    672                 arraysize(kGetSyn)),
    673       MockWrite(true, 0, 0)  // EOF
    674     };
    675 
    676     MockRead reads[] = {
    677       MockRead(true, reinterpret_cast<const char*>(test_cases[i].syn_reply),
    678                test_cases[i].syn_reply_length),
    679       MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    680                arraysize(kGetBodyFrame)),
    681       MockRead(true, 0, 0)  // EOF
    682     };
    683 
    684     HttpRequestInfo request;
    685     request.method = "GET";
    686     request.url = GURL("http://www.google.com/");
    687     request.load_flags = 0;
    688     scoped_refptr<DelayedSocketData> data(
    689         new DelayedSocketData(reads, 1, writes));
    690     TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    691     EXPECT_EQ(ERR_INVALID_RESPONSE, out.rv);
    692   }
    693 }
    694 
    695 // Verify that we don't crash on some corrupt frames.
    696 TEST_F(FlipNetworkTransactionTest, CorruptFrameSessionError) {
    697   static const unsigned char kSynReplyMassiveLength[] = {
    698     0x80, 0x01, 0x00, 0x02,
    699     0x0f, 0x11, 0x11, 0x26,   // This is the length field with a big number
    700     0x00, 0x00, 0x00, 0x01,
    701     0x00, 0x00, 0x00, 0x04,
    702     0x00, 0x06, 's', 't', 'a', 't', 'u', 's',
    703     0x00, 0x03, '2', '0', '0',
    704     0x00, 0x03, 'u', 'r', 'l',
    705     0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    706   };
    707 
    708   struct SynReplyTests {
    709     const unsigned char* syn_reply;
    710     int syn_reply_length;
    711   } test_cases[] = {
    712     { kSynReplyMassiveLength, arraysize(kSynReplyMassiveLength) }
    713   };
    714 
    715   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
    716     MockWrite writes[] = {
    717       MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
    718                 arraysize(kGetSyn)),
    719       MockWrite(true, 0, 0)  // EOF
    720     };
    721 
    722     MockRead reads[] = {
    723       MockRead(true, reinterpret_cast<const char*>(test_cases[i].syn_reply),
    724                test_cases[i].syn_reply_length),
    725       MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    726                arraysize(kGetBodyFrame)),
    727       MockRead(true, 0, 0)  // EOF
    728     };
    729 
    730     HttpRequestInfo request;
    731     request.method = "GET";
    732     request.url = GURL("http://www.google.com/");
    733     request.load_flags = 0;
    734     scoped_refptr<DelayedSocketData> data(
    735         new DelayedSocketData(reads, 1, writes));
    736     TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    737     EXPECT_EQ(ERR_FLIP_PROTOCOL_ERROR, out.rv);
    738   }
    739 }
    740 
    741 TEST_F(FlipNetworkTransactionTest, DISABLED_ServerPush) {
    742   // Reply with the X-Associated-Content header.
    743   static const unsigned char syn_reply[] = {
    744     0x80, 0x01, 0x00, 0x02,
    745     0x00, 0x00, 0x00, 0x71,
    746     0x00, 0x00, 0x00, 0x01,
    747     0x00, 0x00, 0x00, 0x04,
    748     0x00, 0x14, 'X', '-', 'A', 's', 's', 'o', 'c', 'i', 'a', 't',
    749                 'e', 'd', '-', 'C', 'o', 'n', 't', 'e', 'n', 't',
    750     0x00, 0x20, '1', '?', '?', 'h', 't', 't', 'p', ':', '/', '/', 'w', 'w',
    751                 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm',
    752                 '/', 'f', 'o', 'o', '.', 'd', 'a', 't',
    753     0x00, 0x06, 's', 't', 'a', 't', 'u', 's',
    754     0x00, 0x03, '2', '0', '0',
    755     0x00, 0x03, 'u', 'r', 'l',
    756     0x00, 0x0a, '/', 'i', 'n', 'd', 'e', 'x', '.', 'p', 'h', 'p',
    757     0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    758     0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    759   };
    760 
    761   // Syn for the X-Associated-Content (foo.dat)
    762   static const unsigned char syn_push[] = {
    763     0x80, 0x01, 0x00, 0x01,
    764     0x00, 0x00, 0x00, 0x47,
    765     0x00, 0x00, 0x00, 0x02,
    766     0x00, 0x00, 0x00, 0x04,
    767     0x00, 0x04, 'p', 'a', 't', 'h',
    768     0x00, 0x08, '/', 'f', 'o', 'o', '.', 'd', 'a', 't',
    769     0x00, 0x06, 's', 't', 'a', 't', 'u', 's',
    770     0x00, 0x03, '2', '0', '0',
    771     0x00, 0x03, 'u', 'r', 'l',
    772     0x00, 0x08, '/', 'f', 'o', 'o', '.', 'd', 'a', 't',
    773     0x00, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
    774     0x00, 0x08, 'H', 'T', 'T', 'P', '/', '1', '.', '1',
    775   };
    776 
    777   // Body for stream 2
    778   static const unsigned char body_frame_2[] = {
    779     0x00, 0x00, 0x00, 0x02,
    780     0x01, 0x00, 0x00, 0x07,
    781     'g', 'o', 'o', 'd', 'b', 'y', 'e',
    782   };
    783 
    784   MockWrite writes[] = {
    785     MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
    786               arraysize(kGetSyn)),
    787     MockWrite(true, 0, 0)  // EOF
    788   };
    789 
    790   MockRead reads[] = {
    791     MockRead(true, reinterpret_cast<const char*>(syn_reply),
    792              arraysize(syn_reply)),
    793     MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    794              arraysize(kGetBodyFrame)),
    795     MockRead(true, ERR_IO_PENDING),  // Force a pause
    796     MockRead(true, reinterpret_cast<const char*>(syn_push),
    797              arraysize(syn_push)),
    798     MockRead(true, reinterpret_cast<const char*>(body_frame_2),
    799              arraysize(body_frame_2)),
    800     MockRead(true, ERR_IO_PENDING),  // Force a pause
    801     MockRead(true, 0, 0)  // EOF
    802   };
    803 
    804   // We disable SSL for this test.
    805   FlipSession::SetSSLMode(false);
    806 
    807   enum TestTypes {
    808     // Simulate that the server sends the first request, notifying the client
    809     // that it *will* push the second stream.  But the client issues the
    810     // request for the second stream before the push data arrives.
    811     PUSH_AFTER_REQUEST,
    812     // Simulate that the server is sending the pushed stream data before the
    813     // client requests it.  The FlipSession will buffer the response and then
    814     // deliver the data when the client does make the request.
    815     PUSH_BEFORE_REQUEST,
    816     DONE
    817   };
    818 
    819   for (int test_type = PUSH_AFTER_REQUEST; test_type != DONE; ++test_type) {
    820     // Setup a mock session.
    821     SessionDependencies session_deps;
    822     scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
    823     scoped_refptr<DelayedSocketData> data(
    824         new DelayedSocketData(reads, 1, writes));
    825     session_deps.socket_factory.AddSocketDataProvider(data.get());
    826 
    827     // Issue the first request
    828     {
    829       FlipNetworkTransaction trans(session.get());
    830 
    831       // Issue the first request.
    832       HttpRequestInfo request;
    833       request.method = "GET";
    834       request.url = GURL("http://www.google.com/");
    835       request.load_flags = 0;
    836       TestCompletionCallback callback;
    837       int rv = trans.Start(&request, &callback, NULL);
    838       EXPECT_EQ(ERR_IO_PENDING, rv);
    839 
    840       rv = callback.WaitForResult();
    841       EXPECT_EQ(rv, OK);
    842 
    843       // Verify the SYN_REPLY.
    844       const HttpResponseInfo* response = trans.GetResponseInfo();
    845       EXPECT_TRUE(response->headers != NULL);
    846       EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
    847 
    848       if (test_type == PUSH_BEFORE_REQUEST)
    849         data->CompleteRead();
    850 
    851       // Verify the body.
    852       std::string response_data;
    853       rv = ReadTransaction(&trans, &response_data);
    854       EXPECT_EQ(OK, rv);
    855       EXPECT_EQ("hello!", response_data);
    856     }
    857 
    858     // Issue a second request for the X-Associated-Content.
    859     {
    860       FlipNetworkTransaction trans(session.get());
    861 
    862       HttpRequestInfo request;
    863       request.method = "GET";
    864       request.url = GURL("http://www.google.com/foo.dat");
    865       request.load_flags = 0;
    866       TestCompletionCallback callback;
    867       int rv = trans.Start(&request, &callback, NULL);
    868       EXPECT_EQ(ERR_IO_PENDING, rv);
    869 
    870       // In the case where we are Complete the next read now.
    871       if (test_type == PUSH_AFTER_REQUEST)
    872         data->CompleteRead();
    873 
    874       rv = callback.WaitForResult();
    875       EXPECT_EQ(rv, OK);
    876 
    877       // Verify the SYN_REPLY.
    878       const HttpResponseInfo* response = trans.GetResponseInfo();
    879       EXPECT_TRUE(response->headers != NULL);
    880       EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
    881 
    882       // Verify the body.
    883       std::string response_data;
    884       rv = ReadTransaction(&trans, &response_data);
    885       EXPECT_EQ(OK, rv);
    886       EXPECT_EQ("goodbye", response_data);
    887     }
    888 
    889     // Complete the next read now and teardown.
    890     data->CompleteRead();
    891 
    892     // Verify that we consumed all test data.
    893     EXPECT_TRUE(data->at_read_eof());
    894     EXPECT_TRUE(data->at_write_eof());
    895   }
    896 }
    897 
    898 // Test that we shutdown correctly on write errors.
    899 TEST_F(FlipNetworkTransactionTest, WriteError) {
    900   MockWrite writes[] = {
    901     // We'll write 10 bytes successfully
    902     MockWrite(true, reinterpret_cast<const char*>(kGetSyn), 10),
    903     // Followed by ERROR!
    904     MockWrite(true, ERR_FAILED),
    905     MockWrite(true, 0, 0)  // EOF
    906   };
    907 
    908   MockRead reads[] = {
    909     MockRead(true, reinterpret_cast<const char*>(kGetSynReply),
    910              arraysize(kGetSynReply)),
    911     MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    912              arraysize(kGetBodyFrame)),
    913     MockRead(true, 0, 0)  // EOF
    914   };
    915 
    916   HttpRequestInfo request;
    917   request.method = "GET";
    918   request.url = GURL("http://www.google.com/");
    919   request.load_flags = 0;
    920   scoped_refptr<DelayedSocketData> data(
    921       new DelayedSocketData(reads, 2, writes));
    922   TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    923   EXPECT_EQ(ERR_FAILED, out.rv);
    924   data->Reset();
    925 }
    926 
    927 // Test that partial writes work.
    928 TEST_F(FlipNetworkTransactionTest, PartialWrite) {
    929   // Chop the SYN_STREAM frame into 5 chunks.
    930   const int kChunks = 5;
    931   scoped_array<MockWrite> writes(ChopFrame(
    932       reinterpret_cast<const char*>(kGetSyn), arraysize(kGetSyn), kChunks));
    933 
    934   MockRead reads[] = {
    935     MockRead(true, reinterpret_cast<const char*>(kGetSynReply),
    936              arraysize(kGetSynReply)),
    937     MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    938              arraysize(kGetBodyFrame)),
    939     MockRead(true, 0, 0)  // EOF
    940   };
    941 
    942   HttpRequestInfo request;
    943   request.method = "GET";
    944   request.url = GURL("http://www.google.com/");
    945   request.load_flags = 0;
    946   scoped_refptr<DelayedSocketData> data(
    947       new DelayedSocketData(reads, kChunks, writes.get()));
    948   TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    949   EXPECT_EQ(OK, out.rv);
    950   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
    951   EXPECT_EQ("hello!", out.response_data);
    952 }
    953 
    954 TEST_F(FlipNetworkTransactionTest, DISABLED_ConnectFailure) {
    955   MockConnect connects[]  = {
    956     MockConnect(true, ERR_NAME_NOT_RESOLVED),
    957     MockConnect(false, ERR_NAME_NOT_RESOLVED),
    958     MockConnect(true, ERR_INTERNET_DISCONNECTED),
    959     MockConnect(false, ERR_INTERNET_DISCONNECTED)
    960   };
    961 
    962   for (size_t index = 0; index < arraysize(connects); ++index) {
    963     MockWrite writes[] = {
    964       MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
    965                 arraysize(kGetSyn)),
    966       MockWrite(true, 0, 0)  // EOF
    967     };
    968 
    969     MockRead reads[] = {
    970       MockRead(true, reinterpret_cast<const char*>(kGetSynReply),
    971                arraysize(kGetSynReply)),
    972       MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
    973                arraysize(kGetBodyFrame)),
    974       MockRead(true, 0, 0)  // EOF
    975     };
    976 
    977     HttpRequestInfo request;
    978     request.method = "GET";
    979     request.url = GURL("http://www.google.com/");
    980     request.load_flags = 0;
    981     scoped_refptr<DelayedSocketData> data(
    982         new DelayedSocketData(connects[index], reads, 1, writes));
    983     TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
    984     EXPECT_EQ(connects[index].result, out.rv);
    985   }
    986 }
    987 
    988 // In this test, we enable compression, but get a uncompressed SynReply from
    989 // the server.  Verify that teardown is all clean.
    990 TEST_F(FlipNetworkTransactionTest, DecompressFailureOnSynReply) {
    991   MockWrite writes[] = {
    992     MockWrite(true, reinterpret_cast<const char*>(kGetSynCompressed),
    993               arraysize(kGetSynCompressed)),
    994     MockWrite(true, 0, 0)  // EOF
    995   };
    996 
    997   MockRead reads[] = {
    998     MockRead(true, reinterpret_cast<const char*>(kGetSynReply),
    999              arraysize(kGetSynReply)),
   1000     MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
   1001              arraysize(kGetBodyFrame)),
   1002     MockRead(true, 0, 0)  // EOF
   1003   };
   1004 
   1005   // For this test, we turn on the normal compression.
   1006   EnableCompression(true);
   1007 
   1008   HttpRequestInfo request;
   1009   request.method = "GET";
   1010   request.url = GURL("http://www.google.com/");
   1011   request.load_flags = 0;
   1012   scoped_refptr<DelayedSocketData> data(
   1013       new DelayedSocketData(reads, 1, writes));
   1014   TransactionHelperResult out = TransactionHelper(request, data.get(), NULL);
   1015   EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
   1016   data->Reset();
   1017 
   1018   EnableCompression(false);
   1019 }
   1020 
   1021 // Test that the LoadLog contains good data for a simple GET request.
   1022 TEST_F(FlipNetworkTransactionTest, LoadLog) {
   1023   MockWrite writes[] = {
   1024     MockWrite(true, reinterpret_cast<const char*>(kGetSyn),
   1025               arraysize(kGetSyn)),
   1026     MockWrite(true, 0, 0)  // EOF
   1027   };
   1028 
   1029   MockRead reads[] = {
   1030     MockRead(true, reinterpret_cast<const char*>(kGetSynReply),
   1031              arraysize(kGetSynReply)),
   1032     MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame),
   1033              arraysize(kGetBodyFrame)),
   1034     MockRead(true, 0, 0)  // EOF
   1035   };
   1036 
   1037   scoped_refptr<net::LoadLog> log(new net::LoadLog(net::LoadLog::kUnbounded));
   1038 
   1039   HttpRequestInfo request;
   1040   request.method = "GET";
   1041   request.url = GURL("http://www.google.com/");
   1042   request.load_flags = 0;
   1043   scoped_refptr<DelayedSocketData> data(
   1044       new DelayedSocketData(reads, 1, writes));
   1045   TransactionHelperResult out = TransactionHelper(request, data.get(),
   1046                                                   log);
   1047   EXPECT_EQ(OK, out.rv);
   1048   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   1049   EXPECT_EQ("hello!", out.response_data);
   1050 
   1051   // Check that the LoadLog was filled reasonably.
   1052   // This test is intentionally non-specific about the exact ordering of
   1053   // the log; instead we just check to make sure that certain events exist.
   1054   EXPECT_LT(0u, log->entries().size());
   1055   int pos = 0;
   1056   // We know the first event at position 0.
   1057   EXPECT_TRUE(net::LogContainsBeginEvent(
   1058       *log, 0, net::LoadLog::TYPE_FLIP_TRANSACTION_INIT_CONNECTION));
   1059   // For the rest of the events, allow additional events in the middle,
   1060   // but expect these to be logged in order.
   1061   pos = net::ExpectLogContainsSomewhere(log, 0,
   1062       net::LoadLog::TYPE_FLIP_TRANSACTION_INIT_CONNECTION,
   1063       net::LoadLog::PHASE_END);
   1064   pos = net::ExpectLogContainsSomewhere(log, pos + 1,
   1065       net::LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST,
   1066       net::LoadLog::PHASE_BEGIN);
   1067   pos = net::ExpectLogContainsSomewhere(log, pos + 1,
   1068       net::LoadLog::TYPE_FLIP_TRANSACTION_SEND_REQUEST,
   1069       net::LoadLog::PHASE_END);
   1070   pos = net::ExpectLogContainsSomewhere(log, pos + 1,
   1071       net::LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS,
   1072       net::LoadLog::PHASE_BEGIN);
   1073   pos = net::ExpectLogContainsSomewhere(log, pos + 1,
   1074       net::LoadLog::TYPE_FLIP_TRANSACTION_READ_HEADERS,
   1075       net::LoadLog::PHASE_END);
   1076   pos = net::ExpectLogContainsSomewhere(log, pos + 1,
   1077       net::LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY,
   1078       net::LoadLog::PHASE_BEGIN);
   1079   pos = net::ExpectLogContainsSomewhere(log, pos + 1,
   1080       net::LoadLog::TYPE_FLIP_TRANSACTION_READ_BODY,
   1081       net::LoadLog::PHASE_END);
   1082 }
   1083 
   1084 }  // namespace net
   1085