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 17namespace 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. 23MockWrite* 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. 38MockWrite* 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. 48MockRead* 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. 63MockRead* 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|. 74void 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 120int 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. 149spdy::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. 192spdy::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. 199spdy::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. 206spdy::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. 213spdy::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. 221spdy::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|. 232int 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 267spdy::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 288spdy::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. 323spdy::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. 385spdy::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. 398spdy::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. 428spdy::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. 452spdy::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 476spdy::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} 503spdy::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 534spdy::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 553spdy::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. 575spdy::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. 603spdy::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. 615spdy::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. 626spdy::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. 653spdy::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. 686spdy::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. 715spdy::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. 739spdy::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. 747spdy::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|. 755spdy::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|. 768int 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. 842MockWrite 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. 848MockWrite 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. 853MockWrite 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. 859MockRead 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. 865MockRead 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. 870MockRead 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. 877int 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 893SpdySessionDependencies::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 911SpdySessionDependencies::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 921SpdySessionDependencies::~SpdySessionDependencies() {} 922 923// static 924HttpNetworkSession* 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 938HttpNetworkSession* 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 952SpdyURLRequestContext::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 974SpdyURLRequestContext::~SpdyURLRequestContext() { 975 delete http_transaction_factory(); 976 delete http_auth_handler_factory(); 977 delete cert_verifier(); 978 delete host_resolver(); 979} 980 981const 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