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

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

Powered by Google App Engine
This is Rietveld 408576698