• 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 PING frame.
198 // Returns the constructed frame.  The caller takes ownership of the frame.
ConstructSpdyPing()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.
ConstructSpdyGoAway()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.
ConstructSpdyWindowUpdate(const spdy::SpdyStreamId stream_id,uint32 delta_window_size)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.
ConstructSpdyRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyStatusCodes status)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|.
ConstructSpdyHeader(const char * const extra_headers[],int extra_header_count,char * buffer,int buffer_length,int index)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 
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)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 
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)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.
ConstructSpdyGet(const char * const url,bool compressed,int stream_id,RequestPriority request_priority)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.
ConstructSpdyGet(const char * const extra_headers[],int extra_header_count,bool compressed,int stream_id,RequestPriority request_priority)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.
ConstructSpdyGet(const char * const extra_headers[],int extra_header_count,bool compressed,int stream_id,RequestPriority request_priority,bool direct)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.
ConstructSpdyConnect(const char * const extra_headers[],int extra_header_count,int stream_id)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.
ConstructSpdyPush(const char * const extra_headers[],int extra_header_count,int stream_id,int associated_stream_id)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 
ConstructSpdyPush(const char * const extra_headers[],int extra_header_count,int stream_id,int associated_stream_id,const char * url)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 }
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)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 
ConstructSpdyPush(int stream_id,int associated_stream_id,const char * url)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 
ConstructSpdyPushHeaders(int stream_id,const char * const extra_headers[],int extra_header_count)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.
ConstructSpdySynReplyError(const char * const status,const char * const * const extra_headers,int extra_header_count,int stream_id)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.
ConstructSpdyGetSynReplyRedirect(int stream_id)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.
ConstructSpdySynReplyError(int stream_id)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.
ConstructSpdyGetSynReply(const char * const extra_headers[],int extra_header_count,int stream_id)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.
ConstructSpdyPost(int64 content_length,const char * const extra_headers[],int extra_header_count)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.
ConstructChunkedSpdyPost(const char * const extra_headers[],int extra_header_count)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.
ConstructSpdyPostSynReply(const char * const extra_headers[],int extra_header_count)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.
ConstructSpdyBodyFrame(int stream_id,bool fin)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.
ConstructSpdyBodyFrame(int stream_id,const char * data,uint32 len,bool fin)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|.
ConstructWrappedSpdyFrame(const scoped_ptr<spdy::SpdyFrame> & frame,int 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|.
ConstructSpdyReplyString(const char * const extra_headers[],int extra_header_count,char * buffer,int buffer_length)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.
CreateMockWrite(const spdy::SpdyFrame & req)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.
CreateMockWrite(const spdy::SpdyFrame & req,int seq)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.
CreateMockWrite(const spdy::SpdyFrame & req,int seq,bool async)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.
CreateMockRead(const spdy::SpdyFrame & resp)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.
CreateMockRead(const spdy::SpdyFrame & resp,int seq)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.
CreateMockRead(const spdy::SpdyFrame & resp,int seq,bool async)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.
CombineFrames(const spdy::SpdyFrame ** frames,int num_frames,char * buff,int buff_len)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 
SpdySessionDependencies()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 
SpdySessionDependencies(ProxyService * proxy_service)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 
~SpdySessionDependencies()921 SpdySessionDependencies::~SpdySessionDependencies() {}
922 
923 // static
SpdyCreateSession(SpdySessionDependencies * session_deps)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
SpdyCreateSessionDeterministic(SpdySessionDependencies * session_deps)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 
SpdyURLRequestContext()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 
~SpdyURLRequestContext()974 SpdyURLRequestContext::~SpdyURLRequestContext() {
975   delete http_transaction_factory();
976   delete http_auth_handler_factory();
977   delete cert_verifier();
978   delete host_resolver();
979 }
980 
make_spdy_header(spdy::SpdyControlType type)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