OLD | NEW |
(Empty) | |
| 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 "base/basictypes.h" |
| 8 #include "base/string_util.h" |
| 9 |
| 10 namespace net { |
| 11 |
| 12 // Chop a frame into an array of MockWrites. |
| 13 // |data| is the frame to chop. |
| 14 // |length| is the length of the frame to chop. |
| 15 // |num_chunks| is the number of chunks to create. |
| 16 MockWrite* ChopFrame(const char* data, int length, int num_chunks) { |
| 17 MockWrite* chunks = new MockWrite[num_chunks]; |
| 18 int chunk_size = length / num_chunks; |
| 19 for (int index = 0; index < num_chunks; index++) { |
| 20 const char* ptr = data + (index * chunk_size); |
| 21 if (index == num_chunks - 1) |
| 22 chunk_size += length % chunk_size; // The last chunk takes the remainder. |
| 23 chunks[index] = MockWrite(true, ptr, chunk_size); |
| 24 } |
| 25 return chunks; |
| 26 } |
| 27 |
| 28 // Chop a SpdyFrame into an array of MockWrites. |
| 29 // |frame| is the frame to chop. |
| 30 // |num_chunks| is the number of chunks to create. |
| 31 MockWrite* ChopFrame(const spdy::SpdyFrame* frame, int num_chunks) { |
| 32 return ChopFrame(frame->data(), |
| 33 frame->length() + spdy::SpdyFrame::size(), |
| 34 num_chunks); |
| 35 } |
| 36 |
| 37 // Adds headers and values to a map. |
| 38 // |extra_headers| is an array of { name, value } pairs, arranged as strings |
| 39 // where the even entries are the header names, and the odd entries are the |
| 40 // header values. |
| 41 // |headers| gets filled in from |extra_headers|. |
| 42 void AppendHeadersToSpdyFrame(const char* const extra_headers[], |
| 43 int extra_header_count, |
| 44 spdy::SpdyHeaderBlock* headers) { |
| 45 std::string this_header; |
| 46 std::string this_value; |
| 47 |
| 48 if (!extra_header_count) |
| 49 return; |
| 50 |
| 51 // Sanity check: Non-NULL header list. |
| 52 DCHECK(NULL != extra_headers) << "NULL header value pair list"; |
| 53 // Sanity check: Non-NULL header map. |
| 54 DCHECK(NULL != headers) << "NULL header map"; |
| 55 // Copy in the headers. |
| 56 for (int i = 0; i < extra_header_count; i++) { |
| 57 // Sanity check: Non-empty header. |
| 58 DCHECK_NE('\0', *extra_headers[i * 2]) << "Empty header value pair"; |
| 59 this_header = extra_headers[i * 2]; |
| 60 std::string::size_type header_len = this_header.length(); |
| 61 if (!header_len) |
| 62 continue; |
| 63 this_value = extra_headers[1 + (i * 2)]; |
| 64 std::string new_value; |
| 65 if (headers->find(this_header) != headers->end()) { |
| 66 // More than one entry in the header. |
| 67 // Don't add the header again, just the append to the value, |
| 68 // separated by a NULL character. |
| 69 |
| 70 // Adjust the value. |
| 71 new_value = (*headers)[this_header]; |
| 72 // Put in a NULL separator. |
| 73 new_value.append(1, '\0'); |
| 74 // Append the new value. |
| 75 new_value += this_value; |
| 76 } else { |
| 77 // Not a duplicate, just write the value. |
| 78 new_value = this_value; |
| 79 } |
| 80 (*headers)[this_header] = new_value; |
| 81 } |
| 82 } |
| 83 |
| 84 // Writes |val| to a location of size |len|, in big-endian format. |
| 85 // in the buffer pointed to by |buffer_handle|. |
| 86 // Updates the |*buffer_handle| pointer by |len| |
| 87 // Returns the number of bytes written |
| 88 int AppendToBuffer(int val, |
| 89 int len, |
| 90 unsigned char** buffer_handle, |
| 91 int* buffer_len_remaining) { |
| 92 if (len <= 0) |
| 93 return 0; |
| 94 DCHECK((size_t) len <= sizeof(len)) << "Data length too long for data type"; |
| 95 DCHECK(NULL != buffer_handle) << "NULL buffer handle"; |
| 96 DCHECK(NULL != *buffer_handle) << "NULL pointer"; |
| 97 DCHECK(NULL != buffer_len_remaining) |
| 98 << "NULL buffer remainder length pointer"; |
| 99 DCHECK_GE(*buffer_len_remaining, len) << "Insufficient buffer size"; |
| 100 for (int i = 0; i < len; i++) { |
| 101 int shift = (8 * (len - (i + 1))); |
| 102 unsigned char val_chunk = (val >> shift) & 0x0FF; |
| 103 *(*buffer_handle)++ = val_chunk; |
| 104 *buffer_len_remaining += 1; |
| 105 } |
| 106 return len; |
| 107 } |
| 108 |
| 109 // Construct a SPDY packet. |
| 110 // |head| is the start of the packet, up to but not including |
| 111 // the header value pairs. |
| 112 // |extra_headers| are the extra header-value pairs, which typically |
| 113 // will vary the most between calls. |
| 114 // |tail| is any (relatively constant) header-value pairs to add. |
| 115 // |buffer| is the buffer we're filling in. |
| 116 // Returns a SpdyFrame. |
| 117 spdy::SpdyFrame* ConstructSpdyPacket(const SpdyHeaderInfo* header_info, |
| 118 const char* const extra_headers[], |
| 119 int extra_header_count, |
| 120 const char* const tail[], |
| 121 int tail_header_count) { |
| 122 spdy::SpdyFramer framer; |
| 123 spdy::SpdyHeaderBlock headers; |
| 124 // Copy in the extra headers to our map. |
| 125 AppendHeadersToSpdyFrame(extra_headers, extra_header_count, &headers); |
| 126 // Copy in the tail headers to our map. |
| 127 if (tail && tail_header_count) |
| 128 AppendHeadersToSpdyFrame(tail, tail_header_count, &headers); |
| 129 spdy::SpdyFrame* frame = NULL; |
| 130 switch (header_info->kind) { |
| 131 case spdy::SYN_STREAM: |
| 132 frame = framer.CreateSynStream(header_info->id, header_info->assoc_id, |
| 133 header_info->priority, |
| 134 header_info->control_flags, |
| 135 header_info->compressed, &headers); |
| 136 break; |
| 137 case spdy::SYN_REPLY: |
| 138 frame = framer.CreateSynReply(header_info->id, header_info->control_flags, |
| 139 header_info->compressed, &headers); |
| 140 break; |
| 141 case spdy::RST_STREAM: |
| 142 frame = framer.CreateRstStream(header_info->id, header_info->status); |
| 143 break; |
| 144 default: |
| 145 frame = framer.CreateDataFrame(header_info->id, header_info->data, |
| 146 header_info->data_length, |
| 147 header_info->data_flags); |
| 148 break; |
| 149 } |
| 150 return frame; |
| 151 } |
| 152 |
| 153 // Construct an expected SPDY SETTINGS frame. |
| 154 // |settings| are the settings to set. |
| 155 // Returns the constructed frame. The caller takes ownership of the frame. |
| 156 spdy::SpdyFrame* ConstructSpdySettings(spdy::SpdySettings settings) { |
| 157 spdy::SpdyFramer framer; |
| 158 return framer.CreateSettings(settings); |
| 159 } |
| 160 |
| 161 // Construct a single SPDY header entry, for validation. |
| 162 // |extra_headers| are the extra header-value pairs. |
| 163 // |buffer| is the buffer we're filling in. |
| 164 // |index| is the index of the header we want. |
| 165 // Returns the number of bytes written into |buffer|. |
| 166 int ConstructSpdyHeader(const char* const extra_headers[], |
| 167 int extra_header_count, |
| 168 char* buffer, |
| 169 int buffer_length, |
| 170 int index) { |
| 171 const char* this_header = NULL; |
| 172 const char* this_value = NULL; |
| 173 if (!buffer || !buffer_length) |
| 174 return 0; |
| 175 *buffer = '\0'; |
| 176 // Sanity check: Non-empty header list. |
| 177 DCHECK(NULL != extra_headers) << "NULL extra headers pointer"; |
| 178 // Sanity check: Index out of range. |
| 179 DCHECK((index >= 0) && (index < extra_header_count)) |
| 180 << "Index " << index |
| 181 << " out of range [0, " << extra_header_count << ")"; |
| 182 this_header = extra_headers[index * 2]; |
| 183 // Sanity check: Non-empty header. |
| 184 if (!*this_header) |
| 185 return 0; |
| 186 std::string::size_type header_len = strlen(this_header); |
| 187 if (!header_len) |
| 188 return 0; |
| 189 this_value = extra_headers[1 + (index * 2)]; |
| 190 // Sanity check: Non-empty value. |
| 191 if (!*this_value) |
| 192 this_value = ""; |
| 193 int n = base::snprintf(buffer, |
| 194 buffer_length, |
| 195 "%s: %s\r\n", |
| 196 this_header, |
| 197 this_value); |
| 198 return n; |
| 199 } |
| 200 |
| 201 // Constructs a standard SPDY GET packet. |
| 202 // |extra_headers| are the extra header-value pairs, which typically |
| 203 // will vary the most between calls. |
| 204 // Returns a SpdyFrame. |
| 205 spdy::SpdyFrame* ConstructSpdyGet(const char* const extra_headers[], |
| 206 int extra_header_count) { |
| 207 SpdyHeaderInfo SynStartHeader = { |
| 208 spdy::SYN_STREAM, // Kind = Syn |
| 209 1, // Stream ID |
| 210 0, // Associated stream ID |
| 211 SPDY_PRIORITY_LOWEST, // Priority |
| 212 spdy::CONTROL_FLAG_FIN, // Control Flags |
| 213 false, // Compressed |
| 214 spdy::INVALID, // Status |
| 215 NULL, // Data |
| 216 0, // Length |
| 217 spdy::DATA_FLAG_NONE // Data Flags |
| 218 }; |
| 219 static const char* const kStandardGetHeaders[] = { |
| 220 "method", |
| 221 "GET", |
| 222 "url", |
| 223 "http://www.google.com/", |
| 224 "version", |
| 225 "HTTP/1.1" |
| 226 }; |
| 227 return ConstructSpdyPacket( |
| 228 &SynStartHeader, |
| 229 extra_headers, |
| 230 extra_header_count, |
| 231 kStandardGetHeaders, |
| 232 arraysize(kStandardGetHeaders) / 2); |
| 233 } |
| 234 |
| 235 // Constructs a standard SPDY SYN_REPLY packet to match the SPDY GET. |
| 236 // |extra_headers| are the extra header-value pairs, which typically |
| 237 // will vary the most between calls. |
| 238 // Returns a SpdyFrame. |
| 239 spdy::SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[], |
| 240 int extra_header_count) { |
| 241 SpdyHeaderInfo SynStartHeader = { |
| 242 spdy::SYN_REPLY, // Kind = SynReply |
| 243 1, // Stream ID |
| 244 0, // Associated stream ID |
| 245 SPDY_PRIORITY_LOWEST, // Priority |
| 246 spdy::CONTROL_FLAG_NONE, // Control Flags |
| 247 false, // Compressed |
| 248 spdy::INVALID, // Status |
| 249 NULL, // Data |
| 250 0, // Length |
| 251 spdy::DATA_FLAG_NONE // Data Flags |
| 252 }; |
| 253 static const char* const kStandardGetHeaders[] = { |
| 254 "hello", |
| 255 "bye", |
| 256 "status", |
| 257 "200", |
| 258 "url", |
| 259 "/index.php", |
| 260 "version", |
| 261 "HTTP/1.1" |
| 262 }; |
| 263 return ConstructSpdyPacket( |
| 264 &SynStartHeader, |
| 265 extra_headers, |
| 266 extra_header_count, |
| 267 kStandardGetHeaders, |
| 268 arraysize(kStandardGetHeaders) / 2); |
| 269 } |
| 270 |
| 271 // Construct an expected SPDY reply string. |
| 272 // |extra_headers| are the extra header-value pairs, which typically |
| 273 // will vary the most between calls. |
| 274 // |buffer| is the buffer we're filling in. |
| 275 // Returns the number of bytes written into |buffer|. |
| 276 int ConstructSpdyReplyString(const char* const extra_headers[], |
| 277 int extra_header_count, |
| 278 char* buffer, |
| 279 int buffer_length) { |
| 280 int packet_size = 0; |
| 281 int header_count = 0; |
| 282 char* buffer_write = buffer; |
| 283 int buffer_left = buffer_length; |
| 284 spdy::SpdyHeaderBlock headers; |
| 285 if (!buffer || !buffer_length) |
| 286 return 0; |
| 287 // Copy in the extra headers. |
| 288 AppendHeadersToSpdyFrame(extra_headers, extra_header_count, &headers); |
| 289 header_count = headers.size(); |
| 290 // The iterator gets us the list of header/value pairs in sorted order. |
| 291 spdy::SpdyHeaderBlock::iterator next = headers.begin(); |
| 292 spdy::SpdyHeaderBlock::iterator last = headers.end(); |
| 293 for ( ; next != last; ++next) { |
| 294 // Write the header. |
| 295 int value_len, current_len, offset; |
| 296 const char* header_string = next->first.c_str(); |
| 297 packet_size += AppendToBuffer(header_string, |
| 298 next->first.length(), |
| 299 &buffer_write, |
| 300 &buffer_left); |
| 301 packet_size += AppendToBuffer(": ", |
| 302 strlen(": "), |
| 303 &buffer_write, |
| 304 &buffer_left); |
| 305 // Write the value(s). |
| 306 const char* value_string = next->second.c_str(); |
| 307 // Check if it's split among two or more values. |
| 308 value_len = next->second.length(); |
| 309 current_len = strlen(value_string); |
| 310 offset = 0; |
| 311 // Handle the first N-1 values. |
| 312 while (current_len < value_len) { |
| 313 // Finish this line -- write the current value. |
| 314 packet_size += AppendToBuffer(value_string + offset, |
| 315 current_len - offset, |
| 316 &buffer_write, |
| 317 &buffer_left); |
| 318 packet_size += AppendToBuffer("\n", |
| 319 strlen("\n"), |
| 320 &buffer_write, |
| 321 &buffer_left); |
| 322 // Advance to next value. |
| 323 offset = current_len + 1; |
| 324 current_len += 1 + strlen(value_string + offset); |
| 325 // Start another line -- add the header again. |
| 326 packet_size += AppendToBuffer(header_string, |
| 327 next->first.length(), |
| 328 &buffer_write, |
| 329 &buffer_left); |
| 330 packet_size += AppendToBuffer(": ", |
| 331 strlen(": "), |
| 332 &buffer_write, |
| 333 &buffer_left); |
| 334 } |
| 335 EXPECT_EQ(value_len, current_len); |
| 336 // Copy the last (or only) value. |
| 337 packet_size += AppendToBuffer(value_string + offset, |
| 338 value_len - offset, |
| 339 &buffer_write, |
| 340 &buffer_left); |
| 341 packet_size += AppendToBuffer("\n", |
| 342 strlen("\n"), |
| 343 &buffer_write, |
| 344 &buffer_left); |
| 345 } |
| 346 return packet_size; |
| 347 } |
| 348 |
| 349 // Create a MockWrite from the given SpdyFrame. |
| 350 MockWrite CreateMockWrite(spdy::SpdyFrame* req) { |
| 351 return MockWrite( |
| 352 true, req->data(), req->length() + spdy::SpdyFrame::size()); |
| 353 } |
| 354 |
| 355 // Create a MockRead from the given SpdyFrame. |
| 356 MockRead CreateMockRead(spdy::SpdyFrame* resp) { |
| 357 return MockRead( |
| 358 true, resp->data(), resp->length() + spdy::SpdyFrame::size()); |
| 359 } |
| 360 |
| 361 // Create a MockRead from the given SpdyFrame and sequence number. |
| 362 MockRead CreateMockRead(spdy::SpdyFrame* resp, int seq) { |
| 363 return MockRead( |
| 364 true, resp->data(), resp->length() + spdy::SpdyFrame::size(), seq); |
| 365 } |
| 366 |
| 367 } // namespace net |
OLD | NEW |