Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: net/quic/quic_http_stream.cc

Issue 11364068: Add a QuicHttpStream class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: NET_EXPORT_PRIVATE Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/quic/quic_http_stream.h ('k') | net/quic/quic_http_stream_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/quic/quic_http_stream.h"
6
7 #include "base/stringprintf.h"
8 #include "net/base/io_buffer.h"
9 #include "net/base/net_errors.h"
10 #include "net/http/http_response_headers.h"
11 #include "net/http/http_util.h"
12 #include "net/quic/quic_client_session.h"
13 #include "net/quic/quic_reliable_client_stream.h"
14 #include "net/quic/quic_utils.h"
15 #include "net/socket/next_proto.h"
16 #include "net/spdy/spdy_framer.h"
17
18 namespace net {
19
20 static const size_t kHeaderBufInitialSize = 4096;
21
22 QuicHttpStream::QuicHttpStream(QuicReliableClientStream* stream)
23 : io_state_(STATE_NONE),
24 stream_(stream),
25 request_info_(NULL),
26 request_body_stream_(NULL),
27 response_info_(NULL),
28 response_headers_received_(false),
29 read_buf_(new GrowableIOBuffer()),
30 user_buffer_len_(0),
31 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
32 DCHECK(stream_);
33 stream_->SetDelegate(this);
34 }
35
36 QuicHttpStream::~QuicHttpStream() {
37 Close(false);
38 }
39
40 int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
41 const BoundNetLog& stream_net_log,
42 const CompletionCallback& callback) {
43 CHECK(stream_);
44
45 request_info_ = request_info;
46
47 return OK;
48 }
49
50 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
51 HttpResponseInfo* response,
52 const CompletionCallback& callback) {
53 CHECK(stream_);
54 CHECK(!request_body_stream_);
55 CHECK(!response_info_);
56 CHECK(!callback.is_null());
57 CHECK(response);
58
59 // Store the serialized request headers.
60 // TODO(rch): use SPDY serialization
61 std::string path = HttpUtil::PathForRequest(request_info_->url);
62 std::string first_line = base::StringPrintf("%s %s HTTP/1.1\r\n",
63 request_info_->method.c_str(),
64 path.c_str());
65 request_ = first_line + request_headers.ToString();
66
67 // Store the request body.
68 request_body_stream_ = request_info_->upload_data_stream;
69 if (request_body_stream_ && (request_body_stream_->size() ||
70 request_body_stream_->is_chunked())) {
71 // Use kMaxPacketSize as the buffer size, since the request
72 // body data is written with this size at a time.
73 // TODO(rch): use a smarter value since we can't write an entire
74 // packet due to overhead.
75 raw_request_body_buf_ = new IOBufferWithSize(kMaxPacketSize);
76 // The request body buffer is empty at first.
77 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, 0);
78 }
79
80 // Store the response info.
81 response_info_ = response;
82
83 io_state_ = STATE_SEND_HEADERS;
84 int rv = DoLoop(OK);
85 if (rv == ERR_IO_PENDING)
86 callback_ = callback;
87
88 return rv > 0 ? OK : rv;
89 }
90
91 UploadProgress QuicHttpStream::GetUploadProgress() const {
92 if (!request_body_stream_)
93 return UploadProgress();
94
95 return UploadProgress(request_body_stream_->position(),
96 request_body_stream_->size());
97 }
98
99 int QuicHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
100 CHECK(!callback.is_null());
101 // Check if we already have the response headers. If so, return synchronously.
102 if (response_headers_received_) {
103 return OK;
104 }
105
106 // Still waiting for the response, return IO_PENDING.
107 CHECK(callback_.is_null());
108 callback_ = callback;
109 return ERR_IO_PENDING;
110 }
111
112 const HttpResponseInfo* QuicHttpStream::GetResponseInfo() const {
113 return response_info_;
114 }
115
116 int QuicHttpStream::ReadResponseBody(
117 IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
118 CHECK(buf);
119 CHECK(buf_len);
120 CHECK(!callback.is_null());
121
122 // If we have data buffered, complete the IO immediately.
123 if (!response_body_.empty()) {
124 int bytes_read = 0;
125 while (!response_body_.empty() && buf_len > 0) {
126 scoped_refptr<IOBufferWithSize> data = response_body_.front();
127 const int bytes_to_copy = std::min(buf_len, data->size());
128 memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
129 buf_len -= bytes_to_copy;
130 if (bytes_to_copy == data->size()) {
131 response_body_.pop_front();
132 } else {
133 const int bytes_remaining = data->size() - bytes_to_copy;
134 IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
135 memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
136 bytes_remaining);
137 response_body_.pop_front();
138 response_body_.push_front(make_scoped_refptr(new_buffer));
139 }
140 bytes_read += bytes_to_copy;
141 }
142 return bytes_read;
143 }
144
145 if (!stream_) {
146 // If the stream is already closed, there is no body to read.
147 return 0;
148 }
149
150 CHECK(callback_.is_null());
151 CHECK(!user_buffer_);
152 CHECK_EQ(0, user_buffer_len_);
153
154 callback_ = callback;
155 user_buffer_ = buf;
156 user_buffer_len_ = buf_len;
157 return ERR_IO_PENDING;
158 }
159
160 void QuicHttpStream::Close(bool not_reusable) {
161 // Note: the not_reusable flag has no meaning for SPDY streams.
162 if (stream_) {
163 stream_->Close(QUIC_NO_ERROR);
164 }
165 }
166
167 HttpStream* QuicHttpStream::RenewStreamForAuth() {
168 return NULL;
169 }
170
171 bool QuicHttpStream::IsResponseBodyComplete() const {
172 return io_state_ == STATE_OPEN && !stream_;
173 }
174
175 bool QuicHttpStream::CanFindEndOfResponse() const {
176 return true;
177 }
178
179 bool QuicHttpStream::IsMoreDataBuffered() const {
180 return false;
181 }
182
183 bool QuicHttpStream::IsConnectionReused() const {
184 // TODO(rch): do something smarter here.
185 return stream_ && stream_->id() > 1;
186 }
187
188 void QuicHttpStream::SetConnectionReused() {
189 // QUIC doesn't need an indicator here.
190 }
191
192 bool QuicHttpStream::IsConnectionReusable() const {
193 // QUIC streams aren't considered reusable.
194 return false;
195 }
196
197 void QuicHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
198 DCHECK(stream_);
199 NOTIMPLEMENTED();
200 }
201
202 void QuicHttpStream::GetSSLCertRequestInfo(
203 SSLCertRequestInfo* cert_request_info) {
204 DCHECK(stream_);
205 NOTIMPLEMENTED();
206 }
207
208 bool QuicHttpStream::IsSpdyHttpStream() const {
209 return false;
210 }
211
212 void QuicHttpStream::Drain(HttpNetworkSession* session) {
213 if (stream_)
214 stream_->Close(QUIC_NO_ERROR);
215 delete this;
216 }
217
218 int QuicHttpStream::OnSendData() {
219 // TODO(rch): Change QUIC IO to provide notifications to the streams.
220 NOTREACHED();
221 return OK;
222 }
223
224 int QuicHttpStream::OnSendDataComplete(int status, bool* eof) {
225 // TODO(rch): Change QUIC IO to provide notifications to the streams.
226 NOTREACHED();
227 return OK;
228 }
229
230 int QuicHttpStream::OnDataReceived(const char* data, int length) {
231 // Are we still reading the response headers.
232 if (!response_headers_received_) {
233 // Grow the read buffer if necessary.
234 if (read_buf_->RemainingCapacity() < length) {
235 read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
236 }
237 memcpy(read_buf_->data(), data, length);
238 read_buf_->set_offset(read_buf_->offset() + length);
239 int rv = ParseResponseHeaders();
240 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
241 DoCallback(rv);
242 }
243 return OK;
244 }
245
246 if (callback_.is_null()) {
247 BufferResponseBody(data, length);
248 return OK;
249 }
250
251 if (length <= user_buffer_len_) {
252 memcpy(user_buffer_->data(), data, length);
253 } else {
254 memcpy(user_buffer_->data(), data, user_buffer_len_);
255 int delta = length - user_buffer_len_;
256 BufferResponseBody(data + user_buffer_len_, delta);
257 }
258 user_buffer_ = NULL;
259 user_buffer_len_ = 0;
260 DoCallback(length);
261 return OK;
262 }
263
264 void QuicHttpStream::OnClose(QuicErrorCode error) {
265 // TOOD(rch): find better errors.
266 int status = error == QUIC_NO_ERROR && response_headers_received_ ?
267 OK : ERR_ABORTED;
268 stream_ = NULL;
269 if (!callback_.is_null())
270 DoCallback(status);
271 }
272
273 void QuicHttpStream::OnIOComplete(int rv) {
274 rv = DoLoop(rv);
275
276 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
277 DoCallback(rv);
278 }
279 }
280
281 void QuicHttpStream::DoCallback(int rv) {
282 CHECK_NE(rv, ERR_IO_PENDING);
283 CHECK(!callback_.is_null());
284
285 // The client callback can do anything, including destroying this class,
286 // so any pending callback must be issued after everything else is done.
287 CompletionCallback c = callback_;
288 callback_.Reset();
289 c.Run(rv);
290 }
291
292 int QuicHttpStream::DoLoop(int rv) {
293 do {
294 switch (io_state_) {
295 case STATE_SEND_HEADERS:
296 CHECK_EQ(OK, rv);
297 rv = DoSendHeaders();
298 break;
299 case STATE_SEND_HEADERS_COMPLETE:
300 rv = DoSendHeadersComplete(rv);
301 break;
302 case STATE_READ_REQUEST_BODY:
303 CHECK_EQ(OK, rv);
304 rv = DoReadRequestBody();
305 break;
306 case STATE_READ_REQUEST_BODY_COMPLETE:
307 rv = DoReadRequestBodyComplete(rv);
308 break;
309 case STATE_SEND_BODY:
310 CHECK_EQ(OK, rv);
311 rv = DoSendBody();
312 break;
313 case STATE_SEND_BODY_COMPLETE:
314 rv = DoSendBodyComplete(rv);
315 break;
316 case STATE_OPEN:
317 CHECK_EQ(OK, rv);
318 break;
319 default:
320 NOTREACHED() << "io_state_: " << io_state_;
321 break;
322 }
323 } while (io_state_ != STATE_NONE && io_state_ != STATE_OPEN &&
324 rv != ERR_IO_PENDING);
325
326 return rv;
327 }
328
329 int QuicHttpStream::DoSendHeaders() {
330 if (!stream_)
331 return ERR_UNEXPECTED;
332
333 bool has_upload_data = request_body_stream_ != NULL;
334
335 io_state_ = STATE_SEND_HEADERS_COMPLETE;
336 int rv = stream_->WriteData(request_, !has_upload_data);
337 return rv;
338 }
339
340 int QuicHttpStream::DoSendHeadersComplete(int rv) {
341 if (rv < 0) {
342 io_state_ = STATE_NONE;
343 return rv;
344 }
345
346 io_state_ = request_body_stream_ ?
347 STATE_READ_REQUEST_BODY : STATE_OPEN;
348
349 return OK;
350 }
351
352 int QuicHttpStream::DoReadRequestBody() {
353 io_state_ = STATE_READ_REQUEST_BODY_COMPLETE;
354 return request_body_stream_->Read(raw_request_body_buf_,
355 raw_request_body_buf_->size(),
356 base::Bind(&QuicHttpStream::OnIOComplete,
357 weak_factory_.GetWeakPtr()));
358 }
359
360 int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
361 // |rv| is the result of read from the request body from the last call to
362 // DoSendBody().
363 if (rv < 0) {
364 io_state_ = STATE_NONE;
365 return rv;
366 }
367
368 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, rv);
369 if (rv == 0) { // Reached the end.
370 DCHECK(request_body_stream_->IsEOF());
371 }
372
373 io_state_ = STATE_SEND_BODY;
374 return OK;
375 }
376
377 int QuicHttpStream::DoSendBody() {
378 if (!stream_)
379 return ERR_UNEXPECTED;
380
381 CHECK(request_body_stream_);
382 CHECK(request_body_buf_);
383 const bool eof = request_body_stream_->IsEOF();
384 int len = request_body_buf_->BytesRemaining();
385 if (len > 0 || eof) {
386 base::StringPiece data(request_body_buf_->data(), len);
387 int rv = stream_->WriteData(data, eof);
388 request_body_buf_->DidConsume(rv);
389 DCHECK_NE(ERR_IO_PENDING, rv);
390 if (eof) {
391 io_state_ = STATE_OPEN;
392 return OK;
393 }
394 return rv;
395 }
396
397 io_state_ = STATE_SEND_BODY_COMPLETE;
398 return OK;
399 }
400
401 int QuicHttpStream::DoSendBodyComplete(int rv) {
402 if (rv < 0) {
403 io_state_ = STATE_NONE;
404 return rv;
405 }
406
407 io_state_ = STATE_READ_REQUEST_BODY;
408 return OK;
409 }
410
411 int QuicHttpStream::ParseResponseHeaders() {
412 int end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(),
413 read_buf_->offset(), 0);
414
415 if (end_offset == -1) {
416 return ERR_IO_PENDING;
417 }
418
419 if (!stream_)
420 return ERR_UNEXPECTED;
421
422 scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(
423 HttpUtil::AssembleRawHeaders(read_buf_->StartOfBuffer(), end_offset));
424
425 // Put the peer's IP address and port into the response.
426 IPEndPoint address = stream_->GetPeerAddress();
427 response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
428 response_info_->headers = headers;
429 response_info_->vary_data.Init(*request_info_, *response_info_->headers);
430 response_headers_received_ = true;
431
432 // Save the remaining received data.
433 int delta = read_buf_->offset() - end_offset;
434 if (delta > 0) {
435 BufferResponseBody(read_buf_->data(), delta);
436 }
437
438 return OK;
439 }
440
441 void QuicHttpStream::BufferResponseBody(const char* data, int length) {
442 IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
443 memcpy(io_buffer->data(), data, length);
444 response_body_.push_back(make_scoped_refptr(io_buffer));
445 }
446
447 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/quic_http_stream.h ('k') | net/quic/quic_http_stream_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698