Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2010 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/spdy/spdy_test_util.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/string_number_conversions.h"
     11 #include "base/string_util.h"
     12 #include "net/http/http_network_session.h"
     13 #include "net/http/http_network_transaction.h"
     14 #include "net/spdy/spdy_framer.h"
     15 #include "net/spdy/spdy_http_utils.h"
     16 
     17 namespace net {
     18 
     19 // Chop a frame into an array of MockWrites.
     20 // |data| is the frame to chop.
     21 // |length| is the length of the frame to chop.
     22 // |num_chunks| is the number of chunks to create.
     23 MockWrite* ChopWriteFrame(const char* data, int length, int num_chunks) {
     24   MockWrite* chunks = new MockWrite[num_chunks];
     25   int chunk_size = length / num_chunks;
     26   for (int index = 0; index < num_chunks; index++) {
     27     const char* ptr = data + (index * chunk_size);
     28     if (index == num_chunks - 1)
     29       chunk_size += length % chunk_size;  // The last chunk takes the remainder.
     30     chunks[index] = MockWrite(true, ptr, chunk_size);
     31   }
     32   return chunks;
     33 }
     34 
     35 // Chop a SpdyFrame into an array of MockWrites.
     36 // |frame| is the frame to chop.
     37 // |num_chunks| is the number of chunks to create.
     38 MockWrite* ChopWriteFrame(const spdy::SpdyFrame& frame, int num_chunks) {
     39   return ChopWriteFrame(frame.data(),
     40                         frame.length() + spdy::SpdyFrame::size(),
     41                         num_chunks);
     42 }
     43 
     44 // Chop a frame into an array of MockReads.
     45 // |data| is the frame to chop.
     46 // |length| is the length of the frame to chop.
     47 // |num_chunks| is the number of chunks to create.
     48 MockRead* ChopReadFrame(const char* data, int length, int num_chunks) {
     49   MockRead* chunks = new MockRead[num_chunks];
     50   int chunk_size = length / num_chunks;
     51   for (int index = 0; index < num_chunks; index++) {
     52     const char* ptr = data + (index * chunk_size);
     53     if (index == num_chunks - 1)
     54       chunk_size += length % chunk_size;  // The last chunk takes the remainder.
     55     chunks[index] = MockRead(true, ptr, chunk_size);
     56   }
     57   return chunks;
     58 }
     59 
     60 // Chop a SpdyFrame into an array of MockReads.
     61 // |frame| is the frame to chop.
     62 // |num_chunks| is the number of chunks to create.
     63 MockRead* ChopReadFrame(const spdy::SpdyFrame& frame, int num_chunks) {
     64   return ChopReadFrame(frame.data(),
     65                        frame.length() + spdy::SpdyFrame::size(),
     66                        num_chunks);
     67 }
     68 
     69 // Adds headers and values to a map.
     70 // |extra_headers| is an array of { name, value } pairs, arranged as strings
     71 // where the even entries are the header names, and the odd entries are the
     72 // header values.
     73 // |headers| gets filled in from |extra_headers|.
     74 void AppendHeadersToSpdyFrame(const char* const extra_headers[],
     75                               int extra_header_count,
     76                               spdy::SpdyHeaderBlock* headers) {
     77   std::string this_header;
     78   std::string this_value;
     79 
     80   if (!extra_header_count)
     81     return;
     82 
     83   // Sanity check: Non-NULL header list.
     84   DCHECK(NULL != extra_headers) << "NULL header value pair list";
     85   // Sanity check: Non-NULL header map.
     86   DCHECK(NULL != headers) << "NULL header map";
     87   // Copy in the headers.
     88   for (int i = 0; i < extra_header_count; i++) {
     89     // Sanity check: Non-empty header.
     90     DCHECK_NE('\0', *extra_headers[i * 2]) << "Empty header value pair";
     91     this_header = extra_headers[i * 2];
     92     std::string::size_type header_len = this_header.length();
     93     if (!header_len)
     94       continue;
     95     this_value = extra_headers[1 + (i * 2)];
     96     std::string new_value;
     97     if (headers->find(this_header) != headers->end()) {
     98       // More than one entry in the header.
     99       // Don't add the header again, just the append to the value,
    100       // separated by a NULL character.
    101 
    102       // Adjust the value.
    103       new_value = (*headers)[this_header];
    104       // Put in a NULL separator.
    105       new_value.append(1, '\0');
    106       // Append the new value.
    107       new_value += this_value;
    108     } else {
    109       // Not a duplicate, just write the value.
    110       new_value = this_value;
    111     }
    112     (*headers)[this_header] = new_value;
    113   }
    114 }
    115 
    116 // Writes |val| to a location of size |len|, in big-endian format.
    117 // in the buffer pointed to by |buffer_handle|.
    118 // Updates the |*buffer_handle| pointer by |len|
    119 // Returns the number of bytes written
    120 int AppendToBuffer(int val,
    121                    int len,
    122                    unsigned char** buffer_handle,
    123                    int* buffer_len_remaining) {
    124   if (len <= 0)
    125     return 0;
    126   DCHECK((size_t) len <= sizeof(len)) << "Data length too long for data type";
    127   DCHECK(NULL != buffer_handle) << "NULL buffer handle";
    128   DCHECK(NULL != *buffer_handle) << "NULL pointer";
    129   DCHECK(NULL != buffer_len_remaining)
    130       << "NULL buffer remainder length pointer";
    131   DCHECK_GE(*buffer_len_remaining, len) << "Insufficient buffer size";
    132   for (int i = 0; i < len; i++) {
    133     int shift = (8 * (len - (i + 1)));
    134     unsigned char val_chunk = (val >> shift) & 0x0FF;
    135     *(*buffer_handle)++ = val_chunk;
    136     *buffer_len_remaining += 1;
    137   }
    138   return len;
    139 }
    140 
    141 // Construct a SPDY packet.
    142 // |head| is the start of the packet, up to but not including
    143 // the header value pairs.
    144 // |extra_headers| are the extra header-value pairs, which typically
    145 // will vary the most between calls.
    146 // |tail| is any (relatively constant) header-value pairs to add.
    147 // |buffer| is the buffer we're filling in.
    148 // Returns a SpdyFrame.
    149 spdy::SpdyFrame* ConstructSpdyPacket(const SpdyHeaderInfo& header_info,
    150                                      const char* const extra_headers[],
    151                                      int extra_header_count,
    152                                      const char* const tail[],
    153                                      int tail_header_count) {
    154   spdy::SpdyFramer framer;
    155   spdy::SpdyHeaderBlock headers;
    156   // Copy in the extra headers to our map.
    157   AppendHeadersToSpdyFrame(extra_headers, extra_header_count, &headers);
    158   // Copy in the tail headers to our map.
    159   if (tail && tail_header_count)
    160     AppendHeadersToSpdyFrame(tail, tail_header_count, &headers);
    161   spdy::SpdyFrame* frame = NULL;
    162   switch (header_info.kind) {
    163     case spdy::SYN_STREAM:
    164       frame = framer.CreateSynStream(header_info.id, header_info.assoc_id,
    165                                      header_info.priority,
    166                                      header_info.control_flags,
    167                                      header_info.compressed, &headers);
    168       break;
    169     case spdy::SYN_REPLY:
    170       frame = framer.CreateSynReply(header_info.id, header_info.control_flags,
    171                                     header_info.compressed, &headers);
    172       break;
    173     case spdy::RST_STREAM:
    174       frame = framer.CreateRstStream(header_info.id, header_info.status);
    175       break;
    176     case spdy::HEADERS:
    177       frame = framer.CreateHeaders(header_info.id, header_info.control_flags,
    178                                    header_info.compressed, &headers);
    179       break;
    180     default:
    181       frame = framer.CreateDataFrame(header_info.id, header_info.data,
    182                                      header_info.data_length,
    183                                      header_info.data_flags);
    184       break;
    185   }
    186   return frame;
    187 }
    188 
    189 // Construct an expected SPDY SETTINGS frame.
    190 // |settings| are the settings to set.
    191 // Returns the constructed frame.  The caller takes ownership of the frame.
    192 spdy::SpdyFrame* ConstructSpdySettings(spdy::SpdySettings settings) {
    193   spdy::SpdyFramer framer;
    194   return framer.CreateSettings(settings);
    195 }
    196 
    197 // Construct a SPDY GOAWAY frame.
    198 // Returns the constructed frame.  The caller takes ownership of the frame.
    199 spdy::SpdyFrame* ConstructSpdyGoAway() {
    200   spdy::SpdyFramer framer;
    201   return framer.CreateGoAway(0);
    202 }
    203 
    204 // Construct a SPDY WINDOW_UPDATE frame.
    205 // Returns the constructed frame.  The caller takes ownership of the frame.
    206 spdy::SpdyFrame* ConstructSpdyWindowUpdate(
    207     const spdy::SpdyStreamId stream_id, uint32 delta_window_size) {
    208   spdy::SpdyFramer framer;
    209   return framer.CreateWindowUpdate(stream_id, delta_window_size);
    210 }
    211 
    212 // Construct a SPDY RST_STREAM frame.
    213 // Returns the constructed frame.  The caller takes ownership of the frame.
    214 spdy::SpdyFrame* ConstructSpdyRstStream(spdy::SpdyStreamId stream_id,
    215                                         spdy::SpdyStatusCodes status) {
    216   spdy::SpdyFramer framer;
    217   return framer.CreateRstStream(stream_id, status);
    218 }
    219 
    220 // Construct a single SPDY header entry, for validation.
    221 // |extra_headers| are the extra header-value pairs.
    222 // |buffer| is the buffer we're filling in.
    223 // |index| is the index of the header we want.
    224 // Returns the number of bytes written into |buffer|.
    225 int ConstructSpdyHeader(const char* const extra_headers[],
    226                         int extra_header_count,
    227                         char* buffer,
    228                         int buffer_length,
    229                         int index) {
    230   const char* this_header = NULL;
    231   const char* this_value = NULL;
    232   if (!buffer || !buffer_length)
    233     return 0;
    234   *buffer = '\0';
    235   // Sanity check: Non-empty header list.
    236   DCHECK(NULL != extra_headers) << "NULL extra headers pointer";
    237   // Sanity check: Index out of range.
    238   DCHECK((index >= 0) && (index < extra_header_count))
    239       << "Index " << index
    240       << " out of range [0, " << extra_header_count << ")";
    241   this_header = extra_headers[index * 2];
    242   // Sanity check: Non-empty header.
    243   if (!*this_header)
    244     return 0;
    245   std::string::size_type header_len = strlen(this_header);
    246   if (!header_len)
    247     return 0;
    248   this_value = extra_headers[1 + (index * 2)];
    249   // Sanity check: Non-empty value.
    250   if (!*this_value)
    251     this_value = "";
    252   int n = base::snprintf(buffer,
    253                          buffer_length,
    254                          "%s: %s\r\n",
    255                          this_header,
    256                          this_value);
    257   return n;
    258 }
    259 
    260 spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
    261                                            int extra_header_count,
    262                                            bool compressed,
    263                                            int stream_id,
    264                                            RequestPriority request_priority,
    265                                            spdy::SpdyControlType type,
    266                                            spdy::SpdyControlFlags flags,
    267                                            const char* const* kHeaders,
    268                                            int kHeadersSize) {
    269   return ConstructSpdyControlFrame(extra_headers,
    270                                    extra_header_count,
    271                                    compressed,
    272                                    stream_id,
    273                                    request_priority,
    274                                    type,
    275                                    flags,
    276                                    kHeaders,
    277                                    kHeadersSize,
    278                                    0);
    279 }
    280 
    281 spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
    282                                            int extra_header_count,
    283                                            bool compressed,
    284                                            int stream_id,
    285                                            RequestPriority request_priority,
    286                                            spdy::SpdyControlType type,
    287                                            spdy::SpdyControlFlags flags,
    288                                            const char* const* kHeaders,
    289                                            int kHeadersSize,
    290                                            int associated_stream_id) {
    291   const SpdyHeaderInfo kSynStartHeader = {
    292     type,                         // Kind = Syn
    293     stream_id,                    // Stream ID
    294     associated_stream_id,         // Associated stream ID
    295     ConvertRequestPriorityToSpdyPriority(request_priority),
    296                                   // Priority
    297     flags,                        // Control Flags
    298     compressed,                   // Compressed
    299     spdy::INVALID,                // Status
    300     NULL,                         // Data
    301     0,                            // Length
    302     spdy::DATA_FLAG_NONE          // Data Flags
    303   };
    304   return ConstructSpdyPacket(kSynStartHeader,
    305                              extra_headers,
    306                              extra_header_count,
    307                              kHeaders,
    308                              kHeadersSize / 2);
    309 }
    310 
    311 // Constructs a standard SPDY GET SYN packet, optionally compressed
    312 // for the url |url|.
    313 // |extra_headers| are the extra header-value pairs, which typically
    314 // will vary the most between calls.
    315 // Returns a SpdyFrame.
    316 spdy::SpdyFrame* ConstructSpdyGet(const char* const url,
    317                                   bool compressed,
    318                                   int stream_id,
    319                                   RequestPriority request_priority) {
    320   const SpdyHeaderInfo kSynStartHeader = {
    321     spdy::SYN_STREAM,             // Kind = Syn
    322     stream_id,                    // Stream ID
    323     0,                            // Associated stream ID
    324     net::ConvertRequestPriorityToSpdyPriority(request_priority),
    325                                   // Priority
    326     spdy::CONTROL_FLAG_FIN,       // Control Flags
    327     compressed,                   // Compressed
    328     spdy::INVALID,                // Status
    329     NULL,                         // Data
    330     0,                            // Length
    331     spdy::DATA_FLAG_NONE          // Data Flags
    332   };
    333 
    334   GURL gurl(url);
    335 
    336   // This is so ugly.  Why are we using char* in here again?
    337   std::string str_path = gurl.PathForRequest();
    338   std::string str_scheme = gurl.scheme();
    339   std::string str_host = gurl.host();
    340   if (gurl.has_port()) {
    341     str_host += ":";
    342     str_host += gurl.port();
    343   }
    344   scoped_array<char> req(new char[str_path.size() + 1]);
    345   scoped_array<char> scheme(new char[str_scheme.size() + 1]);
    346   scoped_array<char> host(new char[str_host.size() + 1]);
    347   memcpy(req.get(), str_path.c_str(), str_path.size());
    348   memcpy(scheme.get(), str_scheme.c_str(), str_scheme.size());
    349   memcpy(host.get(), str_host.c_str(), str_host.size());
    350   req.get()[str_path.size()] = '\0';
    351   scheme.get()[str_scheme.size()] = '\0';
    352   host.get()[str_host.size()] = '\0';
    353 
    354   const char* const headers[] = {
    355     "method",
    356     "GET",
    357     "url",
    358     req.get(),
    359     "host",
    360     host.get(),
    361     "scheme",
    362     scheme.get(),
    363     "version",
    364     "HTTP/1.1"
    365   };
    366   return ConstructSpdyPacket(
    367       kSynStartHeader,
    368       NULL,
    369       0,
    370       headers,
    371       arraysize(headers) / 2);
    372 }
    373 
    374 // Constructs a standard SPDY GET SYN packet, optionally compressed.
    375 // |extra_headers| are the extra header-value pairs, which typically
    376 // will vary the most between calls.
    377 // Returns a SpdyFrame.
    378 spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
    379                                   int extra_header_count,
    380                                   bool compressed,
    381                                   int stream_id,
    382                                   RequestPriority request_priority) {
    383   return ConstructSpdyGet(extra_headers, extra_header_count, compressed,
    384                           stream_id, request_priority, true);
    385 }
    386 
    387 // Constructs a standard SPDY GET SYN packet, optionally compressed.
    388 // |extra_headers| are the extra header-value pairs, which typically
    389 // will vary the most between calls.
    390 // Returns a SpdyFrame.
    391 spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
    392                                   int extra_header_count,
    393                                   bool compressed,
    394                                   int stream_id,
    395                                   RequestPriority request_priority,
    396                                   bool direct) {
    397   const char* const kStandardGetHeaders[] = {
    398     "method",
    399     "GET",
    400     "url",
    401     (direct ? "/" : "http://www.google.com/"),
    402     "host",
    403     "www.google.com",
    404     "scheme",
    405     "http",
    406     "version",
    407     "HTTP/1.1"
    408   };
    409   return ConstructSpdyControlFrame(extra_headers,
    410                                    extra_header_count,
    411                                    compressed,
    412                                    stream_id,
    413                                    request_priority,
    414                                    spdy::SYN_STREAM,
    415                                    spdy::CONTROL_FLAG_FIN,
    416                                    kStandardGetHeaders,
    417                                    arraysize(kStandardGetHeaders));
    418 }
    419 
    420 // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
    421 spdy::SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
    422                                       int extra_header_count,
    423                                       int stream_id) {
    424   const char* const kConnectHeaders[] = {
    425     "method", "CONNECT",
    426     "url", "www.google.com:443",
    427     "host", "www.google.com",
    428     "version", "HTTP/1.1",
    429   };
    430   return ConstructSpdyControlFrame(extra_headers,
    431                                    extra_header_count,
    432                                    /*compressed*/ false,
    433                                    stream_id,
    434                                    LOWEST,
    435                                    spdy::SYN_STREAM,
    436                                    spdy::CONTROL_FLAG_NONE,
    437                                    kConnectHeaders,
    438                                    arraysize(kConnectHeaders));
    439 }
    440 
    441 // Constructs a standard SPDY push SYN packet.
    442 // |extra_headers| are the extra header-value pairs, which typically
    443 // will vary the most between calls.
    444 // Returns a SpdyFrame.
    445 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
    446                                    int extra_header_count,
    447                                    int stream_id,
    448                                    int associated_stream_id) {
    449   const char* const kStandardGetHeaders[] = {
    450     "hello",
    451     "bye",
    452     "status",
    453     "200",
    454     "version",
    455     "HTTP/1.1"
    456   };
    457   return ConstructSpdyControlFrame(extra_headers,
    458                                    extra_header_count,
    459                                    false,
    460                                    stream_id,
    461                                    LOWEST,
    462                                    spdy::SYN_STREAM,
    463                                    spdy::CONTROL_FLAG_NONE,
    464                                    kStandardGetHeaders,
    465                                    arraysize(kStandardGetHeaders),
    466                                    associated_stream_id);
    467 }
    468 
    469 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
    470                                    int extra_header_count,
    471                                    int stream_id,
    472                                    int associated_stream_id,
    473                                    const char* url) {
    474   const char* const kStandardGetHeaders[] = {
    475     "hello",
    476     "bye",
    477     "status",
    478     "200 OK",
    479     "url",
    480     url,
    481     "version",
    482     "HTTP/1.1"
    483   };
    484   return ConstructSpdyControlFrame(extra_headers,
    485                                    extra_header_count,
    486                                    false,
    487                                    stream_id,
    488                                    LOWEST,
    489                                    spdy::SYN_STREAM,
    490                                    spdy::CONTROL_FLAG_NONE,
    491                                    kStandardGetHeaders,
    492                                    arraysize(kStandardGetHeaders),
    493                                    associated_stream_id);
    494 
    495 }
    496 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
    497                                    int extra_header_count,
    498                                    int stream_id,
    499                                    int associated_stream_id,
    500                                    const char* url,
    501                                    const char* status,
    502                                    const char* location) {
    503   const char* const kStandardGetHeaders[] = {
    504     "hello",
    505     "bye",
    506     "status",
    507     status,
    508     "location",
    509     location,
    510     "url",
    511     url,
    512     "version",
    513     "HTTP/1.1"
    514   };
    515   return ConstructSpdyControlFrame(extra_headers,
    516                                    extra_header_count,
    517                                    false,
    518                                    stream_id,
    519                                    LOWEST,
    520                                    spdy::SYN_STREAM,
    521                                    spdy::CONTROL_FLAG_NONE,
    522                                    kStandardGetHeaders,
    523                                    arraysize(kStandardGetHeaders),
    524                                    associated_stream_id);
    525 }
    526 
    527 spdy::SpdyFrame* ConstructSpdyPush(int stream_id,
    528                                   int associated_stream_id,
    529                                   const char* url) {
    530   const char* const kStandardGetHeaders[] = {
    531     "url",
    532     url
    533   };
    534   return ConstructSpdyControlFrame(0,
    535                                    0,
    536                                    false,
    537                                    stream_id,
    538                                    LOWEST,
    539                                    spdy::SYN_STREAM,
    540                                    spdy::CONTROL_FLAG_NONE,
    541                                    kStandardGetHeaders,
    542                                    arraysize(kStandardGetHeaders),
    543                                    associated_stream_id);
    544 }
    545 
    546 spdy::SpdyFrame* ConstructSpdyPushHeaders(int stream_id,
    547                                           const char* const extra_headers[],
    548                                           int extra_header_count) {
    549   const char* const kStandardGetHeaders[] = {
    550     "status",
    551     "200 OK",
    552     "version",
    553     "HTTP/1.1"
    554   };
    555   return ConstructSpdyControlFrame(extra_headers,
    556                                    extra_header_count,
    557                                    false,
    558                                    stream_id,
    559                                    LOWEST,
    560                                    spdy::HEADERS,
    561                                    spdy::CONTROL_FLAG_NONE,
    562                                    kStandardGetHeaders,
    563                                    arraysize(kStandardGetHeaders));
    564 }
    565 
    566 // Constructs a standard SPDY SYN_REPLY packet with the specified status code.
    567 // Returns a SpdyFrame.
    568 spdy::SpdyFrame* ConstructSpdySynReplyError(
    569     const char* const status,
    570     const char* const* const extra_headers,
    571     int extra_header_count,
    572     int stream_id) {
    573   const char* const kStandardGetHeaders[] = {
    574     "hello",
    575     "bye",
    576     "status",
    577     status,
    578     "version",
    579     "HTTP/1.1"
    580   };
    581   return ConstructSpdyControlFrame(extra_headers,
    582                                    extra_header_count,
    583                                    false,
    584                                    stream_id,
    585                                    LOWEST,
    586                                    spdy::SYN_REPLY,
    587                                    spdy::CONTROL_FLAG_NONE,
    588                                    kStandardGetHeaders,
    589                                    arraysize(kStandardGetHeaders));
    590 }
    591 
    592 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
    593 // |extra_headers| are the extra header-value pairs, which typically
    594 // will vary the most between calls.
    595 // Returns a SpdyFrame.
    596 spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id) {
    597   static const char* const kExtraHeaders[] = {
    598     "location",
    599     "http://www.foo.com/index.php",
    600   };
    601   return ConstructSpdySynReplyError("301 Moved Permanently", kExtraHeaders,
    602                                     arraysize(kExtraHeaders)/2, stream_id);
    603 }
    604 
    605 // Constructs a standard SPDY SYN_REPLY packet with an Internal Server
    606 // Error status code.
    607 // Returns a SpdyFrame.
    608 spdy::SpdyFrame* ConstructSpdySynReplyError(int stream_id) {
    609   return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1);
    610 }
    611 
    612 
    613 
    614 
    615 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
    616 // |extra_headers| are the extra header-value pairs, which typically
    617 // will vary the most between calls.
    618 // Returns a SpdyFrame.
    619 spdy::SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
    620                                           int extra_header_count,
    621                                           int stream_id) {
    622   static const char* const kStandardGetHeaders[] = {
    623     "hello",
    624     "bye",
    625     "status",
    626     "200",
    627     "version",
    628     "HTTP/1.1"
    629   };
    630   return ConstructSpdyControlFrame(extra_headers,
    631                                    extra_header_count,
    632                                    false,
    633                                    stream_id,
    634                                    LOWEST,
    635                                    spdy::SYN_REPLY,
    636                                    spdy::CONTROL_FLAG_NONE,
    637                                    kStandardGetHeaders,
    638                                    arraysize(kStandardGetHeaders));
    639 }
    640 
    641 // Constructs a standard SPDY POST SYN packet.
    642 // |content_length| is the size of post data.
    643 // |extra_headers| are the extra header-value pairs, which typically
    644 // will vary the most between calls.
    645 // Returns a SpdyFrame.
    646 spdy::SpdyFrame* ConstructSpdyPost(int64 content_length,
    647                                    const char* const extra_headers[],
    648                                    int extra_header_count) {
    649   std::string length_str = base::Int64ToString(content_length);
    650   const char* post_headers[] = {
    651     "method",
    652     "POST",
    653     "url",
    654     "/",
    655     "host",
    656     "www.google.com",
    657     "scheme",
    658     "http",
    659     "version",
    660     "HTTP/1.1",
    661     "content-length",
    662     length_str.c_str()
    663   };
    664   return ConstructSpdyControlFrame(extra_headers,
    665                                    extra_header_count,
    666                                    false,
    667                                    1,
    668                                    LOWEST,
    669                                    spdy::SYN_STREAM,
    670                                    spdy::CONTROL_FLAG_NONE,
    671                                    post_headers,
    672                                    arraysize(post_headers));
    673 }
    674 
    675 // Constructs a chunked transfer SPDY POST SYN packet.
    676 // |extra_headers| are the extra header-value pairs, which typically
    677 // will vary the most between calls.
    678 // Returns a SpdyFrame.
    679 spdy::SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[],
    680                                           int extra_header_count) {
    681   const char* post_headers[] = {
    682     "method",
    683     "POST",
    684     "url",
    685     "/",
    686     "host",
    687     "www.google.com",
    688     "scheme",
    689     "http",
    690     "version",
    691     "HTTP/1.1"
    692   };
    693   return ConstructSpdyControlFrame(extra_headers,
    694                                    extra_header_count,
    695                                    false,
    696                                    1,
    697                                    LOWEST,
    698                                    spdy::SYN_STREAM,
    699                                    spdy::CONTROL_FLAG_NONE,
    700                                    post_headers,
    701                                    arraysize(post_headers));
    702 }
    703 
    704 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY POST.
    705 // |extra_headers| are the extra header-value pairs, which typically
    706 // will vary the most between calls.
    707 // Returns a SpdyFrame.
    708 spdy::SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
    709                                            int extra_header_count) {
    710   static const char* const kStandardGetHeaders[] = {
    711     "hello",
    712     "bye",
    713     "status",
    714     "200",
    715     "url",
    716     "/index.php",
    717     "version",
    718     "HTTP/1.1"
    719   };
    720   return ConstructSpdyControlFrame(extra_headers,
    721                                    extra_header_count,
    722                                    false,
    723                                    1,
    724                                    LOWEST,
    725                                    spdy::SYN_REPLY,
    726                                    spdy::CONTROL_FLAG_NONE,
    727                                    kStandardGetHeaders,
    728                                    arraysize(kStandardGetHeaders));
    729 }
    730 
    731 // Constructs a single SPDY data frame with the default contents.
    732 spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, bool fin) {
    733   spdy::SpdyFramer framer;
    734   return framer.CreateDataFrame(
    735       stream_id, kUploadData, kUploadDataSize,
    736       fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE);
    737 }
    738 
    739 // Constructs a single SPDY data frame with the given content.
    740 spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
    741                                         uint32 len, bool fin) {
    742   spdy::SpdyFramer framer;
    743   return framer.CreateDataFrame(
    744       stream_id, data, len, fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE);
    745 }
    746 
    747 // Wraps |frame| in the payload of a data frame in stream |stream_id|.
    748 spdy::SpdyFrame* ConstructWrappedSpdyFrame(
    749     const scoped_ptr<spdy::SpdyFrame>& frame,
    750     int stream_id) {
    751   return ConstructSpdyBodyFrame(stream_id, frame->data(),
    752                                 frame->length() + spdy::SpdyFrame::size(),
    753                                 false);
    754 }
    755 
    756 // Construct an expected SPDY reply string.
    757 // |extra_headers| are the extra header-value pairs, which typically
    758 // will vary the most between calls.
    759 // |buffer| is the buffer we're filling in.
    760 // Returns the number of bytes written into |buffer|.
    761 int ConstructSpdyReplyString(const char* const extra_headers[],
    762                              int extra_header_count,
    763                              char* buffer,
    764                              int buffer_length) {
    765   int packet_size = 0;
    766   int header_count = 0;
    767   char* buffer_write = buffer;
    768   int buffer_left = buffer_length;
    769   spdy::SpdyHeaderBlock headers;
    770   if (!buffer || !buffer_length)
    771     return 0;
    772   // Copy in the extra headers.
    773   AppendHeadersToSpdyFrame(extra_headers, extra_header_count, &headers);
    774   header_count = headers.size();
    775   // The iterator gets us the list of header/value pairs in sorted order.
    776   spdy::SpdyHeaderBlock::iterator next = headers.begin();
    777   spdy::SpdyHeaderBlock::iterator last = headers.end();
    778   for ( ; next != last; ++next) {
    779     // Write the header.
    780     int value_len, current_len, offset;
    781     const char* header_string = next->first.c_str();
    782     packet_size += AppendToBuffer(header_string,
    783                                   next->first.length(),
    784                                   &buffer_write,
    785                                   &buffer_left);
    786     packet_size += AppendToBuffer(": ",
    787                                   strlen(": "),
    788                                   &buffer_write,
    789                                   &buffer_left);
    790     // Write the value(s).
    791     const char* value_string = next->second.c_str();
    792     // Check if it's split among two or more values.
    793     value_len = next->second.length();
    794     current_len = strlen(value_string);
    795     offset = 0;
    796     // Handle the first N-1 values.
    797     while (current_len < value_len) {
    798       // Finish this line -- write the current value.
    799       packet_size += AppendToBuffer(value_string + offset,
    800                                     current_len - offset,
    801                                     &buffer_write,
    802                                     &buffer_left);
    803       packet_size += AppendToBuffer("\n",
    804                                     strlen("\n"),
    805                                     &buffer_write,
    806                                     &buffer_left);
    807       // Advance to next value.
    808       offset = current_len + 1;
    809       current_len += 1 + strlen(value_string + offset);
    810       // Start another line -- add the header again.
    811       packet_size += AppendToBuffer(header_string,
    812                                     next->first.length(),
    813                                     &buffer_write,
    814                                     &buffer_left);
    815       packet_size += AppendToBuffer(": ",
    816                                     strlen(": "),
    817                                     &buffer_write,
    818                                     &buffer_left);
    819     }
    820     EXPECT_EQ(value_len, current_len);
    821     // Copy the last (or only) value.
    822     packet_size += AppendToBuffer(value_string + offset,
    823                                   value_len - offset,
    824                                   &buffer_write,
    825                                   &buffer_left);
    826     packet_size += AppendToBuffer("\n",
    827                                   strlen("\n"),
    828                                   &buffer_write,
    829                                   &buffer_left);
    830   }
    831   return packet_size;
    832 }
    833 
    834 // Create a MockWrite from the given SpdyFrame.
    835 MockWrite CreateMockWrite(const spdy::SpdyFrame& req) {
    836   return MockWrite(
    837       true, req.data(), req.length() + spdy::SpdyFrame::size());
    838 }
    839 
    840 // Create a MockWrite from the given SpdyFrame and sequence number.
    841 MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq) {
    842   return CreateMockWrite(req, seq, true);
    843 }
    844 
    845 // Create a MockWrite from the given SpdyFrame and sequence number.
    846 MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq, bool async) {
    847   return MockWrite(
    848       async, req.data(), req.length() + spdy::SpdyFrame::size(), seq);
    849 }
    850 
    851 // Create a MockRead from the given SpdyFrame.
    852 MockRead CreateMockRead(const spdy::SpdyFrame& resp) {
    853   return MockRead(
    854       true, resp.data(), resp.length() + spdy::SpdyFrame::size());
    855 }
    856 
    857 // Create a MockRead from the given SpdyFrame and sequence number.
    858 MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq) {
    859   return CreateMockRead(resp, seq, true);
    860 }
    861 
    862 // Create a MockRead from the given SpdyFrame and sequence number.
    863 MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq, bool async) {
    864   return MockRead(
    865       async, resp.data(), resp.length() + spdy::SpdyFrame::size(), seq);
    866 }
    867 
    868 // Combines the given SpdyFrames into the given char array and returns
    869 // the total length.
    870 int CombineFrames(const spdy::SpdyFrame** frames, int num_frames,
    871                   char* buff, int buff_len) {
    872   int total_len = 0;
    873   for (int i = 0; i < num_frames; ++i) {
    874     total_len += frames[i]->length() + spdy::SpdyFrame::size();
    875   }
    876   DCHECK_LE(total_len, buff_len);
    877   char* ptr = buff;
    878   for (int i = 0; i < num_frames; ++i) {
    879     int len = frames[i]->length() + spdy::SpdyFrame::size();
    880     memcpy(ptr, frames[i]->data(), len);
    881     ptr += len;
    882   }
    883   return total_len;
    884 }
    885 
    886 SpdySessionDependencies::SpdySessionDependencies()
    887     : host_resolver(new MockCachingHostResolver),
    888       cert_verifier(new CertVerifier),
    889       proxy_service(ProxyService::CreateDirect()),
    890       ssl_config_service(new SSLConfigServiceDefaults),
    891       socket_factory(new MockClientSocketFactory),
    892       deterministic_socket_factory(new DeterministicMockClientSocketFactory),
    893       http_auth_handler_factory(
    894           HttpAuthHandlerFactory::CreateDefault(host_resolver.get())) {
    895   // Note: The CancelledTransaction test does cleanup by running all
    896   // tasks in the message loop (RunAllPending).  Unfortunately, that
    897   // doesn't clean up tasks on the host resolver thread; and
    898   // TCPConnectJob is currently not cancellable.  Using synchronous
    899   // lookups allows the test to shutdown cleanly.  Until we have
    900   // cancellable TCPConnectJobs, use synchronous lookups.
    901   host_resolver->set_synchronous_mode(true);
    902 }
    903 
    904 SpdySessionDependencies::SpdySessionDependencies(ProxyService* proxy_service)
    905     : host_resolver(new MockHostResolver),
    906       cert_verifier(new CertVerifier),
    907       proxy_service(proxy_service),
    908       ssl_config_service(new SSLConfigServiceDefaults),
    909       socket_factory(new MockClientSocketFactory),
    910       deterministic_socket_factory(new DeterministicMockClientSocketFactory),
    911       http_auth_handler_factory(
    912           HttpAuthHandlerFactory::CreateDefault(host_resolver.get())) {}
    913 
    914 SpdySessionDependencies::~SpdySessionDependencies() {}
    915 
    916 // static
    917 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSession(
    918     SpdySessionDependencies* session_deps) {
    919   net::HttpNetworkSession::Params params;
    920   params.client_socket_factory = session_deps->socket_factory.get();
    921   params.host_resolver = session_deps->host_resolver.get();
    922   params.cert_verifier = session_deps->cert_verifier.get();
    923   params.proxy_service = session_deps->proxy_service;
    924   params.ssl_config_service = session_deps->ssl_config_service;
    925   params.http_auth_handler_factory =
    926       session_deps->http_auth_handler_factory.get();
    927   return new HttpNetworkSession(params);
    928 }
    929 
    930 // static
    931 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSessionDeterministic(
    932     SpdySessionDependencies* session_deps) {
    933   net::HttpNetworkSession::Params params;
    934   params.client_socket_factory =
    935       session_deps->deterministic_socket_factory.get();
    936   params.host_resolver = session_deps->host_resolver.get();
    937   params.cert_verifier = session_deps->cert_verifier.get();
    938   params.proxy_service = session_deps->proxy_service;
    939   params.ssl_config_service = session_deps->ssl_config_service;
    940   params.http_auth_handler_factory =
    941       session_deps->http_auth_handler_factory.get();
    942   return new HttpNetworkSession(params);
    943 }
    944 
    945 SpdyURLRequestContext::SpdyURLRequestContext() {
    946   set_host_resolver(new MockHostResolver());
    947   set_cert_verifier(new CertVerifier);
    948   set_proxy_service(ProxyService::CreateDirect());
    949   set_ssl_config_service(new SSLConfigServiceDefaults);
    950   set_http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault(
    951       host_resolver()));
    952   net::HttpNetworkSession::Params params;
    953   params.client_socket_factory = &socket_factory_;
    954   params.host_resolver = host_resolver();
    955   params.cert_verifier = cert_verifier();
    956   params.proxy_service = proxy_service();
    957   params.ssl_config_service = ssl_config_service();
    958   params.http_auth_handler_factory = http_auth_handler_factory();
    959   params.network_delegate = network_delegate();
    960   scoped_refptr<HttpNetworkSession> network_session(
    961       new HttpNetworkSession(params));
    962   set_http_transaction_factory(new HttpCache(
    963       network_session,
    964       HttpCache::DefaultBackend::InMemory(0)));
    965 }
    966 
    967 SpdyURLRequestContext::~SpdyURLRequestContext() {
    968   delete http_transaction_factory();
    969   delete http_auth_handler_factory();
    970   delete cert_verifier();
    971   delete host_resolver();
    972 }
    973 
    974 const SpdyHeaderInfo make_spdy_header(spdy::SpdyControlType type) {
    975   const SpdyHeaderInfo kHeader = {
    976     type,                         // Kind = Syn
    977     1,                            // Stream ID
    978     0,                            // Associated stream ID
    979     2,                            // Priority
    980     spdy::CONTROL_FLAG_FIN,       // Control Flags
    981     false,                        // Compressed
    982     spdy::INVALID,                // Status
    983     NULL,                         // Data
    984     0,                            // Length
    985     spdy::DATA_FLAG_NONE          // Data Flags
    986   };
    987   return kHeader;
    988 }
    989 }  // namespace net
    990