| 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 |