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 PING frame.
    198 // Returns the constructed frame.  The caller takes ownership of the frame.
    199 spdy::SpdyFrame* ConstructSpdyPing() {
    200   spdy::SpdyFramer framer;
    201   return framer.CreatePingFrame(1);
    202 }
    203 
    204 // Construct a SPDY GOAWAY frame.
    205 // Returns the constructed frame.  The caller takes ownership of the frame.
    206 spdy::SpdyFrame* ConstructSpdyGoAway() {
    207   spdy::SpdyFramer framer;
    208   return framer.CreateGoAway(0);
    209 }
    210 
    211 // Construct a SPDY WINDOW_UPDATE frame.
    212 // Returns the constructed frame.  The caller takes ownership of the frame.
    213 spdy::SpdyFrame* ConstructSpdyWindowUpdate(
    214     const spdy::SpdyStreamId stream_id, uint32 delta_window_size) {
    215   spdy::SpdyFramer framer;
    216   return framer.CreateWindowUpdate(stream_id, delta_window_size);
    217 }
    218 
    219 // Construct a SPDY RST_STREAM frame.
    220 // Returns the constructed frame.  The caller takes ownership of the frame.
    221 spdy::SpdyFrame* ConstructSpdyRstStream(spdy::SpdyStreamId stream_id,
    222                                         spdy::SpdyStatusCodes status) {
    223   spdy::SpdyFramer framer;
    224   return framer.CreateRstStream(stream_id, status);
    225 }
    226 
    227 // Construct a single SPDY header entry, for validation.
    228 // |extra_headers| are the extra header-value pairs.
    229 // |buffer| is the buffer we're filling in.
    230 // |index| is the index of the header we want.
    231 // Returns the number of bytes written into |buffer|.
    232 int ConstructSpdyHeader(const char* const extra_headers[],
    233                         int extra_header_count,
    234                         char* buffer,
    235                         int buffer_length,
    236                         int index) {
    237   const char* this_header = NULL;
    238   const char* this_value = NULL;
    239   if (!buffer || !buffer_length)
    240     return 0;
    241   *buffer = '\0';
    242   // Sanity check: Non-empty header list.
    243   DCHECK(NULL != extra_headers) << "NULL extra headers pointer";
    244   // Sanity check: Index out of range.
    245   DCHECK((index >= 0) && (index < extra_header_count))
    246       << "Index " << index
    247       << " out of range [0, " << extra_header_count << ")";
    248   this_header = extra_headers[index * 2];
    249   // Sanity check: Non-empty header.
    250   if (!*this_header)
    251     return 0;
    252   std::string::size_type header_len = strlen(this_header);
    253   if (!header_len)
    254     return 0;
    255   this_value = extra_headers[1 + (index * 2)];
    256   // Sanity check: Non-empty value.
    257   if (!*this_value)
    258     this_value = "";
    259   int n = base::snprintf(buffer,
    260                          buffer_length,
    261                          "%s: %s\r\n",
    262                          this_header,
    263                          this_value);
    264   return n;
    265 }
    266 
    267 spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
    268                                            int extra_header_count,
    269                                            bool compressed,
    270                                            int stream_id,
    271                                            RequestPriority request_priority,
    272                                            spdy::SpdyControlType type,
    273                                            spdy::SpdyControlFlags flags,
    274                                            const char* const* kHeaders,
    275                                            int kHeadersSize) {
    276   return ConstructSpdyControlFrame(extra_headers,
    277                                    extra_header_count,
    278                                    compressed,
    279                                    stream_id,
    280                                    request_priority,
    281                                    type,
    282                                    flags,
    283                                    kHeaders,
    284                                    kHeadersSize,
    285                                    0);
    286 }
    287 
    288 spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[],
    289                                            int extra_header_count,
    290                                            bool compressed,
    291                                            int stream_id,
    292                                            RequestPriority request_priority,
    293                                            spdy::SpdyControlType type,
    294                                            spdy::SpdyControlFlags flags,
    295                                            const char* const* kHeaders,
    296                                            int kHeadersSize,
    297                                            int associated_stream_id) {
    298   const SpdyHeaderInfo kSynStartHeader = {
    299     type,                         // Kind = Syn
    300     stream_id,                    // Stream ID
    301     associated_stream_id,         // Associated stream ID
    302     ConvertRequestPriorityToSpdyPriority(request_priority),
    303                                   // Priority
    304     flags,                        // Control Flags
    305     compressed,                   // Compressed
    306     spdy::INVALID,                // Status
    307     NULL,                         // Data
    308     0,                            // Length
    309     spdy::DATA_FLAG_NONE          // Data Flags
    310   };
    311   return ConstructSpdyPacket(kSynStartHeader,
    312                              extra_headers,
    313                              extra_header_count,
    314                              kHeaders,
    315                              kHeadersSize / 2);
    316 }
    317 
    318 // Constructs a standard SPDY GET SYN packet, optionally compressed
    319 // for the url |url|.
    320 // |extra_headers| are the extra header-value pairs, which typically
    321 // will vary the most between calls.
    322 // Returns a SpdyFrame.
    323 spdy::SpdyFrame* ConstructSpdyGet(const char* const url,
    324                                   bool compressed,
    325                                   int stream_id,
    326                                   RequestPriority request_priority) {
    327   const SpdyHeaderInfo kSynStartHeader = {
    328     spdy::SYN_STREAM,             // Kind = Syn
    329     stream_id,                    // Stream ID
    330     0,                            // Associated stream ID
    331     net::ConvertRequestPriorityToSpdyPriority(request_priority),
    332                                   // Priority
    333     spdy::CONTROL_FLAG_FIN,       // Control Flags
    334     compressed,                   // Compressed
    335     spdy::INVALID,                // Status
    336     NULL,                         // Data
    337     0,                            // Length
    338     spdy::DATA_FLAG_NONE          // Data Flags
    339   };
    340 
    341   GURL gurl(url);
    342 
    343   // This is so ugly.  Why are we using char* in here again?
    344   std::string str_path = gurl.PathForRequest();
    345   std::string str_scheme = gurl.scheme();
    346   std::string str_host = gurl.host();
    347   if (gurl.has_port()) {
    348     str_host += ":";
    349     str_host += gurl.port();
    350   }
    351   scoped_array<char> req(new char[str_path.size() + 1]);
    352   scoped_array<char> scheme(new char[str_scheme.size() + 1]);
    353   scoped_array<char> host(new char[str_host.size() + 1]);
    354   memcpy(req.get(), str_path.c_str(), str_path.size());
    355   memcpy(scheme.get(), str_scheme.c_str(), str_scheme.size());
    356   memcpy(host.get(), str_host.c_str(), str_host.size());
    357   req.get()[str_path.size()] = '\0';
    358   scheme.get()[str_scheme.size()] = '\0';
    359   host.get()[str_host.size()] = '\0';
    360 
    361   const char* const headers[] = {
    362     "method",
    363     "GET",
    364     "url",
    365     req.get(),
    366     "host",
    367     host.get(),
    368     "scheme",
    369     scheme.get(),
    370     "version",
    371     "HTTP/1.1"
    372   };
    373   return ConstructSpdyPacket(
    374       kSynStartHeader,
    375       NULL,
    376       0,
    377       headers,
    378       arraysize(headers) / 2);
    379 }
    380 
    381 // Constructs a standard SPDY GET SYN packet, optionally compressed.
    382 // |extra_headers| are the extra header-value pairs, which typically
    383 // will vary the most between calls.
    384 // Returns a SpdyFrame.
    385 spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
    386                                   int extra_header_count,
    387                                   bool compressed,
    388                                   int stream_id,
    389                                   RequestPriority request_priority) {
    390   return ConstructSpdyGet(extra_headers, extra_header_count, compressed,
    391                           stream_id, request_priority, true);
    392 }
    393 
    394 // Constructs a standard SPDY GET SYN packet, optionally compressed.
    395 // |extra_headers| are the extra header-value pairs, which typically
    396 // will vary the most between calls.
    397 // Returns a SpdyFrame.
    398 spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
    399                                   int extra_header_count,
    400                                   bool compressed,
    401                                   int stream_id,
    402                                   RequestPriority request_priority,
    403                                   bool direct) {
    404   const char* const kStandardGetHeaders[] = {
    405     "method",
    406     "GET",
    407     "url",
    408     (direct ? "/" : "http://www.google.com/"),
    409     "host",
    410     "www.google.com",
    411     "scheme",
    412     "http",
    413     "version",
    414     "HTTP/1.1"
    415   };
    416   return ConstructSpdyControlFrame(extra_headers,
    417                                    extra_header_count,
    418                                    compressed,
    419                                    stream_id,
    420                                    request_priority,
    421                                    spdy::SYN_STREAM,
    422                                    spdy::CONTROL_FLAG_FIN,
    423                                    kStandardGetHeaders,
    424                                    arraysize(kStandardGetHeaders));
    425 }
    426 
    427 // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
    428 spdy::SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
    429                                       int extra_header_count,
    430                                       int stream_id) {
    431   const char* const kConnectHeaders[] = {
    432     "method", "CONNECT",
    433     "url", "www.google.com:443",
    434     "host", "www.google.com",
    435     "version", "HTTP/1.1",
    436   };
    437   return ConstructSpdyControlFrame(extra_headers,
    438                                    extra_header_count,
    439                                    /*compressed*/ false,
    440                                    stream_id,
    441                                    LOWEST,
    442                                    spdy::SYN_STREAM,
    443                                    spdy::CONTROL_FLAG_NONE,
    444                                    kConnectHeaders,
    445                                    arraysize(kConnectHeaders));
    446 }
    447 
    448 // Constructs a standard SPDY push SYN packet.
    449 // |extra_headers| are the extra header-value pairs, which typically
    450 // will vary the most between calls.
    451 // Returns a SpdyFrame.
    452 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
    453                                    int extra_header_count,
    454                                    int stream_id,
    455                                    int associated_stream_id) {
    456   const char* const kStandardGetHeaders[] = {
    457     "hello",
    458     "bye",
    459     "status",
    460     "200",
    461     "version",
    462     "HTTP/1.1"
    463   };
    464   return ConstructSpdyControlFrame(extra_headers,
    465                                    extra_header_count,
    466                                    false,
    467                                    stream_id,
    468                                    LOWEST,
    469                                    spdy::SYN_STREAM,
    470                                    spdy::CONTROL_FLAG_NONE,
    471                                    kStandardGetHeaders,
    472                                    arraysize(kStandardGetHeaders),
    473                                    associated_stream_id);
    474 }
    475 
    476 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
    477                                    int extra_header_count,
    478                                    int stream_id,
    479                                    int associated_stream_id,
    480                                    const char* url) {
    481   const char* const kStandardGetHeaders[] = {
    482     "hello",
    483     "bye",
    484     "status",
    485     "200 OK",
    486     "url",
    487     url,
    488     "version",
    489     "HTTP/1.1"
    490   };
    491   return ConstructSpdyControlFrame(extra_headers,
    492                                    extra_header_count,
    493                                    false,
    494                                    stream_id,
    495                                    LOWEST,
    496                                    spdy::SYN_STREAM,
    497                                    spdy::CONTROL_FLAG_NONE,
    498                                    kStandardGetHeaders,
    499                                    arraysize(kStandardGetHeaders),
    500                                    associated_stream_id);
    501 
    502 }
    503 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
    504                                    int extra_header_count,
    505                                    int stream_id,
    506                                    int associated_stream_id,
    507                                    const char* url,
    508                                    const char* status,
    509                                    const char* location) {
    510   const char* const kStandardGetHeaders[] = {
    511     "hello",
    512     "bye",
    513     "status",
    514     status,
    515     "location",
    516     location,
    517     "url",
    518     url,
    519     "version",
    520     "HTTP/1.1"
    521   };
    522   return ConstructSpdyControlFrame(extra_headers,
    523                                    extra_header_count,
    524                                    false,
    525                                    stream_id,
    526                                    LOWEST,
    527                                    spdy::SYN_STREAM,
    528                                    spdy::CONTROL_FLAG_NONE,
    529                                    kStandardGetHeaders,
    530                                    arraysize(kStandardGetHeaders),
    531                                    associated_stream_id);
    532 }
    533 
    534 spdy::SpdyFrame* ConstructSpdyPush(int stream_id,
    535                                   int associated_stream_id,
    536                                   const char* url) {
    537   const char* const kStandardGetHeaders[] = {
    538     "url",
    539     url
    540   };
    541   return ConstructSpdyControlFrame(0,
    542                                    0,
    543                                    false,
    544                                    stream_id,
    545                                    LOWEST,
    546                                    spdy::SYN_STREAM,
    547                                    spdy::CONTROL_FLAG_NONE,
    548                                    kStandardGetHeaders,
    549                                    arraysize(kStandardGetHeaders),
    550                                    associated_stream_id);
    551 }
    552 
    553 spdy::SpdyFrame* ConstructSpdyPushHeaders(int stream_id,
    554                                           const char* const extra_headers[],
    555                                           int extra_header_count) {
    556   const char* const kStandardGetHeaders[] = {
    557     "status",
    558     "200 OK",
    559     "version",
    560     "HTTP/1.1"
    561   };
    562   return ConstructSpdyControlFrame(extra_headers,
    563                                    extra_header_count,
    564                                    false,
    565                                    stream_id,
    566                                    LOWEST,
    567                                    spdy::HEADERS,
    568                                    spdy::CONTROL_FLAG_NONE,
    569                                    kStandardGetHeaders,
    570                                    arraysize(kStandardGetHeaders));
    571 }
    572 
    573 // Constructs a standard SPDY SYN_REPLY packet with the specified status code.
    574 // Returns a SpdyFrame.
    575 spdy::SpdyFrame* ConstructSpdySynReplyError(
    576     const char* const status,
    577     const char* const* const extra_headers,
    578     int extra_header_count,
    579     int stream_id) {
    580   const char* const kStandardGetHeaders[] = {
    581     "hello",
    582     "bye",
    583     "status",
    584     status,
    585     "version",
    586     "HTTP/1.1"
    587   };
    588   return ConstructSpdyControlFrame(extra_headers,
    589                                    extra_header_count,
    590                                    false,
    591                                    stream_id,
    592                                    LOWEST,
    593                                    spdy::SYN_REPLY,
    594                                    spdy::CONTROL_FLAG_NONE,
    595                                    kStandardGetHeaders,
    596                                    arraysize(kStandardGetHeaders));
    597 }
    598 
    599 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
    600 // |extra_headers| are the extra header-value pairs, which typically
    601 // will vary the most between calls.
    602 // Returns a SpdyFrame.
    603 spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id) {
    604   static const char* const kExtraHeaders[] = {
    605     "location",
    606     "http://www.foo.com/index.php",
    607   };
    608   return ConstructSpdySynReplyError("301 Moved Permanently", kExtraHeaders,
    609                                     arraysize(kExtraHeaders)/2, stream_id);
    610 }
    611 
    612 // Constructs a standard SPDY SYN_REPLY packet with an Internal Server
    613 // Error status code.
    614 // Returns a SpdyFrame.
    615 spdy::SpdyFrame* ConstructSpdySynReplyError(int stream_id) {
    616   return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1);
    617 }
    618 
    619 
    620 
    621 
    622 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET.
    623 // |extra_headers| are the extra header-value pairs, which typically
    624 // will vary the most between calls.
    625 // Returns a SpdyFrame.
    626 spdy::SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
    627                                           int extra_header_count,
    628                                           int stream_id) {
    629   static const char* const kStandardGetHeaders[] = {
    630     "hello",
    631     "bye",
    632     "status",
    633     "200",
    634     "version",
    635     "HTTP/1.1"
    636   };
    637   return ConstructSpdyControlFrame(extra_headers,
    638                                    extra_header_count,
    639                                    false,
    640                                    stream_id,
    641                                    LOWEST,
    642                                    spdy::SYN_REPLY,
    643                                    spdy::CONTROL_FLAG_NONE,
    644                                    kStandardGetHeaders,
    645                                    arraysize(kStandardGetHeaders));
    646 }
    647 
    648 // Constructs a standard SPDY POST SYN packet.
    649 // |content_length| is the size of post data.
    650 // |extra_headers| are the extra header-value pairs, which typically
    651 // will vary the most between calls.
    652 // Returns a SpdyFrame.
    653 spdy::SpdyFrame* ConstructSpdyPost(int64 content_length,
    654                                    const char* const extra_headers[],
    655                                    int extra_header_count) {
    656   std::string length_str = base::Int64ToString(content_length);
    657   const char* post_headers[] = {
    658     "method",
    659     "POST",
    660     "url",
    661     "/",
    662     "host",
    663     "www.google.com",
    664     "scheme",
    665     "http",
    666     "version",
    667     "HTTP/1.1",
    668     "content-length",
    669     length_str.c_str()
    670   };
    671   return ConstructSpdyControlFrame(extra_headers,
    672                                    extra_header_count,
    673                                    false,
    674                                    1,
    675                                    LOWEST,
    676                                    spdy::SYN_STREAM,
    677                                    spdy::CONTROL_FLAG_NONE,
    678                                    post_headers,
    679                                    arraysize(post_headers));
    680 }
    681 
    682 // Constructs a chunked transfer SPDY POST SYN packet.
    683 // |extra_headers| are the extra header-value pairs, which typically
    684 // will vary the most between calls.
    685 // Returns a SpdyFrame.
    686 spdy::SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[],
    687                                           int extra_header_count) {
    688   const char* post_headers[] = {
    689     "method",
    690     "POST",
    691     "url",
    692     "/",
    693     "host",
    694     "www.google.com",
    695     "scheme",
    696     "http",
    697     "version",
    698     "HTTP/1.1"
    699   };
    700   return ConstructSpdyControlFrame(extra_headers,
    701                                    extra_header_count,
    702                                    false,
    703                                    1,
    704                                    LOWEST,
    705                                    spdy::SYN_STREAM,
    706                                    spdy::CONTROL_FLAG_NONE,
    707                                    post_headers,
    708                                    arraysize(post_headers));
    709 }
    710 
    711 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY POST.
    712 // |extra_headers| are the extra header-value pairs, which typically
    713 // will vary the most between calls.
    714 // Returns a SpdyFrame.
    715 spdy::SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
    716                                            int extra_header_count) {
    717   static const char* const kStandardGetHeaders[] = {
    718     "hello",
    719     "bye",
    720     "status",
    721     "200",
    722     "url",
    723     "/index.php",
    724     "version",
    725     "HTTP/1.1"
    726   };
    727   return ConstructSpdyControlFrame(extra_headers,
    728                                    extra_header_count,
    729                                    false,
    730                                    1,
    731                                    LOWEST,
    732                                    spdy::SYN_REPLY,
    733                                    spdy::CONTROL_FLAG_NONE,
    734                                    kStandardGetHeaders,
    735                                    arraysize(kStandardGetHeaders));
    736 }
    737 
    738 // Constructs a single SPDY data frame with the default contents.
    739 spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, bool fin) {
    740   spdy::SpdyFramer framer;
    741   return framer.CreateDataFrame(
    742       stream_id, kUploadData, kUploadDataSize,
    743       fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE);
    744 }
    745 
    746 // Constructs a single SPDY data frame with the given content.
    747 spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
    748                                         uint32 len, bool fin) {
    749   spdy::SpdyFramer framer;
    750   return framer.CreateDataFrame(
    751       stream_id, data, len, fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE);
    752 }
    753 
    754 // Wraps |frame| in the payload of a data frame in stream |stream_id|.
    755 spdy::SpdyFrame* ConstructWrappedSpdyFrame(
    756     const scoped_ptr<spdy::SpdyFrame>& frame,
    757     int stream_id) {
    758   return ConstructSpdyBodyFrame(stream_id, frame->data(),
    759                                 frame->length() + spdy::SpdyFrame::size(),
    760                                 false);
    761 }
    762 
    763 // Construct an expected SPDY reply string.
    764 // |extra_headers| are the extra header-value pairs, which typically
    765 // will vary the most between calls.
    766 // |buffer| is the buffer we're filling in.
    767 // Returns the number of bytes written into |buffer|.
    768 int ConstructSpdyReplyString(const char* const extra_headers[],
    769                              int extra_header_count,
    770                              char* buffer,
    771                              int buffer_length) {
    772   int packet_size = 0;
    773   int header_count = 0;
    774   char* buffer_write = buffer;
    775   int buffer_left = buffer_length;
    776   spdy::SpdyHeaderBlock headers;
    777   if (!buffer || !buffer_length)
    778     return 0;
    779   // Copy in the extra headers.
    780   AppendHeadersToSpdyFrame(extra_headers, extra_header_count, &headers);
    781   header_count = headers.size();
    782   // The iterator gets us the list of header/value pairs in sorted order.
    783   spdy::SpdyHeaderBlock::iterator next = headers.begin();
    784   spdy::SpdyHeaderBlock::iterator last = headers.end();
    785   for ( ; next != last; ++next) {
    786     // Write the header.
    787     int value_len, current_len, offset;
    788     const char* header_string = next->first.c_str();
    789     packet_size += AppendToBuffer(header_string,
    790                                   next->first.length(),
    791                                   &buffer_write,
    792                                   &buffer_left);
    793     packet_size += AppendToBuffer(": ",
    794                                   strlen(": "),
    795                                   &buffer_write,
    796                                   &buffer_left);
    797     // Write the value(s).
    798     const char* value_string = next->second.c_str();
    799     // Check if it's split among two or more values.
    800     value_len = next->second.length();
    801     current_len = strlen(value_string);
    802     offset = 0;
    803     // Handle the first N-1 values.
    804     while (current_len < value_len) {
    805       // Finish this line -- write the current value.
    806       packet_size += AppendToBuffer(value_string + offset,
    807                                     current_len - offset,
    808                                     &buffer_write,
    809                                     &buffer_left);
    810       packet_size += AppendToBuffer("\n",
    811                                     strlen("\n"),
    812                                     &buffer_write,
    813                                     &buffer_left);
    814       // Advance to next value.
    815       offset = current_len + 1;
    816       current_len += 1 + strlen(value_string + offset);
    817       // Start another line -- add the header again.
    818       packet_size += AppendToBuffer(header_string,
    819                                     next->first.length(),
    820                                     &buffer_write,
    821                                     &buffer_left);
    822       packet_size += AppendToBuffer(": ",
    823                                     strlen(": "),
    824                                     &buffer_write,
    825                                     &buffer_left);
    826     }
    827     EXPECT_EQ(value_len, current_len);
    828     // Copy the last (or only) value.
    829     packet_size += AppendToBuffer(value_string + offset,
    830                                   value_len - offset,
    831                                   &buffer_write,
    832                                   &buffer_left);
    833     packet_size += AppendToBuffer("\n",
    834                                   strlen("\n"),
    835                                   &buffer_write,
    836                                   &buffer_left);
    837   }
    838   return packet_size;
    839 }
    840 
    841 // Create a MockWrite from the given SpdyFrame.
    842 MockWrite CreateMockWrite(const spdy::SpdyFrame& req) {
    843   return MockWrite(
    844       true, req.data(), req.length() + spdy::SpdyFrame::size());
    845 }
    846 
    847 // Create a MockWrite from the given SpdyFrame and sequence number.
    848 MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq) {
    849   return CreateMockWrite(req, seq, true);
    850 }
    851 
    852 // Create a MockWrite from the given SpdyFrame and sequence number.
    853 MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq, bool async) {
    854   return MockWrite(
    855       async, req.data(), req.length() + spdy::SpdyFrame::size(), seq);
    856 }
    857 
    858 // Create a MockRead from the given SpdyFrame.
    859 MockRead CreateMockRead(const spdy::SpdyFrame& resp) {
    860   return MockRead(
    861       true, resp.data(), resp.length() + spdy::SpdyFrame::size());
    862 }
    863 
    864 // Create a MockRead from the given SpdyFrame and sequence number.
    865 MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq) {
    866   return CreateMockRead(resp, seq, true);
    867 }
    868 
    869 // Create a MockRead from the given SpdyFrame and sequence number.
    870 MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq, bool async) {
    871   return MockRead(
    872       async, resp.data(), resp.length() + spdy::SpdyFrame::size(), seq);
    873 }
    874 
    875 // Combines the given SpdyFrames into the given char array and returns
    876 // the total length.
    877 int CombineFrames(const spdy::SpdyFrame** frames, int num_frames,
    878                   char* buff, int buff_len) {
    879   int total_len = 0;
    880   for (int i = 0; i < num_frames; ++i) {
    881     total_len += frames[i]->length() + spdy::SpdyFrame::size();
    882   }
    883   DCHECK_LE(total_len, buff_len);
    884   char* ptr = buff;
    885   for (int i = 0; i < num_frames; ++i) {
    886     int len = frames[i]->length() + spdy::SpdyFrame::size();
    887     memcpy(ptr, frames[i]->data(), len);
    888     ptr += len;
    889   }
    890   return total_len;
    891 }
    892 
    893 SpdySessionDependencies::SpdySessionDependencies()
    894     : host_resolver(new MockCachingHostResolver),
    895       cert_verifier(new CertVerifier),
    896       proxy_service(ProxyService::CreateDirect()),
    897       ssl_config_service(new SSLConfigServiceDefaults),
    898       socket_factory(new MockClientSocketFactory),
    899       deterministic_socket_factory(new DeterministicMockClientSocketFactory),
    900       http_auth_handler_factory(
    901           HttpAuthHandlerFactory::CreateDefault(host_resolver.get())) {
    902   // Note: The CancelledTransaction test does cleanup by running all
    903   // tasks in the message loop (RunAllPending).  Unfortunately, that
    904   // doesn't clean up tasks on the host resolver thread; and
    905   // TCPConnectJob is currently not cancellable.  Using synchronous
    906   // lookups allows the test to shutdown cleanly.  Until we have
    907   // cancellable TCPConnectJobs, use synchronous lookups.
    908   host_resolver->set_synchronous_mode(true);
    909 }
    910 
    911 SpdySessionDependencies::SpdySessionDependencies(ProxyService* proxy_service)
    912     : host_resolver(new MockHostResolver),
    913       cert_verifier(new CertVerifier),
    914       proxy_service(proxy_service),
    915       ssl_config_service(new SSLConfigServiceDefaults),
    916       socket_factory(new MockClientSocketFactory),
    917       deterministic_socket_factory(new DeterministicMockClientSocketFactory),
    918       http_auth_handler_factory(
    919           HttpAuthHandlerFactory::CreateDefault(host_resolver.get())) {}
    920 
    921 SpdySessionDependencies::~SpdySessionDependencies() {}
    922 
    923 // static
    924 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSession(
    925     SpdySessionDependencies* session_deps) {
    926   net::HttpNetworkSession::Params params;
    927   params.client_socket_factory = session_deps->socket_factory.get();
    928   params.host_resolver = session_deps->host_resolver.get();
    929   params.cert_verifier = session_deps->cert_verifier.get();
    930   params.proxy_service = session_deps->proxy_service;
    931   params.ssl_config_service = session_deps->ssl_config_service;
    932   params.http_auth_handler_factory =
    933       session_deps->http_auth_handler_factory.get();
    934   return new HttpNetworkSession(params);
    935 }
    936 
    937 // static
    938 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSessionDeterministic(
    939     SpdySessionDependencies* session_deps) {
    940   net::HttpNetworkSession::Params params;
    941   params.client_socket_factory =
    942       session_deps->deterministic_socket_factory.get();
    943   params.host_resolver = session_deps->host_resolver.get();
    944   params.cert_verifier = session_deps->cert_verifier.get();
    945   params.proxy_service = session_deps->proxy_service;
    946   params.ssl_config_service = session_deps->ssl_config_service;
    947   params.http_auth_handler_factory =
    948       session_deps->http_auth_handler_factory.get();
    949   return new HttpNetworkSession(params);
    950 }
    951 
    952 SpdyURLRequestContext::SpdyURLRequestContext() {
    953   set_host_resolver(new MockHostResolver());
    954   set_cert_verifier(new CertVerifier);
    955   set_proxy_service(ProxyService::CreateDirect());
    956   set_ssl_config_service(new SSLConfigServiceDefaults);
    957   set_http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault(
    958       host_resolver()));
    959   net::HttpNetworkSession::Params params;
    960   params.client_socket_factory = &socket_factory_;
    961   params.host_resolver = host_resolver();
    962   params.cert_verifier = cert_verifier();
    963   params.proxy_service = proxy_service();
    964   params.ssl_config_service = ssl_config_service();
    965   params.http_auth_handler_factory = http_auth_handler_factory();
    966   params.network_delegate = network_delegate();
    967   scoped_refptr<HttpNetworkSession> network_session(
    968       new HttpNetworkSession(params));
    969   set_http_transaction_factory(new HttpCache(
    970       network_session,
    971       HttpCache::DefaultBackend::InMemory(0)));
    972 }
    973 
    974 SpdyURLRequestContext::~SpdyURLRequestContext() {
    975   delete http_transaction_factory();
    976   delete http_auth_handler_factory();
    977   delete cert_verifier();
    978   delete host_resolver();
    979 }
    980 
    981 const SpdyHeaderInfo make_spdy_header(spdy::SpdyControlType type) {
    982   const SpdyHeaderInfo kHeader = {
    983     type,                         // Kind = Syn
    984     1,                            // Stream ID
    985     0,                            // Associated stream ID
    986     2,                            // Priority
    987     spdy::CONTROL_FLAG_FIN,       // Control Flags
    988     false,                        // Compressed
    989     spdy::INVALID,                // Status
    990     NULL,                         // Data
    991     0,                            // Length
    992     spdy::DATA_FLAG_NONE          // Data Flags
    993   };
    994   return kHeader;
    995 }
    996 }  // namespace net
    997