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