1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
|
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_SPDY_SPDY_TEST_UTIL_COMMON_H_
#define NET_SPDY_SPDY_TEST_UTIL_COMMON_H_
#include <string>
#include <vector>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "crypto/ec_private_key.h"
#include "crypto/ec_signature_creator.h"
#include "net/base/completion_callback.h"
#include "net/base/request_priority.h"
#include "net/base/test_completion_callback.h"
#include "net/cert/cert_verifier.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_network_session.h"
#include "net/http/http_response_info.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/transport_security_state.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_protocol.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#include "testing/gtest/include/gtest/gtest.h"
class GURL;
namespace net {
class BoundNetLog;
class SpdySession;
class SpdySessionKey;
class SpdySessionPool;
class SpdyStream;
class SpdyStreamRequest;
// Default upload data used by both, mock objects and framer when creating
// data frames.
const char kDefaultURL[] = "http://www.google.com";
const char kUploadData[] = "hello!";
const int kUploadDataSize = arraysize(kUploadData)-1;
// SpdyNextProtos returns a vector of next protocols for negotiating
// SPDY.
std::vector<NextProto> SpdyNextProtos();
// Chop a frame into an array of MockWrites.
// |data| is the frame to chop.
// |length| is the length of the frame to chop.
// |num_chunks| is the number of chunks to create.
MockWrite* ChopWriteFrame(const char* data, int length, int num_chunks);
// Chop a SpdyFrame into an array of MockWrites.
// |frame| is the frame to chop.
// |num_chunks| is the number of chunks to create.
MockWrite* ChopWriteFrame(const SpdyFrame& frame, int num_chunks);
// Chop a frame into an array of MockReads.
// |data| is the frame to chop.
// |length| is the length of the frame to chop.
// |num_chunks| is the number of chunks to create.
MockRead* ChopReadFrame(const char* data, int length, int num_chunks);
// Chop a SpdyFrame into an array of MockReads.
// |frame| is the frame to chop.
// |num_chunks| is the number of chunks to create.
MockRead* ChopReadFrame(const SpdyFrame& frame, int num_chunks);
// Adds headers and values to a map.
// |extra_headers| is an array of { name, value } pairs, arranged as strings
// where the even entries are the header names, and the odd entries are the
// header values.
// |headers| gets filled in from |extra_headers|.
void AppendToHeaderBlock(const char* const extra_headers[],
int extra_header_count,
SpdyHeaderBlock* headers);
// Create an async MockWrite from the given SpdyFrame.
MockWrite CreateMockWrite(const SpdyFrame& req);
// Create an async MockWrite from the given SpdyFrame and sequence number.
MockWrite CreateMockWrite(const SpdyFrame& req, int seq);
MockWrite CreateMockWrite(const SpdyFrame& req, int seq, IoMode mode);
// Create a MockRead from the given SpdyFrame.
MockRead CreateMockRead(const SpdyFrame& resp);
// Create a MockRead from the given SpdyFrame and sequence number.
MockRead CreateMockRead(const SpdyFrame& resp, int seq);
MockRead CreateMockRead(const SpdyFrame& resp, int seq, IoMode mode);
// Combines the given SpdyFrames into the given char array and returns
// the total length.
int CombineFrames(const SpdyFrame** frames, int num_frames,
char* buff, int buff_len);
// Returns the SpdyPriority embedded in the given frame. Returns true
// and fills in |priority| on success.
bool GetSpdyPriority(SpdyMajorVersion version,
const SpdyFrame& frame,
SpdyPriority* priority);
// Tries to create a stream in |session| synchronously. Returns NULL
// on failure.
base::WeakPtr<SpdyStream> CreateStreamSynchronously(
SpdyStreamType type,
const base::WeakPtr<SpdySession>& session,
const GURL& url,
RequestPriority priority,
const BoundNetLog& net_log);
// Helper class used by some tests to release a stream as soon as it's
// created.
class StreamReleaserCallback : public TestCompletionCallbackBase {
public:
StreamReleaserCallback();
virtual ~StreamReleaserCallback();
// Returns a callback that releases |request|'s stream.
CompletionCallback MakeCallback(SpdyStreamRequest* request);
private:
void OnComplete(SpdyStreamRequest* request, int result);
};
const size_t kSpdyCredentialSlotUnused = 0;
// This struct holds information used to construct spdy control and data frames.
struct SpdyHeaderInfo {
SpdyFrameType kind;
SpdyStreamId id;
SpdyStreamId assoc_id;
SpdyPriority priority;
size_t credential_slot; // SPDY3 only
SpdyControlFlags control_flags;
bool compressed;
SpdyRstStreamStatus status;
const char* data;
uint32 data_length;
SpdyDataFlags data_flags;
};
// An ECSignatureCreator that returns deterministic signatures.
class MockECSignatureCreator : public crypto::ECSignatureCreator {
public:
explicit MockECSignatureCreator(crypto::ECPrivateKey* key);
// crypto::ECSignatureCreator
virtual bool Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature) OVERRIDE;
virtual bool DecodeSignature(const std::vector<uint8>& signature,
std::vector<uint8>* out_raw_sig) OVERRIDE;
private:
crypto::ECPrivateKey* key_;
DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreator);
};
// An ECSignatureCreatorFactory creates MockECSignatureCreator.
class MockECSignatureCreatorFactory : public crypto::ECSignatureCreatorFactory {
public:
MockECSignatureCreatorFactory();
virtual ~MockECSignatureCreatorFactory();
// crypto::ECSignatureCreatorFactory
virtual crypto::ECSignatureCreator* Create(
crypto::ECPrivateKey* key) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreatorFactory);
};
// Helper to manage the lifetimes of the dependencies for a
// HttpNetworkTransaction.
struct SpdySessionDependencies {
// Default set of dependencies -- "null" proxy service.
explicit SpdySessionDependencies(NextProto protocol);
// Custom proxy service dependency.
SpdySessionDependencies(NextProto protocol, ProxyService* proxy_service);
~SpdySessionDependencies();
static HttpNetworkSession* SpdyCreateSession(
SpdySessionDependencies* session_deps);
static HttpNetworkSession* SpdyCreateSessionDeterministic(
SpdySessionDependencies* session_deps);
static HttpNetworkSession::Params CreateSessionParams(
SpdySessionDependencies* session_deps);
// NOTE: host_resolver must be ordered before http_auth_handler_factory.
scoped_ptr<MockHostResolverBase> host_resolver;
scoped_ptr<CertVerifier> cert_verifier;
scoped_ptr<TransportSecurityState> transport_security_state;
scoped_ptr<ProxyService> proxy_service;
scoped_refptr<SSLConfigService> ssl_config_service;
scoped_ptr<MockClientSocketFactory> socket_factory;
scoped_ptr<DeterministicMockClientSocketFactory> deterministic_socket_factory;
scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
HttpServerPropertiesImpl http_server_properties;
bool enable_ip_pooling;
bool enable_compression;
bool enable_ping;
bool enable_user_alternate_protocol_ports;
NextProto protocol;
size_t stream_initial_recv_window_size;
SpdySession::TimeFunc time_func;
std::string trusted_spdy_proxy;
NetLog* net_log;
};
class SpdyURLRequestContext : public URLRequestContext {
public:
explicit SpdyURLRequestContext(NextProto protocol);
virtual ~SpdyURLRequestContext();
MockClientSocketFactory& socket_factory() { return socket_factory_; }
private:
MockClientSocketFactory socket_factory_;
net::URLRequestContextStorage storage_;
};
// Equivalent to pool->GetIfExists(spdy_session_key, BoundNetLog()) != NULL.
bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key);
// Creates a SPDY session for the given key and puts it in the SPDY
// session pool in |http_session|. A SPDY session for |key| must not
// already exist.
base::WeakPtr<SpdySession> CreateInsecureSpdySession(
const scoped_refptr<HttpNetworkSession>& http_session,
const SpdySessionKey& key,
const BoundNetLog& net_log);
// Tries to create a SPDY session for the given key but expects the
// attempt to fail with the given error. A SPDY session for |key| must
// not already exist.
void TryCreateInsecureSpdySessionExpectingFailure(
const scoped_refptr<HttpNetworkSession>& http_session,
const SpdySessionKey& key,
Error expected_error,
const BoundNetLog& net_log);
// Like CreateInsecureSpdySession(), but uses TLS.
base::WeakPtr<SpdySession> CreateSecureSpdySession(
const scoped_refptr<HttpNetworkSession>& http_session,
const SpdySessionKey& key,
const BoundNetLog& net_log);
// Creates an insecure SPDY session for the given key and puts it in
// |pool|. The returned session will neither receive nor send any
// data. A SPDY session for |key| must not already exist.
base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool,
const SpdySessionKey& key);
// Tries to create an insecure SPDY session for the given key but
// expects the attempt to fail with the given error. The session will
// neither receive nor send any data. A SPDY session for |key| must
// not already exist.
void TryCreateFakeSpdySessionExpectingFailure(SpdySessionPool* pool,
const SpdySessionKey& key,
Error expected_error);
class SpdySessionPoolPeer {
public:
explicit SpdySessionPoolPeer(SpdySessionPool* pool);
void RemoveAliases(const SpdySessionKey& key);
void DisableDomainAuthenticationVerification();
void SetEnableSendingInitialData(bool enabled);
private:
SpdySessionPool* const pool_;
DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer);
};
class SpdyTestUtil {
public:
explicit SpdyTestUtil(NextProto protocol);
// Add the appropriate headers to put |url| into |block|.
void AddUrlToHeaderBlock(base::StringPiece url,
SpdyHeaderBlock* headers) const;
scoped_ptr<SpdyHeaderBlock> ConstructGetHeaderBlock(
base::StringPiece url) const;
scoped_ptr<SpdyHeaderBlock> ConstructGetHeaderBlockForProxy(
base::StringPiece url) const;
scoped_ptr<SpdyHeaderBlock> ConstructHeadHeaderBlock(
base::StringPiece url,
int64 content_length) const;
scoped_ptr<SpdyHeaderBlock> ConstructPostHeaderBlock(
base::StringPiece url,
int64 content_length) const;
scoped_ptr<SpdyHeaderBlock> ConstructPutHeaderBlock(
base::StringPiece url,
int64 content_length) const;
// Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as
// specified in header_info.kind), the provided headers are included in the
// frame.
SpdyFrame* ConstructSpdyFrame(
const SpdyHeaderInfo& header_info,
scoped_ptr<SpdyHeaderBlock> headers) const;
// Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as
// specified in header_info.kind), the headers provided in extra_headers and
// (if non-NULL) tail_headers are concatenated and included in the frame.
// (extra_headers must always be non-NULL.)
SpdyFrame* ConstructSpdyFrame(const SpdyHeaderInfo& header_info,
const char* const extra_headers[],
int extra_header_count,
const char* const tail_headers[],
int tail_header_count) const;
// Construct a generic SpdyControlFrame.
SpdyFrame* ConstructSpdyControlFrame(
scoped_ptr<SpdyHeaderBlock> headers,
bool compressed,
SpdyStreamId stream_id,
RequestPriority request_priority,
SpdyFrameType type,
SpdyControlFlags flags,
SpdyStreamId associated_stream_id) const;
// Construct a generic SpdyControlFrame.
//
// Warning: extra_header_count is the number of header-value pairs in
// extra_headers (so half the number of elements), but tail_headers_size is
// the actual number of elements (both keys and values) in tail_headers.
// TODO(ttuttle): Fix this inconsistency.
SpdyFrame* ConstructSpdyControlFrame(
const char* const extra_headers[],
int extra_header_count,
bool compressed,
SpdyStreamId stream_id,
RequestPriority request_priority,
SpdyFrameType type,
SpdyControlFlags flags,
const char* const* tail_headers,
int tail_headers_size,
SpdyStreamId associated_stream_id) const;
// Construct an expected SPDY reply string from the given headers.
std::string ConstructSpdyReplyString(const SpdyHeaderBlock& headers) const;
// Construct an expected SPDY SETTINGS frame.
// |settings| are the settings to set.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdySettings(const SettingsMap& settings) const;
// Construct a SPDY PING frame.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdyPing(uint32 ping_id, bool is_ack) const;
// Construct a SPDY GOAWAY frame with last_good_stream_id = 0.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdyGoAway() const;
// Construct a SPDY GOAWAY frame with the specified last_good_stream_id.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdyGoAway(SpdyStreamId last_good_stream_id) const;
// Construct a SPDY WINDOW_UPDATE frame.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdyWindowUpdate(
SpdyStreamId stream_id,
uint32 delta_window_size) const;
// Construct a SPDY RST_STREAM frame.
// Returns the constructed frame. The caller takes ownership of the frame.
SpdyFrame* ConstructSpdyRstStream(SpdyStreamId stream_id,
SpdyRstStreamStatus status) const;
// Constructs a standard SPDY GET SYN frame, optionally compressed
// for the url |url|.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const url,
bool compressed,
SpdyStreamId stream_id,
RequestPriority request_priority) const;
SpdyFrame* ConstructSpdyGetForProxy(const char* const url,
bool compressed,
SpdyStreamId stream_id,
RequestPriority request_priority) const;
// Constructs a standard SPDY GET SYN frame, optionally compressed.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls. If |direct| is false, the
// the full url will be used instead of simply the path.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGet(const char* const extra_headers[],
int extra_header_count,
bool compressed,
int stream_id,
RequestPriority request_priority,
bool direct) const;
// Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
int extra_header_count,
int stream_id,
RequestPriority priority) const;
// Constructs a standard SPDY push SYN frame.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
int extra_header_count,
int stream_id,
int associated_stream_id,
const char* url);
SpdyFrame* ConstructSpdyPush(const char* const extra_headers[],
int extra_header_count,
int stream_id,
int associated_stream_id,
const char* url,
const char* status,
const char* location);
SpdyFrame* ConstructSpdyPushHeaders(int stream_id,
const char* const extra_headers[],
int extra_header_count);
// Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[],
int extra_header_count,
int stream_id);
// Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id);
// Constructs a standard SPDY SYN_REPLY frame with an Internal Server
// Error status code.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdySynReplyError(int stream_id);
// Constructs a standard SPDY SYN_REPLY frame with the specified status code.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdySynReplyError(const char* const status,
const char* const* const extra_headers,
int extra_header_count,
int stream_id);
// Constructs a standard SPDY POST SYN frame.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPost(const char* url,
SpdyStreamId stream_id,
int64 content_length,
RequestPriority priority,
const char* const extra_headers[],
int extra_header_count);
// Constructs a chunked transfer SPDY POST SYN frame.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[],
int extra_header_count);
// Constructs a standard SPDY SYN_REPLY frame to match the SPDY POST.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdyFrame.
SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[],
int extra_header_count);
// Constructs a single SPDY data frame with the contents "hello!"
SpdyFrame* ConstructSpdyBodyFrame(int stream_id,
bool fin);
// Constructs a single SPDY data frame with the given content.
SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data,
uint32 len, bool fin);
// Wraps |frame| in the payload of a data frame in stream |stream_id|.
SpdyFrame* ConstructWrappedSpdyFrame(const scoped_ptr<SpdyFrame>& frame,
int stream_id);
const SpdyHeaderInfo MakeSpdyHeader(SpdyFrameType type);
NextProto protocol() const { return protocol_; }
SpdyMajorVersion spdy_version() const { return spdy_version_; }
bool is_spdy2() const { return protocol_ < kProtoSPDY3; }
scoped_ptr<SpdyFramer> CreateFramer() const;
const char* GetMethodKey() const;
const char* GetStatusKey() const;
const char* GetHostKey() const;
const char* GetSchemeKey() const;
const char* GetVersionKey() const;
const char* GetPathKey() const;
private:
// |content_length| may be NULL, in which case the content-length
// header will be omitted.
scoped_ptr<SpdyHeaderBlock> ConstructHeaderBlock(
base::StringPiece method,
base::StringPiece url,
int64* content_length) const;
const NextProto protocol_;
const SpdyMajorVersion spdy_version_;
};
} // namespace net
#endif // NET_SPDY_SPDY_TEST_UTIL_COMMON_H_
|