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

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: Fix bugs Created 8 years, 1 month 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 {
willchan no longer on Chromium 2012/11/21 23:27:30 Would be great to clean up this method name since
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 bool had_headers = response_headers_received_;
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 rv = DoSendBody(rv);
311 break;
312 case STATE_OPEN:
313 CHECK_EQ(OK, rv);
314 break;
315 default:
316 NOTREACHED() << "io_state_: " << io_state_;
317 break;
318 }
319 } while (io_state_ != STATE_NONE && io_state_ != STATE_OPEN &&
320 rv != ERR_IO_PENDING);
321
322 return rv;
323 }
324
325 int QuicHttpStream::DoSendHeaders() {
326 if (!stream_)
327 return ERR_FAILED;
328
329 bool has_upload_data = request_body_stream_ != NULL;
330
331 io_state_ = STATE_SEND_HEADERS_COMPLETE;
332 int rv = stream_->WriteData(request_, !has_upload_data);
333 return rv;
334 }
335
336 int QuicHttpStream::DoSendHeadersComplete(int rv) {
337 if (rv < 0) {
338 io_state_ = STATE_NONE;
339 return rv;
340 }
341
342 io_state_ = request_body_stream_ ?
343 STATE_READ_REQUEST_BODY : STATE_OPEN;
344
345 return OK;
346 }
347
348 int QuicHttpStream::DoReadRequestBody() {
349 io_state_ = STATE_READ_REQUEST_BODY_COMPLETE;
350 return request_body_stream_->Read(raw_request_body_buf_,
351 raw_request_body_buf_->size(),
352 base::Bind(&QuicHttpStream::OnIOComplete,
353 weak_factory_.GetWeakPtr()));
354 }
355
356 int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
357 // |rv| is the result of read from the request body from the last call to
358 // DoSendBody().
359 if (rv < 0) {
360 io_state_ = STATE_NONE;
361 return rv;
362 }
363
364 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, rv);
365 if (rv == 0) { // Reached the end.
366 DCHECK(request_body_stream_->IsEOF());
367 }
368
369 io_state_ = STATE_SEND_BODY;
370 return OK;
371 }
372
373 int QuicHttpStream::DoSendBody(int rv) {
374 // |rv| is the number of bytes to be sent in this write.
375 if (rv < 0) {
376 io_state_ = STATE_NONE;
377 return rv;
378 }
379 if (!stream_)
380 return ERR_FAILED;
381
382 CHECK(request_body_stream_);
383 CHECK(request_body_buf_);
384 const bool eof = request_body_stream_->IsEOF();
385 int len = request_body_buf_->BytesRemaining();
386 if (len > 0 || eof) {
387 base::StringPiece data(request_body_buf_->data(), len);
388 int rv = stream_->WriteData(data, eof);
389 request_body_buf_->DidConsume(rv);
390 DCHECK_NE(ERR_IO_PENDING, rv);
391 if (eof) {
392 io_state_ = STATE_OPEN;
393 return OK;
394 }
395 return rv;
396 }
397
398 io_state_ = STATE_READ_REQUEST_BODY;
399 return OK;
400 }
401
402 int QuicHttpStream::ParseResponseHeaders() {
403 int end_offset = HttpUtil::LocateEndOfHeaders(read_buf_->StartOfBuffer(),
404 read_buf_->offset(), 0);
405
406 if (end_offset == -1) {
407 return ERR_IO_PENDING;
408 }
409
410 if (!stream_)
411 return ERR_FAILED;
412
413 scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(
414 HttpUtil::AssembleRawHeaders(read_buf_->StartOfBuffer(), end_offset));
415
416 // Put the peer's IP address and port into the response.
417 IPEndPoint address = stream_->GetPeerAddress();
418 response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
419 response_info_->headers = headers;
420 response_info_->vary_data.Init(*request_info_, *response_info_->headers);
421 response_headers_received_ = true;
422
423 // Save the remaining received data.
424 int delta = end_offset - read_buf_->offset();
425 if (delta > 0) {
426 BufferResponseBody(read_buf_->data(), delta);
427 }
428
429 return OK;
430 }
431
432 void QuicHttpStream::BufferResponseBody(const char* data, int length) {
433 IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
434 memcpy(io_buffer->data(), data, length);
435 response_body_.push_back(make_scoped_refptr(io_buffer));
436 }
437
438 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698