1 // Copyright (c) 2013 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.
5 #include "net/spdy/spdy_test_util_common.h"
9 #include "base/compiler_specific.h"
10 #include "net/socket/socket_test_util.h"
11 #include "net/spdy/buffered_spdy_framer.h"
12 #include "net/spdy/spdy_session.h"
13 #include "net/spdy/spdy_stream.h"
17 // Chop a frame into an array of MockWrites.
18 // |data| is the frame to chop.
19 // |length| is the length of the frame to chop.
20 // |num_chunks| is the number of chunks to create.
21 MockWrite
* ChopWriteFrame(const char* data
, int length
, int num_chunks
) {
22 MockWrite
* chunks
= new MockWrite
[num_chunks
];
23 int chunk_size
= length
/ num_chunks
;
24 for (int index
= 0; index
< num_chunks
; index
++) {
25 const char* ptr
= data
+ (index
* chunk_size
);
26 if (index
== num_chunks
- 1)
27 chunk_size
+= length
% chunk_size
; // The last chunk takes the remainder.
28 chunks
[index
] = MockWrite(ASYNC
, ptr
, chunk_size
);
33 // Chop a SpdyFrame into an array of MockWrites.
34 // |frame| is the frame to chop.
35 // |num_chunks| is the number of chunks to create.
36 MockWrite
* ChopWriteFrame(const SpdyFrame
& frame
, int num_chunks
) {
37 return ChopWriteFrame(frame
.data(), frame
.size(), num_chunks
);
40 // Chop a frame into an array of MockReads.
41 // |data| is the frame to chop.
42 // |length| is the length of the frame to chop.
43 // |num_chunks| is the number of chunks to create.
44 MockRead
* ChopReadFrame(const char* data
, int length
, int num_chunks
) {
45 MockRead
* chunks
= new MockRead
[num_chunks
];
46 int chunk_size
= length
/ num_chunks
;
47 for (int index
= 0; index
< num_chunks
; index
++) {
48 const char* ptr
= data
+ (index
* chunk_size
);
49 if (index
== num_chunks
- 1)
50 chunk_size
+= length
% chunk_size
; // The last chunk takes the remainder.
51 chunks
[index
] = MockRead(ASYNC
, ptr
, chunk_size
);
56 // Chop a SpdyFrame into an array of MockReads.
57 // |frame| is the frame to chop.
58 // |num_chunks| is the number of chunks to create.
59 MockRead
* ChopReadFrame(const SpdyFrame
& frame
, int num_chunks
) {
60 return ChopReadFrame(frame
.data(), frame
.size(), num_chunks
);
63 // Adds headers and values to a map.
64 // |extra_headers| is an array of { name, value } pairs, arranged as strings
65 // where the even entries are the header names, and the odd entries are the
67 // |headers| gets filled in from |extra_headers|.
68 void AppendToHeaderBlock(const char* const extra_headers
[],
69 int extra_header_count
,
70 SpdyHeaderBlock
* headers
) {
71 std::string this_header
;
72 std::string this_value
;
74 if (!extra_header_count
)
77 // Sanity check: Non-NULL header list.
78 DCHECK(NULL
!= extra_headers
) << "NULL header value pair list";
79 // Sanity check: Non-NULL header map.
80 DCHECK(NULL
!= headers
) << "NULL header map";
81 // Copy in the headers.
82 for (int i
= 0; i
< extra_header_count
; i
++) {
83 // Sanity check: Non-empty header.
84 DCHECK_NE('\0', *extra_headers
[i
* 2]) << "Empty header value pair";
85 this_header
= extra_headers
[i
* 2];
86 std::string::size_type header_len
= this_header
.length();
89 this_value
= extra_headers
[1 + (i
* 2)];
90 std::string new_value
;
91 if (headers
->find(this_header
) != headers
->end()) {
92 // More than one entry in the header.
93 // Don't add the header again, just the append to the value,
94 // separated by a NULL character.
97 new_value
= (*headers
)[this_header
];
98 // Put in a NULL separator.
99 new_value
.append(1, '\0');
100 // Append the new value.
101 new_value
+= this_value
;
103 // Not a duplicate, just write the value.
104 new_value
= this_value
;
106 (*headers
)[this_header
] = new_value
;
110 // Writes |val| to a location of size |len|, in big-endian format.
111 // in the buffer pointed to by |buffer_handle|.
112 // Updates the |*buffer_handle| pointer by |len|
113 // Returns the number of bytes written
114 int AppendToBuffer(int val
,
116 unsigned char** buffer_handle
,
117 int* buffer_len_remaining
) {
120 DCHECK((size_t) len
<= sizeof(len
)) << "Data length too long for data type";
121 DCHECK(NULL
!= buffer_handle
) << "NULL buffer handle";
122 DCHECK(NULL
!= *buffer_handle
) << "NULL pointer";
123 DCHECK(NULL
!= buffer_len_remaining
)
124 << "NULL buffer remainder length pointer";
125 DCHECK_GE(*buffer_len_remaining
, len
) << "Insufficient buffer size";
126 for (int i
= 0; i
< len
; i
++) {
127 int shift
= (8 * (len
- (i
+ 1)));
128 unsigned char val_chunk
= (val
>> shift
) & 0x0FF;
129 *(*buffer_handle
)++ = val_chunk
;
130 *buffer_len_remaining
+= 1;
135 // Create a MockWrite from the given SpdyFrame.
136 MockWrite
CreateMockWrite(const SpdyFrame
& req
) {
137 return MockWrite(ASYNC
, req
.data(), req
.size());
140 // Create a MockWrite from the given SpdyFrame and sequence number.
141 MockWrite
CreateMockWrite(const SpdyFrame
& req
, int seq
) {
142 return CreateMockWrite(req
, seq
, ASYNC
);
145 // Create a MockWrite from the given SpdyFrame and sequence number.
146 MockWrite
CreateMockWrite(const SpdyFrame
& req
, int seq
, IoMode mode
) {
147 return MockWrite(mode
, req
.data(), req
.size(), seq
);
150 // Create a MockRead from the given SpdyFrame.
151 MockRead
CreateMockRead(const SpdyFrame
& resp
) {
152 return MockRead(ASYNC
, resp
.data(), resp
.size());
155 // Create a MockRead from the given SpdyFrame and sequence number.
156 MockRead
CreateMockRead(const SpdyFrame
& resp
, int seq
) {
157 return CreateMockRead(resp
, seq
, ASYNC
);
160 // Create a MockRead from the given SpdyFrame and sequence number.
161 MockRead
CreateMockRead(const SpdyFrame
& resp
, int seq
, IoMode mode
) {
162 return MockRead(mode
, resp
.data(), resp
.size(), seq
);
165 // Combines the given SpdyFrames into the given char array and returns
167 int CombineFrames(const SpdyFrame
** frames
, int num_frames
,
168 char* buff
, int buff_len
) {
170 for (int i
= 0; i
< num_frames
; ++i
) {
171 total_len
+= frames
[i
]->size();
173 DCHECK_LE(total_len
, buff_len
);
175 for (int i
= 0; i
< num_frames
; ++i
) {
176 int len
= frames
[i
]->size();
177 memcpy(ptr
, frames
[i
]->data(), len
);
185 class PriorityGetter
: public BufferedSpdyFramerVisitorInterface
{
187 PriorityGetter() : priority_(0) {}
188 virtual ~PriorityGetter() {}
190 SpdyPriority
priority() const {
194 virtual void OnError(SpdyFramer::SpdyError error_code
) OVERRIDE
{}
195 virtual void OnStreamError(SpdyStreamId stream_id
,
196 const std::string
& description
) OVERRIDE
{}
197 virtual void OnSynStream(SpdyStreamId stream_id
,
198 SpdyStreamId associated_stream_id
,
199 SpdyPriority priority
,
200 uint8 credential_slot
,
203 const SpdyHeaderBlock
& headers
) OVERRIDE
{
204 priority_
= priority
;
206 virtual void OnSynReply(SpdyStreamId stream_id
,
208 const SpdyHeaderBlock
& headers
) OVERRIDE
{}
209 virtual void OnHeaders(SpdyStreamId stream_id
,
211 const SpdyHeaderBlock
& headers
) OVERRIDE
{}
212 virtual void OnStreamFrameData(SpdyStreamId stream_id
,
215 bool fin
) OVERRIDE
{}
216 virtual void OnSetting(
217 SpdySettingsIds id
, uint8 flags
, uint32 value
) OVERRIDE
{}
218 virtual void OnPing(uint32 unique_id
) OVERRIDE
{}
219 virtual void OnRstStream(SpdyStreamId stream_id
,
220 SpdyRstStreamStatus status
) OVERRIDE
{}
221 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id
,
222 SpdyGoAwayStatus status
) OVERRIDE
{}
223 virtual void OnWindowUpdate(SpdyStreamId stream_id
,
224 uint32 delta_window_size
) OVERRIDE
{}
225 virtual void OnSynStreamCompressed(
226 size_t uncompressed_size
,
227 size_t compressed_size
) OVERRIDE
{}
230 SpdyPriority priority_
;
235 bool GetSpdyPriority(int version
,
236 const SpdyFrame
& frame
,
237 SpdyPriority
* priority
) {
238 BufferedSpdyFramer
framer(version
, false);
239 PriorityGetter priority_getter
;
240 framer
.set_visitor(&priority_getter
);
241 size_t frame_size
= frame
.size();
242 if (framer
.ProcessInput(frame
.data(), frame_size
) != frame_size
) {
245 *priority
= priority_getter
.priority();
249 scoped_refptr
<SpdyStream
> CreateStreamSynchronously(
250 const scoped_refptr
<SpdySession
>& session
,
252 RequestPriority priority
,
253 const BoundNetLog
& net_log
) {
254 SpdyStreamRequest stream_request
;
255 int rv
= stream_request
.StartRequest(session
, url
, priority
, net_log
,
256 CompletionCallback());
257 return (rv
== OK
) ? stream_request
.ReleaseStream() : NULL
;
260 StreamReleaserCallback::StreamReleaserCallback(
261 SpdySession
* session
,
262 SpdyStream
* first_stream
)
264 first_stream_(first_stream
) {}
266 StreamReleaserCallback::~StreamReleaserCallback() {}
268 CompletionCallback
StreamReleaserCallback::MakeCallback(
269 SpdyStreamRequest
* request
) {
270 return base::Bind(&StreamReleaserCallback::OnComplete
,
271 base::Unretained(this),
275 void StreamReleaserCallback::OnComplete(
276 SpdyStreamRequest
* request
, int result
) {
277 session_
->CloseSessionOnError(ERR_FAILED
, false, "On complete.");
279 first_stream_
->Cancel();
280 first_stream_
= NULL
;
281 request
->ReleaseStream()->Cancel();