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. 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. 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. 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. 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|. 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 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. 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. 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. 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. 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. 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|. 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 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 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. 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. 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. 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. 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. 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 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 } 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 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 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. 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. 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. 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. 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. 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. 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. 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. 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. 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|. 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|. 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. 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. 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. 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. 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. 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. 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. 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 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 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 914 SpdySessionDependencies::~SpdySessionDependencies() {} 915 916 // static 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 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 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 967 SpdyURLRequestContext::~SpdyURLRequestContext() { 968 delete http_transaction_factory(); 969 delete http_auth_handler_factory(); 970 delete cert_verifier(); 971 delete host_resolver(); 972 } 973 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