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