• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
ChopWriteFrame(const char * data,int length,int num_chunks)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.
ChopWriteFrame(const spdy::SpdyFrame & frame,int num_chunks)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.
ChopReadFrame(const char * data,int length,int num_chunks)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.
ChopReadFrame(const spdy::SpdyFrame & frame,int num_chunks)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|.
AppendHeadersToSpdyFrame(const char * const extra_headers[],int extra_header_count,spdy::SpdyHeaderBlock * 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
AppendToBuffer(int val,int len,unsigned char ** buffer_handle,int * buffer_len_remaining)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.
ConstructSpdyPacket(const SpdyHeaderInfo & header_info,const char * const extra_headers[],int extra_header_count,const char * const tail[],int tail_header_count)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.
ConstructSpdySettings(spdy::SpdySettings settings)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.
ConstructSpdyGoAway()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.
ConstructSpdyWindowUpdate(const spdy::SpdyStreamId stream_id,uint32 delta_window_size)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.
ConstructSpdyRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyStatusCodes status)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|.
ConstructSpdyHeader(const char * const extra_headers[],int extra_header_count,char * buffer,int buffer_length,int index)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 
ConstructSpdyControlFrame(const char * const extra_headers[],int extra_header_count,bool compressed,int stream_id,RequestPriority request_priority,spdy::SpdyControlType type,spdy::SpdyControlFlags flags,const char * const * kHeaders,int kHeadersSize)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 
ConstructSpdyControlFrame(const char * const extra_headers[],int extra_header_count,bool compressed,int stream_id,RequestPriority request_priority,spdy::SpdyControlType type,spdy::SpdyControlFlags flags,const char * const * kHeaders,int kHeadersSize,int associated_stream_id)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.
ConstructSpdyGet(const char * const url,bool compressed,int stream_id,RequestPriority request_priority)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.
ConstructSpdyGet(const char * const extra_headers[],int extra_header_count,bool compressed,int stream_id,RequestPriority request_priority)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.
ConstructSpdyGet(const char * const extra_headers[],int extra_header_count,bool compressed,int stream_id,RequestPriority request_priority,bool direct)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.
ConstructSpdyConnect(const char * const extra_headers[],int extra_header_count,int stream_id)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.
ConstructSpdyPush(const char * const extra_headers[],int extra_header_count,int stream_id,int associated_stream_id)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 
ConstructSpdyPush(const char * const extra_headers[],int extra_header_count,int stream_id,int associated_stream_id,const char * url)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 }
ConstructSpdyPush(const char * const extra_headers[],int extra_header_count,int stream_id,int associated_stream_id,const char * url,const char * status,const char * location)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 
ConstructSpdyPush(int stream_id,int associated_stream_id,const char * url)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 
ConstructSpdyPushHeaders(int stream_id,const char * const extra_headers[],int extra_header_count)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.
ConstructSpdySynReplyError(const char * const status,const char * const * const extra_headers,int extra_header_count,int stream_id)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.
ConstructSpdyGetSynReplyRedirect(int stream_id)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.
ConstructSpdySynReplyError(int stream_id)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.
ConstructSpdyGetSynReply(const char * const extra_headers[],int extra_header_count,int stream_id)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.
ConstructSpdyPost(int64 content_length,const char * const extra_headers[],int extra_header_count)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.
ConstructChunkedSpdyPost(const char * const extra_headers[],int extra_header_count)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.
ConstructSpdyPostSynReply(const char * const extra_headers[],int extra_header_count)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.
ConstructSpdyBodyFrame(int stream_id,bool fin)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.
ConstructSpdyBodyFrame(int stream_id,const char * data,uint32 len,bool fin)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|.
ConstructWrappedSpdyFrame(const scoped_ptr<spdy::SpdyFrame> & frame,int 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|.
ConstructSpdyReplyString(const char * const extra_headers[],int extra_header_count,char * buffer,int buffer_length)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.
CreateMockWrite(const spdy::SpdyFrame & req)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.
CreateMockWrite(const spdy::SpdyFrame & req,int seq)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.
CreateMockWrite(const spdy::SpdyFrame & req,int seq,bool async)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.
CreateMockRead(const spdy::SpdyFrame & resp)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.
CreateMockRead(const spdy::SpdyFrame & resp,int seq)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.
CreateMockRead(const spdy::SpdyFrame & resp,int seq,bool async)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.
CombineFrames(const spdy::SpdyFrame ** frames,int num_frames,char * buff,int buff_len)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 
SpdySessionDependencies()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 
SpdySessionDependencies(ProxyService * proxy_service)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 
~SpdySessionDependencies()914 SpdySessionDependencies::~SpdySessionDependencies() {}
915 
916 // static
SpdyCreateSession(SpdySessionDependencies * session_deps)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
SpdyCreateSessionDeterministic(SpdySessionDependencies * session_deps)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 
SpdyURLRequestContext()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 
~SpdyURLRequestContext()967 SpdyURLRequestContext::~SpdyURLRequestContext() {
968   delete http_transaction_factory();
969   delete http_auth_handler_factory();
970   delete cert_verifier();
971   delete host_resolver();
972 }
973 
make_spdy_header(spdy::SpdyControlType type)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