OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/compiler_specific.h" | |
11 #include "base/string_number_conversions.h" | |
12 #include "base/string_util.h" | |
13 #include "net/http/http_network_session.h" | |
14 #include "net/http/http_network_transaction.h" | |
15 #include "net/http/http_server_properties_impl.h" | |
16 #include "net/spdy/spdy_framer.h" | |
17 #include "net/spdy/spdy_http_utils.h" | |
18 | |
19 namespace net { | |
20 | |
21 // Chop a frame into an array of MockWrites. | |
22 // |data| is the frame to chop. | |
23 // |length| is the length of the frame to chop. | |
24 // |num_chunks| is the number of chunks to create. | |
25 MockWrite* ChopWriteFrame(const char* data, int length, int num_chunks) { | |
26 MockWrite* chunks = new MockWrite[num_chunks]; | |
27 int chunk_size = length / num_chunks; | |
28 for (int index = 0; index < num_chunks; index++) { | |
29 const char* ptr = data + (index * chunk_size); | |
30 if (index == num_chunks - 1) | |
31 chunk_size += length % chunk_size; // The last chunk takes the remainder. | |
32 chunks[index] = MockWrite(ASYNC, ptr, chunk_size); | |
33 } | |
34 return chunks; | |
35 } | |
36 | |
37 // Chop a SpdyFrame into an array of MockWrites. | |
38 // |frame| is the frame to chop. | |
39 // |num_chunks| is the number of chunks to create. | |
40 MockWrite* ChopWriteFrame(const spdy::SpdyFrame& frame, int num_chunks) { | |
41 return ChopWriteFrame(frame.data(), | |
42 frame.length() + spdy::SpdyFrame::kHeaderSize, | |
43 num_chunks); | |
44 } | |
45 | |
46 // Chop a frame into an array of MockReads. | |
47 // |data| is the frame to chop. | |
48 // |length| is the length of the frame to chop. | |
49 // |num_chunks| is the number of chunks to create. | |
50 MockRead* ChopReadFrame(const char* data, int length, int num_chunks) { | |
51 MockRead* chunks = new MockRead[num_chunks]; | |
52 int chunk_size = length / num_chunks; | |
53 for (int index = 0; index < num_chunks; index++) { | |
54 const char* ptr = data + (index * chunk_size); | |
55 if (index == num_chunks - 1) | |
56 chunk_size += length % chunk_size; // The last chunk takes the remainder. | |
57 chunks[index] = MockRead(ASYNC, ptr, chunk_size); | |
58 } | |
59 return chunks; | |
60 } | |
61 | |
62 // Chop a SpdyFrame into an array of MockReads. | |
63 // |frame| is the frame to chop. | |
64 // |num_chunks| is the number of chunks to create. | |
65 MockRead* ChopReadFrame(const spdy::SpdyFrame& frame, int num_chunks) { | |
66 return ChopReadFrame(frame.data(), | |
67 frame.length() + spdy::SpdyFrame::kHeaderSize, | |
68 num_chunks); | |
69 } | |
70 | |
71 // Adds headers and values to a map. | |
72 // |extra_headers| is an array of { name, value } pairs, arranged as strings | |
73 // where the even entries are the header names, and the odd entries are the | |
74 // header values. | |
75 // |headers| gets filled in from |extra_headers|. | |
76 void AppendHeadersToSpdyFrame(const char* const extra_headers[], | |
77 int extra_header_count, | |
78 spdy::SpdyHeaderBlock* headers) { | |
79 std::string this_header; | |
80 std::string this_value; | |
81 | |
82 if (!extra_header_count) | |
83 return; | |
84 | |
85 // Sanity check: Non-NULL header list. | |
86 DCHECK(NULL != extra_headers) << "NULL header value pair list"; | |
87 // Sanity check: Non-NULL header map. | |
88 DCHECK(NULL != headers) << "NULL header map"; | |
89 // Copy in the headers. | |
90 for (int i = 0; i < extra_header_count; i++) { | |
91 // Sanity check: Non-empty header. | |
92 DCHECK_NE('\0', *extra_headers[i * 2]) << "Empty header value pair"; | |
93 this_header = extra_headers[i * 2]; | |
94 std::string::size_type header_len = this_header.length(); | |
95 if (!header_len) | |
96 continue; | |
97 this_value = extra_headers[1 + (i * 2)]; | |
98 std::string new_value; | |
99 if (headers->find(this_header) != headers->end()) { | |
100 // More than one entry in the header. | |
101 // Don't add the header again, just the append to the value, | |
102 // separated by a NULL character. | |
103 | |
104 // Adjust the value. | |
105 new_value = (*headers)[this_header]; | |
106 // Put in a NULL separator. | |
107 new_value.append(1, '\0'); | |
108 // Append the new value. | |
109 new_value += this_value; | |
110 } else { | |
111 // Not a duplicate, just write the value. | |
112 new_value = this_value; | |
113 } | |
114 (*headers)[this_header] = new_value; | |
115 } | |
116 } | |
117 | |
118 // Writes |val| to a location of size |len|, in big-endian format. | |
119 // in the buffer pointed to by |buffer_handle|. | |
120 // Updates the |*buffer_handle| pointer by |len| | |
121 // Returns the number of bytes written | |
122 int AppendToBuffer(int val, | |
123 int len, | |
124 unsigned char** buffer_handle, | |
125 int* buffer_len_remaining) { | |
126 if (len <= 0) | |
127 return 0; | |
128 DCHECK((size_t) len <= sizeof(len)) << "Data length too long for data type"; | |
129 DCHECK(NULL != buffer_handle) << "NULL buffer handle"; | |
130 DCHECK(NULL != *buffer_handle) << "NULL pointer"; | |
131 DCHECK(NULL != buffer_len_remaining) | |
132 << "NULL buffer remainder length pointer"; | |
133 DCHECK_GE(*buffer_len_remaining, len) << "Insufficient buffer size"; | |
134 for (int i = 0; i < len; i++) { | |
135 int shift = (8 * (len - (i + 1))); | |
136 unsigned char val_chunk = (val >> shift) & 0x0FF; | |
137 *(*buffer_handle)++ = val_chunk; | |
138 *buffer_len_remaining += 1; | |
139 } | |
140 return len; | |
141 } | |
142 | |
143 // Construct a SPDY packet. | |
144 // |head| is the start of the packet, up to but not including | |
145 // the header value pairs. | |
146 // |extra_headers| are the extra header-value pairs, which typically | |
147 // will vary the most between calls. | |
148 // |tail| is any (relatively constant) header-value pairs to add. | |
149 // |buffer| is the buffer we're filling in. | |
150 // Returns a SpdyFrame. | |
151 spdy::SpdyFrame* ConstructSpdyPacket(const SpdyHeaderInfo& header_info, | |
152 const char* const extra_headers[], | |
153 int extra_header_count, | |
154 const char* const tail[], | |
155 int tail_header_count) { | |
156 spdy::SpdyFramer framer; | |
157 spdy::SpdyHeaderBlock headers; | |
158 // Copy in the extra headers to our map. | |
159 AppendHeadersToSpdyFrame(extra_headers, extra_header_count, &headers); | |
160 // Copy in the tail headers to our map. | |
161 if (tail && tail_header_count) | |
162 AppendHeadersToSpdyFrame(tail, tail_header_count, &headers); | |
163 spdy::SpdyFrame* frame = NULL; | |
164 switch (header_info.kind) { | |
165 case spdy::SYN_STREAM: | |
166 frame = framer.CreateSynStream(header_info.id, header_info.assoc_id, | |
167 header_info.priority, | |
168 header_info.control_flags, | |
169 header_info.compressed, &headers); | |
170 break; | |
171 case spdy::SYN_REPLY: | |
172 frame = framer.CreateSynReply(header_info.id, header_info.control_flags, | |
173 header_info.compressed, &headers); | |
174 break; | |
175 case spdy::RST_STREAM: | |
176 frame = framer.CreateRstStream(header_info.id, header_info.status); | |
177 break; | |
178 case spdy::HEADERS: | |
179 frame = framer.CreateHeaders(header_info.id, header_info.control_flags, | |
180 header_info.compressed, &headers); | |
181 break; | |
182 default: | |
183 frame = framer.CreateDataFrame(header_info.id, header_info.data, | |
184 header_info.data_length, | |
185 header_info.data_flags); | |
186 break; | |
187 } | |
188 return frame; | |
189 } | |
190 | |
191 // Construct an expected SPDY SETTINGS frame. | |
192 // |settings| are the settings to set. | |
193 // Returns the constructed frame. The caller takes ownership of the frame. | |
194 spdy::SpdyFrame* ConstructSpdySettings( | |
195 const spdy::SpdySettings& settings) { | |
196 spdy::SpdyFramer framer; | |
197 return framer.CreateSettings(settings); | |
198 } | |
199 | |
200 // Construct an expected SPDY CREDENTIAL frame. | |
201 // |credential| is the credential to sen. | |
202 // Returns the constructed frame. The caller takes ownership of the frame. | |
203 spdy::SpdyFrame* ConstructSpdyCredential( | |
204 const spdy::SpdyCredential& credential) { | |
205 spdy::SpdyFramer framer; | |
206 return framer.CreateCredentialFrame(credential); | |
207 } | |
208 | |
209 // Construct a SPDY PING frame. | |
210 // Returns the constructed frame. The caller takes ownership of the frame. | |
211 spdy::SpdyFrame* ConstructSpdyPing() { | |
212 spdy::SpdyFramer framer; | |
213 return framer.CreatePingFrame(1); | |
214 } | |
215 | |
216 // Construct a SPDY GOAWAY frame. | |
217 // Returns the constructed frame. The caller takes ownership of the frame. | |
218 spdy::SpdyFrame* ConstructSpdyGoAway() { | |
219 spdy::SpdyFramer framer; | |
220 return framer.CreateGoAway(0); | |
221 } | |
222 | |
223 // Construct a SPDY WINDOW_UPDATE frame. | |
224 // Returns the constructed frame. The caller takes ownership of the frame. | |
225 spdy::SpdyFrame* ConstructSpdyWindowUpdate( | |
226 const spdy::SpdyStreamId stream_id, uint32 delta_window_size) { | |
227 spdy::SpdyFramer framer; | |
228 return framer.CreateWindowUpdate(stream_id, delta_window_size); | |
229 } | |
230 | |
231 // Construct a SPDY RST_STREAM frame. | |
232 // Returns the constructed frame. The caller takes ownership of the frame. | |
233 spdy::SpdyFrame* ConstructSpdyRstStream(spdy::SpdyStreamId stream_id, | |
234 spdy::SpdyStatusCodes status) { | |
235 spdy::SpdyFramer framer; | |
236 return framer.CreateRstStream(stream_id, status); | |
237 } | |
238 | |
239 // Construct a single SPDY header entry, for validation. | |
240 // |extra_headers| are the extra header-value pairs. | |
241 // |buffer| is the buffer we're filling in. | |
242 // |index| is the index of the header we want. | |
243 // Returns the number of bytes written into |buffer|. | |
244 int ConstructSpdyHeader(const char* const extra_headers[], | |
245 int extra_header_count, | |
246 char* buffer, | |
247 int buffer_length, | |
248 int index) { | |
249 const char* this_header = NULL; | |
250 const char* this_value = NULL; | |
251 if (!buffer || !buffer_length) | |
252 return 0; | |
253 *buffer = '\0'; | |
254 // Sanity check: Non-empty header list. | |
255 DCHECK(NULL != extra_headers) << "NULL extra headers pointer"; | |
256 // Sanity check: Index out of range. | |
257 DCHECK((index >= 0) && (index < extra_header_count)) | |
258 << "Index " << index | |
259 << " out of range [0, " << extra_header_count << ")"; | |
260 this_header = extra_headers[index * 2]; | |
261 // Sanity check: Non-empty header. | |
262 if (!*this_header) | |
263 return 0; | |
264 std::string::size_type header_len = strlen(this_header); | |
265 if (!header_len) | |
266 return 0; | |
267 this_value = extra_headers[1 + (index * 2)]; | |
268 // Sanity check: Non-empty value. | |
269 if (!*this_value) | |
270 this_value = ""; | |
271 int n = base::snprintf(buffer, | |
272 buffer_length, | |
273 "%s: %s\r\n", | |
274 this_header, | |
275 this_value); | |
276 return n; | |
277 } | |
278 | |
279 spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[], | |
280 int extra_header_count, | |
281 bool compressed, | |
282 int stream_id, | |
283 RequestPriority request_priority, | |
284 spdy::SpdyControlType type, | |
285 spdy::SpdyControlFlags flags, | |
286 const char* const* kHeaders, | |
287 int kHeadersSize) { | |
288 return ConstructSpdyControlFrame(extra_headers, | |
289 extra_header_count, | |
290 compressed, | |
291 stream_id, | |
292 request_priority, | |
293 type, | |
294 flags, | |
295 kHeaders, | |
296 kHeadersSize, | |
297 0); | |
298 } | |
299 | |
300 spdy::SpdyFrame* ConstructSpdyControlFrame(const char* const extra_headers[], | |
301 int extra_header_count, | |
302 bool compressed, | |
303 int stream_id, | |
304 RequestPriority request_priority, | |
305 spdy::SpdyControlType type, | |
306 spdy::SpdyControlFlags flags, | |
307 const char* const* kHeaders, | |
308 int kHeadersSize, | |
309 int associated_stream_id) { | |
310 const SpdyHeaderInfo kSynStartHeader = { | |
311 type, // Kind = Syn | |
312 stream_id, // Stream ID | |
313 associated_stream_id, // Associated stream ID | |
314 ConvertRequestPriorityToSpdyPriority(request_priority), | |
315 // Priority | |
316 flags, // Control Flags | |
317 compressed, // Compressed | |
318 spdy::INVALID, // Status | |
319 NULL, // Data | |
320 0, // Length | |
321 spdy::DATA_FLAG_NONE // Data Flags | |
322 }; | |
323 return ConstructSpdyPacket(kSynStartHeader, | |
324 extra_headers, | |
325 extra_header_count, | |
326 kHeaders, | |
327 kHeadersSize / 2); | |
328 } | |
329 | |
330 // Constructs a standard SPDY GET SYN packet, optionally compressed | |
331 // for the url |url|. | |
332 // |extra_headers| are the extra header-value pairs, which typically | |
333 // will vary the most between calls. | |
334 // Returns a SpdyFrame. | |
335 spdy::SpdyFrame* ConstructSpdyGet(const char* const url, | |
336 bool compressed, | |
337 int stream_id, | |
338 RequestPriority request_priority) { | |
339 const SpdyHeaderInfo kSynStartHeader = { | |
340 spdy::SYN_STREAM, // Kind = Syn | |
341 stream_id, // Stream ID | |
342 0, // Associated stream ID | |
343 net::ConvertRequestPriorityToSpdyPriority(request_priority), | |
344 // Priority | |
345 spdy::CONTROL_FLAG_FIN, // Control Flags | |
346 compressed, // Compressed | |
347 spdy::INVALID, // Status | |
348 NULL, // Data | |
349 0, // Length | |
350 spdy::DATA_FLAG_NONE // Data Flags | |
351 }; | |
352 | |
353 GURL gurl(url); | |
354 | |
355 // This is so ugly. Why are we using char* in here again? | |
356 std::string str_path = gurl.PathForRequest(); | |
357 std::string str_scheme = gurl.scheme(); | |
358 std::string str_host = gurl.host(); | |
359 if (gurl.has_port()) { | |
360 str_host += ":"; | |
361 str_host += gurl.port(); | |
362 } | |
363 scoped_array<char> req(new char[str_path.size() + 1]); | |
364 scoped_array<char> scheme(new char[str_scheme.size() + 1]); | |
365 scoped_array<char> host(new char[str_host.size() + 1]); | |
366 memcpy(req.get(), str_path.c_str(), str_path.size()); | |
367 memcpy(scheme.get(), str_scheme.c_str(), str_scheme.size()); | |
368 memcpy(host.get(), str_host.c_str(), str_host.size()); | |
369 req.get()[str_path.size()] = '\0'; | |
370 scheme.get()[str_scheme.size()] = '\0'; | |
371 host.get()[str_host.size()] = '\0'; | |
372 | |
373 const char* const headers[] = { | |
374 "method", | |
375 "GET", | |
376 "url", | |
377 req.get(), | |
378 "host", | |
379 host.get(), | |
380 "scheme", | |
381 scheme.get(), | |
382 "version", | |
383 "HTTP/1.1" | |
384 }; | |
385 return ConstructSpdyPacket( | |
386 kSynStartHeader, | |
387 NULL, | |
388 0, | |
389 headers, | |
390 arraysize(headers) / 2); | |
391 } | |
392 | |
393 // Constructs a standard SPDY GET SYN packet, optionally compressed. | |
394 // |extra_headers| are the extra header-value pairs, which typically | |
395 // will vary the most between calls. | |
396 // Returns a SpdyFrame. | |
397 spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[], | |
398 int extra_header_count, | |
399 bool compressed, | |
400 int stream_id, | |
401 RequestPriority request_priority) { | |
402 return ConstructSpdyGet(extra_headers, extra_header_count, compressed, | |
403 stream_id, request_priority, true); | |
404 } | |
405 | |
406 // Constructs a standard SPDY GET SYN packet, optionally compressed. | |
407 // |extra_headers| are the extra header-value pairs, which typically | |
408 // will vary the most between calls. | |
409 // Returns a SpdyFrame. | |
410 spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[], | |
411 int extra_header_count, | |
412 bool compressed, | |
413 int stream_id, | |
414 RequestPriority request_priority, | |
415 bool direct) { | |
416 const char* const kStandardGetHeaders[] = { | |
417 "method", | |
418 "GET", | |
419 "url", | |
420 (direct ? "/" : "http://www.google.com/"), | |
421 "host", | |
422 "www.google.com", | |
423 "scheme", | |
424 "http", | |
425 "version", | |
426 "HTTP/1.1" | |
427 }; | |
428 return ConstructSpdyControlFrame(extra_headers, | |
429 extra_header_count, | |
430 compressed, | |
431 stream_id, | |
432 request_priority, | |
433 spdy::SYN_STREAM, | |
434 spdy::CONTROL_FLAG_FIN, | |
435 kStandardGetHeaders, | |
436 arraysize(kStandardGetHeaders)); | |
437 } | |
438 | |
439 // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request. | |
440 spdy::SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[], | |
441 int extra_header_count, | |
442 int stream_id) { | |
443 const char* const kConnectHeaders[] = { | |
444 "method", "CONNECT", | |
445 "url", "www.google.com:443", | |
446 "host", "www.google.com", | |
447 "version", "HTTP/1.1", | |
448 }; | |
449 return ConstructSpdyControlFrame(extra_headers, | |
450 extra_header_count, | |
451 /*compressed*/ false, | |
452 stream_id, | |
453 LOWEST, | |
454 spdy::SYN_STREAM, | |
455 spdy::CONTROL_FLAG_NONE, | |
456 kConnectHeaders, | |
457 arraysize(kConnectHeaders)); | |
458 } | |
459 | |
460 // Constructs a standard SPDY push SYN packet. | |
461 // |extra_headers| are the extra header-value pairs, which typically | |
462 // will vary the most between calls. | |
463 // Returns a SpdyFrame. | |
464 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], | |
465 int extra_header_count, | |
466 int stream_id, | |
467 int associated_stream_id) { | |
468 const char* const kStandardGetHeaders[] = { | |
469 "hello", | |
470 "bye", | |
471 "status", | |
472 "200", | |
473 "version", | |
474 "HTTP/1.1" | |
475 }; | |
476 return ConstructSpdyControlFrame(extra_headers, | |
477 extra_header_count, | |
478 false, | |
479 stream_id, | |
480 LOWEST, | |
481 spdy::SYN_STREAM, | |
482 spdy::CONTROL_FLAG_NONE, | |
483 kStandardGetHeaders, | |
484 arraysize(kStandardGetHeaders), | |
485 associated_stream_id); | |
486 } | |
487 | |
488 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], | |
489 int extra_header_count, | |
490 int stream_id, | |
491 int associated_stream_id, | |
492 const char* url) { | |
493 const char* const kStandardGetHeaders[] = { | |
494 "hello", | |
495 "bye", | |
496 "status", | |
497 "200 OK", | |
498 "url", | |
499 url, | |
500 "version", | |
501 "HTTP/1.1" | |
502 }; | |
503 return ConstructSpdyControlFrame(extra_headers, | |
504 extra_header_count, | |
505 false, | |
506 stream_id, | |
507 LOWEST, | |
508 spdy::SYN_STREAM, | |
509 spdy::CONTROL_FLAG_NONE, | |
510 kStandardGetHeaders, | |
511 arraysize(kStandardGetHeaders), | |
512 associated_stream_id); | |
513 | |
514 } | |
515 spdy::SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], | |
516 int extra_header_count, | |
517 int stream_id, | |
518 int associated_stream_id, | |
519 const char* url, | |
520 const char* status, | |
521 const char* location) { | |
522 const char* const kStandardGetHeaders[] = { | |
523 "hello", | |
524 "bye", | |
525 "status", | |
526 status, | |
527 "location", | |
528 location, | |
529 "url", | |
530 url, | |
531 "version", | |
532 "HTTP/1.1" | |
533 }; | |
534 return ConstructSpdyControlFrame(extra_headers, | |
535 extra_header_count, | |
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 | |
546 spdy::SpdyFrame* ConstructSpdyPush(int stream_id, | |
547 int associated_stream_id, | |
548 const char* url) { | |
549 const char* const kStandardGetHeaders[] = { | |
550 "url", | |
551 url | |
552 }; | |
553 return ConstructSpdyControlFrame(0, | |
554 0, | |
555 false, | |
556 stream_id, | |
557 LOWEST, | |
558 spdy::SYN_STREAM, | |
559 spdy::CONTROL_FLAG_NONE, | |
560 kStandardGetHeaders, | |
561 arraysize(kStandardGetHeaders), | |
562 associated_stream_id); | |
563 } | |
564 | |
565 spdy::SpdyFrame* ConstructSpdyPushHeaders(int stream_id, | |
566 const char* const extra_headers[], | |
567 int extra_header_count) { | |
568 const char* const kStandardGetHeaders[] = { | |
569 "status", | |
570 "200 OK", | |
571 "version", | |
572 "HTTP/1.1" | |
573 }; | |
574 return ConstructSpdyControlFrame(extra_headers, | |
575 extra_header_count, | |
576 false, | |
577 stream_id, | |
578 LOWEST, | |
579 spdy::HEADERS, | |
580 spdy::CONTROL_FLAG_NONE, | |
581 kStandardGetHeaders, | |
582 arraysize(kStandardGetHeaders)); | |
583 } | |
584 | |
585 // Constructs a standard SPDY SYN_REPLY packet with the specified status code. | |
586 // Returns a SpdyFrame. | |
587 spdy::SpdyFrame* ConstructSpdySynReplyError( | |
588 const char* const status, | |
589 const char* const* const extra_headers, | |
590 int extra_header_count, | |
591 int stream_id) { | |
592 const char* const kStandardGetHeaders[] = { | |
593 "hello", | |
594 "bye", | |
595 "status", | |
596 status, | |
597 "version", | |
598 "HTTP/1.1" | |
599 }; | |
600 return ConstructSpdyControlFrame(extra_headers, | |
601 extra_header_count, | |
602 false, | |
603 stream_id, | |
604 LOWEST, | |
605 spdy::SYN_REPLY, | |
606 spdy::CONTROL_FLAG_NONE, | |
607 kStandardGetHeaders, | |
608 arraysize(kStandardGetHeaders)); | |
609 } | |
610 | |
611 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET. | |
612 // |extra_headers| are the extra header-value pairs, which typically | |
613 // will vary the most between calls. | |
614 // Returns a SpdyFrame. | |
615 spdy::SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id) { | |
616 static const char* const kExtraHeaders[] = { | |
617 "location", | |
618 "http://www.foo.com/index.php", | |
619 }; | |
620 return ConstructSpdySynReplyError("301 Moved Permanently", kExtraHeaders, | |
621 arraysize(kExtraHeaders)/2, stream_id); | |
622 } | |
623 | |
624 // Constructs a standard SPDY SYN_REPLY packet with an Internal Server | |
625 // Error status code. | |
626 // Returns a SpdyFrame. | |
627 spdy::SpdyFrame* ConstructSpdySynReplyError(int stream_id) { | |
628 return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1); | |
629 } | |
630 | |
631 | |
632 | |
633 | |
634 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET. | |
635 // |extra_headers| are the extra header-value pairs, which typically | |
636 // will vary the most between calls. | |
637 // Returns a SpdyFrame. | |
638 spdy::SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[], | |
639 int extra_header_count, | |
640 int stream_id) { | |
641 static const char* const kStandardGetHeaders[] = { | |
642 "hello", | |
643 "bye", | |
644 "status", | |
645 "200", | |
646 "version", | |
647 "HTTP/1.1" | |
648 }; | |
649 return ConstructSpdyControlFrame(extra_headers, | |
650 extra_header_count, | |
651 false, | |
652 stream_id, | |
653 LOWEST, | |
654 spdy::SYN_REPLY, | |
655 spdy::CONTROL_FLAG_NONE, | |
656 kStandardGetHeaders, | |
657 arraysize(kStandardGetHeaders)); | |
658 } | |
659 | |
660 // Constructs a standard SPDY POST SYN packet. | |
661 // |content_length| is the size of post data. | |
662 // |extra_headers| are the extra header-value pairs, which typically | |
663 // will vary the most between calls. | |
664 // Returns a SpdyFrame. | |
665 spdy::SpdyFrame* ConstructSpdyPost(int64 content_length, | |
666 const char* const extra_headers[], | |
667 int extra_header_count) { | |
668 std::string length_str = base::Int64ToString(content_length); | |
669 const char* post_headers[] = { | |
670 "method", | |
671 "POST", | |
672 "url", | |
673 "/", | |
674 "host", | |
675 "www.google.com", | |
676 "scheme", | |
677 "http", | |
678 "version", | |
679 "HTTP/1.1", | |
680 "content-length", | |
681 length_str.c_str() | |
682 }; | |
683 return ConstructSpdyControlFrame(extra_headers, | |
684 extra_header_count, | |
685 false, | |
686 1, | |
687 LOWEST, | |
688 spdy::SYN_STREAM, | |
689 spdy::CONTROL_FLAG_NONE, | |
690 post_headers, | |
691 arraysize(post_headers)); | |
692 } | |
693 | |
694 // Constructs a chunked transfer SPDY POST SYN packet. | |
695 // |extra_headers| are the extra header-value pairs, which typically | |
696 // will vary the most between calls. | |
697 // Returns a SpdyFrame. | |
698 spdy::SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[], | |
699 int extra_header_count) { | |
700 const char* post_headers[] = { | |
701 "method", | |
702 "POST", | |
703 "url", | |
704 "/", | |
705 "host", | |
706 "www.google.com", | |
707 "scheme", | |
708 "http", | |
709 "version", | |
710 "HTTP/1.1" | |
711 }; | |
712 return ConstructSpdyControlFrame(extra_headers, | |
713 extra_header_count, | |
714 false, | |
715 1, | |
716 LOWEST, | |
717 spdy::SYN_STREAM, | |
718 spdy::CONTROL_FLAG_NONE, | |
719 post_headers, | |
720 arraysize(post_headers)); | |
721 } | |
722 | |
723 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY POST. | |
724 // |extra_headers| are the extra header-value pairs, which typically | |
725 // will vary the most between calls. | |
726 // Returns a SpdyFrame. | |
727 spdy::SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[], | |
728 int extra_header_count) { | |
729 static const char* const kStandardGetHeaders[] = { | |
730 "hello", | |
731 "bye", | |
732 "status", | |
733 "200", | |
734 "url", | |
735 "/index.php", | |
736 "version", | |
737 "HTTP/1.1" | |
738 }; | |
739 return ConstructSpdyControlFrame(extra_headers, | |
740 extra_header_count, | |
741 false, | |
742 1, | |
743 LOWEST, | |
744 spdy::SYN_REPLY, | |
745 spdy::CONTROL_FLAG_NONE, | |
746 kStandardGetHeaders, | |
747 arraysize(kStandardGetHeaders)); | |
748 } | |
749 | |
750 // Constructs a single SPDY data frame with the default contents. | |
751 spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, bool fin) { | |
752 spdy::SpdyFramer framer; | |
753 return framer.CreateDataFrame( | |
754 stream_id, kUploadData, kUploadDataSize, | |
755 fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE); | |
756 } | |
757 | |
758 // Constructs a single SPDY data frame with the given content. | |
759 spdy::SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data, | |
760 uint32 len, bool fin) { | |
761 spdy::SpdyFramer framer; | |
762 return framer.CreateDataFrame( | |
763 stream_id, data, len, fin ? spdy::DATA_FLAG_FIN : spdy::DATA_FLAG_NONE); | |
764 } | |
765 | |
766 // Wraps |frame| in the payload of a data frame in stream |stream_id|. | |
767 spdy::SpdyFrame* ConstructWrappedSpdyFrame( | |
768 const scoped_ptr<spdy::SpdyFrame>& frame, | |
769 int stream_id) { | |
770 return ConstructSpdyBodyFrame(stream_id, frame->data(), | |
771 frame->length() + spdy::SpdyFrame::kHeaderSize, | |
772 false); | |
773 } | |
774 | |
775 // Construct an expected SPDY reply string. | |
776 // |extra_headers| are the extra header-value pairs, which typically | |
777 // will vary the most between calls. | |
778 // |buffer| is the buffer we're filling in. | |
779 // Returns the number of bytes written into |buffer|. | |
780 int ConstructSpdyReplyString(const char* const extra_headers[], | |
781 int extra_header_count, | |
782 char* buffer, | |
783 int buffer_length) { | |
784 int packet_size = 0; | |
785 char* buffer_write = buffer; | |
786 int buffer_left = buffer_length; | |
787 spdy::SpdyHeaderBlock headers; | |
788 if (!buffer || !buffer_length) | |
789 return 0; | |
790 // Copy in the extra headers. | |
791 AppendHeadersToSpdyFrame(extra_headers, extra_header_count, &headers); | |
792 // The iterator gets us the list of header/value pairs in sorted order. | |
793 spdy::SpdyHeaderBlock::iterator next = headers.begin(); | |
794 spdy::SpdyHeaderBlock::iterator last = headers.end(); | |
795 for ( ; next != last; ++next) { | |
796 // Write the header. | |
797 int value_len, current_len, offset; | |
798 const char* header_string = next->first.c_str(); | |
799 packet_size += AppendToBuffer(header_string, | |
800 next->first.length(), | |
801 &buffer_write, | |
802 &buffer_left); | |
803 packet_size += AppendToBuffer(": ", | |
804 strlen(": "), | |
805 &buffer_write, | |
806 &buffer_left); | |
807 // Write the value(s). | |
808 const char* value_string = next->second.c_str(); | |
809 // Check if it's split among two or more values. | |
810 value_len = next->second.length(); | |
811 current_len = strlen(value_string); | |
812 offset = 0; | |
813 // Handle the first N-1 values. | |
814 while (current_len < value_len) { | |
815 // Finish this line -- write the current value. | |
816 packet_size += AppendToBuffer(value_string + offset, | |
817 current_len - offset, | |
818 &buffer_write, | |
819 &buffer_left); | |
820 packet_size += AppendToBuffer("\n", | |
821 strlen("\n"), | |
822 &buffer_write, | |
823 &buffer_left); | |
824 // Advance to next value. | |
825 offset = current_len + 1; | |
826 current_len += 1 + strlen(value_string + offset); | |
827 // Start another line -- add the header again. | |
828 packet_size += AppendToBuffer(header_string, | |
829 next->first.length(), | |
830 &buffer_write, | |
831 &buffer_left); | |
832 packet_size += AppendToBuffer(": ", | |
833 strlen(": "), | |
834 &buffer_write, | |
835 &buffer_left); | |
836 } | |
837 EXPECT_EQ(value_len, current_len); | |
838 // Copy the last (or only) value. | |
839 packet_size += AppendToBuffer(value_string + offset, | |
840 value_len - offset, | |
841 &buffer_write, | |
842 &buffer_left); | |
843 packet_size += AppendToBuffer("\n", | |
844 strlen("\n"), | |
845 &buffer_write, | |
846 &buffer_left); | |
847 } | |
848 return packet_size; | |
849 } | |
850 | |
851 // Create a MockWrite from the given SpdyFrame. | |
852 MockWrite CreateMockWrite(const spdy::SpdyFrame& req) { | |
853 return MockWrite( | |
854 ASYNC, req.data(), req.length() + spdy::SpdyFrame::kHeaderSize); | |
855 } | |
856 | |
857 // Create a MockWrite from the given SpdyFrame and sequence number. | |
858 MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq) { | |
859 return CreateMockWrite(req, seq, ASYNC); | |
860 } | |
861 | |
862 // Create a MockWrite from the given SpdyFrame and sequence number. | |
863 MockWrite CreateMockWrite(const spdy::SpdyFrame& req, int seq, IoMode mode) { | |
864 return MockWrite( | |
865 mode, req.data(), req.length() + spdy::SpdyFrame::kHeaderSize, seq); | |
866 } | |
867 | |
868 // Create a MockRead from the given SpdyFrame. | |
869 MockRead CreateMockRead(const spdy::SpdyFrame& resp) { | |
870 return MockRead( | |
871 ASYNC, resp.data(), resp.length() + spdy::SpdyFrame::kHeaderSize); | |
872 } | |
873 | |
874 // Create a MockRead from the given SpdyFrame and sequence number. | |
875 MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq) { | |
876 return CreateMockRead(resp, seq, ASYNC); | |
877 } | |
878 | |
879 // Create a MockRead from the given SpdyFrame and sequence number. | |
880 MockRead CreateMockRead(const spdy::SpdyFrame& resp, int seq, IoMode mode) { | |
881 return MockRead( | |
882 mode, resp.data(), resp.length() + spdy::SpdyFrame::kHeaderSize, seq); | |
883 } | |
884 | |
885 // Combines the given SpdyFrames into the given char array and returns | |
886 // the total length. | |
887 int CombineFrames(const spdy::SpdyFrame** frames, int num_frames, | |
888 char* buff, int buff_len) { | |
889 int total_len = 0; | |
890 for (int i = 0; i < num_frames; ++i) { | |
891 total_len += frames[i]->length() + spdy::SpdyFrame::kHeaderSize; | |
892 } | |
893 DCHECK_LE(total_len, buff_len); | |
894 char* ptr = buff; | |
895 for (int i = 0; i < num_frames; ++i) { | |
896 int len = frames[i]->length() + spdy::SpdyFrame::kHeaderSize; | |
897 memcpy(ptr, frames[i]->data(), len); | |
898 ptr += len; | |
899 } | |
900 return total_len; | |
901 } | |
902 | |
903 SpdySessionDependencies::SpdySessionDependencies() | |
904 : host_resolver(new MockCachingHostResolver), | |
905 cert_verifier(new CertVerifier), | |
906 proxy_service(ProxyService::CreateDirect()), | |
907 ssl_config_service(new SSLConfigServiceDefaults), | |
908 socket_factory(new MockClientSocketFactory), | |
909 deterministic_socket_factory(new DeterministicMockClientSocketFactory), | |
910 http_auth_handler_factory( | |
911 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())) { | |
912 // Note: The CancelledTransaction test does cleanup by running all | |
913 // tasks in the message loop (RunAllPending). Unfortunately, that | |
914 // doesn't clean up tasks on the host resolver thread; and | |
915 // TCPConnectJob is currently not cancellable. Using synchronous | |
916 // lookups allows the test to shutdown cleanly. Until we have | |
917 // cancellable TCPConnectJobs, use synchronous lookups. | |
918 host_resolver->set_synchronous_mode(true); | |
919 } | |
920 | |
921 SpdySessionDependencies::SpdySessionDependencies(ProxyService* proxy_service) | |
922 : host_resolver(new MockHostResolver), | |
923 cert_verifier(new CertVerifier), | |
924 proxy_service(proxy_service), | |
925 ssl_config_service(new SSLConfigServiceDefaults), | |
926 socket_factory(new MockClientSocketFactory), | |
927 deterministic_socket_factory(new DeterministicMockClientSocketFactory), | |
928 http_auth_handler_factory( | |
929 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())) {} | |
930 | |
931 SpdySessionDependencies::~SpdySessionDependencies() {} | |
932 | |
933 // static | |
934 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSession( | |
935 SpdySessionDependencies* session_deps) { | |
936 net::HttpNetworkSession::Params params; | |
937 params.client_socket_factory = session_deps->socket_factory.get(); | |
938 params.host_resolver = session_deps->host_resolver.get(); | |
939 params.cert_verifier = session_deps->cert_verifier.get(); | |
940 params.proxy_service = session_deps->proxy_service.get(); | |
941 params.ssl_config_service = session_deps->ssl_config_service; | |
942 params.http_auth_handler_factory = | |
943 session_deps->http_auth_handler_factory.get(); | |
944 params.http_server_properties = &session_deps->http_server_properties; | |
945 return new HttpNetworkSession(params); | |
946 } | |
947 | |
948 // static | |
949 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSessionDeterministic( | |
950 SpdySessionDependencies* session_deps) { | |
951 net::HttpNetworkSession::Params params; | |
952 params.client_socket_factory = | |
953 session_deps->deterministic_socket_factory.get(); | |
954 params.host_resolver = session_deps->host_resolver.get(); | |
955 params.cert_verifier = session_deps->cert_verifier.get(); | |
956 params.proxy_service = session_deps->proxy_service.get(); | |
957 params.ssl_config_service = session_deps->ssl_config_service; | |
958 params.http_auth_handler_factory = | |
959 session_deps->http_auth_handler_factory.get(); | |
960 params.http_server_properties = &session_deps->http_server_properties; | |
961 return new HttpNetworkSession(params); | |
962 } | |
963 | |
964 SpdyURLRequestContext::SpdyURLRequestContext() | |
965 : ALLOW_THIS_IN_INITIALIZER_LIST(storage_(this)) { | |
966 storage_.set_host_resolver(new MockHostResolver()); | |
967 storage_.set_cert_verifier(new CertVerifier); | |
968 storage_.set_proxy_service(ProxyService::CreateDirect()); | |
969 storage_.set_ssl_config_service(new SSLConfigServiceDefaults); | |
970 storage_.set_http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault( | |
971 host_resolver())); | |
972 storage_.set_http_server_properties(new HttpServerPropertiesImpl); | |
973 net::HttpNetworkSession::Params params; | |
974 params.client_socket_factory = &socket_factory_; | |
975 params.host_resolver = host_resolver(); | |
976 params.cert_verifier = cert_verifier(); | |
977 params.proxy_service = proxy_service(); | |
978 params.ssl_config_service = ssl_config_service(); | |
979 params.http_auth_handler_factory = http_auth_handler_factory(); | |
980 params.network_delegate = network_delegate(); | |
981 params.http_server_properties = http_server_properties(); | |
982 scoped_refptr<HttpNetworkSession> network_session( | |
983 new HttpNetworkSession(params)); | |
984 storage_.set_http_transaction_factory(new HttpCache( | |
985 network_session, | |
986 HttpCache::DefaultBackend::InMemory(0))); | |
987 } | |
988 | |
989 SpdyURLRequestContext::~SpdyURLRequestContext() { | |
990 } | |
991 | |
992 const SpdyHeaderInfo MakeSpdyHeader(spdy::SpdyControlType type) { | |
993 const SpdyHeaderInfo kHeader = { | |
994 type, // Kind = Syn | |
995 1, // Stream ID | |
996 0, // Associated stream ID | |
997 2, // Priority | |
998 spdy::CONTROL_FLAG_FIN, // Control Flags | |
999 false, // Compressed | |
1000 spdy::INVALID, // Status | |
1001 NULL, // Data | |
1002 0, // Length | |
1003 spdy::DATA_FLAG_NONE // Data Flags | |
1004 }; | |
1005 return kHeader; | |
1006 } | |
1007 } // namespace net | |
OLD | NEW |