OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/spdy/spdy_http_stream.h" | 5 #include "net/spdy/spdy_http_stream.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <list> | 8 #include <list> |
9 #include <string> | 9 #include <string> |
10 | 10 |
(...skipping 18 matching lines...) Expand all Loading... | |
29 bool direct) | 29 bool direct) |
30 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | 30 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
31 stream_(NULL), | 31 stream_(NULL), |
32 spdy_session_(spdy_session), | 32 spdy_session_(spdy_session), |
33 response_info_(NULL), | 33 response_info_(NULL), |
34 download_finished_(false), | 34 download_finished_(false), |
35 response_headers_received_(false), | 35 response_headers_received_(false), |
36 user_buffer_len_(0), | 36 user_buffer_len_(0), |
37 buffered_read_callback_pending_(false), | 37 buffered_read_callback_pending_(false), |
38 more_read_data_pending_(false), | 38 more_read_data_pending_(false), |
39 direct_(direct) { } | 39 direct_(direct), |
40 waiting_for_chunk_(false) { } | |
40 | 41 |
41 void SpdyHttpStream::InitializeWithExistingStream(SpdyStream* spdy_stream) { | 42 void SpdyHttpStream::InitializeWithExistingStream(SpdyStream* spdy_stream) { |
42 stream_ = spdy_stream; | 43 stream_ = spdy_stream; |
43 stream_->SetDelegate(this); | 44 stream_->SetDelegate(this); |
44 response_headers_received_ = true; | 45 response_headers_received_ = true; |
45 } | 46 } |
46 | 47 |
47 SpdyHttpStream::~SpdyHttpStream() { | 48 SpdyHttpStream::~SpdyHttpStream() { |
49 if (request_body_stream_ != NULL) | |
50 request_body_stream_->set_chunk_callback(NULL); | |
48 if (stream_) | 51 if (stream_) |
49 stream_->DetachDelegate(); | 52 stream_->DetachDelegate(); |
50 } | 53 } |
51 | 54 |
52 int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info, | 55 int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info, |
53 const BoundNetLog& stream_net_log, | 56 const BoundNetLog& stream_net_log, |
54 const CompletionCallback& callback) { | 57 const CompletionCallback& callback) { |
55 DCHECK(!stream_.get()); | 58 DCHECK(!stream_.get()); |
56 if (spdy_session_->IsClosed()) | 59 if (spdy_session_->IsClosed()) |
57 return ERR_CONNECTION_CLOSED; | 60 return ERR_CONNECTION_CLOSED; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 | 178 |
176 void SpdyHttpStream::SetConnectionReused() { | 179 void SpdyHttpStream::SetConnectionReused() { |
177 // SPDY doesn't need an indicator here. | 180 // SPDY doesn't need an indicator here. |
178 } | 181 } |
179 | 182 |
180 bool SpdyHttpStream::IsConnectionReusable() const { | 183 bool SpdyHttpStream::IsConnectionReusable() const { |
181 // SPDY streams aren't considered reusable. | 184 // SPDY streams aren't considered reusable. |
182 return false; | 185 return false; |
183 } | 186 } |
184 | 187 |
185 void SpdyHttpStream::set_chunk_callback(ChunkCallback* callback) { | |
186 if (request_body_stream_ != NULL) | |
187 request_body_stream_->set_chunk_callback(callback); | |
188 } | |
189 | |
190 int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers, | 188 int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers, |
191 scoped_ptr<UploadDataStream> request_body, | 189 scoped_ptr<UploadDataStream> request_body, |
192 HttpResponseInfo* response, | 190 HttpResponseInfo* response, |
193 const CompletionCallback& callback) { | 191 const CompletionCallback& callback) { |
194 base::Time request_time = base::Time::Now(); | 192 base::Time request_time = base::Time::Now(); |
195 CHECK(stream_.get()); | 193 CHECK(stream_.get()); |
196 | 194 |
197 stream_->SetDelegate(this); | 195 stream_->SetDelegate(this); |
198 | 196 |
199 linked_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); | 197 linked_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); |
200 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, | 198 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, |
201 headers.get(), stream_->GetProtocolVersion(), | 199 headers.get(), stream_->GetProtocolVersion(), |
202 direct_); | 200 direct_); |
203 stream_->set_spdy_headers(headers); | 201 stream_->set_spdy_headers(headers); |
204 | 202 |
205 stream_->SetRequestTime(request_time); | 203 stream_->SetRequestTime(request_time); |
206 // This should only get called in the case of a request occurring | 204 // This should only get called in the case of a request occurring |
207 // during server push that has already begun but hasn't finished, | 205 // during server push that has already begun but hasn't finished, |
208 // so we set the response's request time to be the actual one | 206 // so we set the response's request time to be the actual one |
209 if (response_info_) | 207 if (response_info_) |
210 response_info_->request_time = request_time; | 208 response_info_->request_time = request_time; |
211 | 209 |
212 CHECK(!request_body_stream_.get()); | 210 CHECK(!request_body_stream_.get()); |
213 if (request_body != NULL) { | 211 if (request_body != NULL) { |
214 if (request_body->size() || request_body->is_chunked()) { | 212 if (request_body->size() || request_body->is_chunked()) { |
215 request_body_stream_.reset(request_body.release()); | 213 request_body_stream_.reset(request_body.release()); |
214 request_body_stream_->set_chunk_callback(this); | |
216 // Use kMaxSpdyFrameChunkSize as the buffer size, since the request | 215 // Use kMaxSpdyFrameChunkSize as the buffer size, since the request |
217 // body data is written with this size at a time. | 216 // body data is written with this size at a time. |
218 raw_request_body_buf_ = new IOBufferWithSize(kMaxSpdyFrameChunkSize); | 217 raw_request_body_buf_ = new IOBufferWithSize(kMaxSpdyFrameChunkSize); |
219 // The request body buffer is empty at first. | 218 // The request body buffer is empty at first. |
220 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, 0); | 219 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, 0); |
221 } | 220 } |
222 } | 221 } |
223 | 222 |
224 CHECK(!callback.is_null()); | 223 CHECK(!callback.is_null()); |
225 CHECK(!stream_->cancelled()); | 224 CHECK(!stream_->cancelled()); |
(...skipping 10 matching lines...) Expand all Loading... | |
236 // | 235 // |
237 // a) A client initiated request. In this case, |response_info_| should be | 236 // a) A client initiated request. In this case, |response_info_| should be |
238 // NULL to start with. | 237 // NULL to start with. |
239 // b) A client request which matches a response that the server has already | 238 // b) A client request which matches a response that the server has already |
240 // pushed. | 239 // pushed. |
241 if (push_response_info_.get()) { | 240 if (push_response_info_.get()) { |
242 *response = *(push_response_info_.get()); | 241 *response = *(push_response_info_.get()); |
243 push_response_info_.reset(); | 242 push_response_info_.reset(); |
244 } | 243 } |
245 else | 244 else |
246 DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_); | 245 DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_); |
Ryan Sleevi
2012/07/05 06:52:06
style nit: this should be
} else {
DCHECK_EQ(..
ramant (doing other things)
2012/07/06 22:55:42
Done.
| |
247 | 246 |
248 response_info_ = response; | 247 response_info_ = response; |
249 | 248 |
250 // Put the peer's IP address and port into the response. | 249 // Put the peer's IP address and port into the response. |
251 IPEndPoint address; | 250 IPEndPoint address; |
252 int result = stream_->GetPeerAddress(&address); | 251 int result = stream_->GetPeerAddress(&address); |
253 if (result != OK) | 252 if (result != OK) |
254 return result; | 253 return result; |
255 response_info_->socket_address = HostPortPair::FromIPEndPoint(address); | 254 response_info_->socket_address = HostPortPair::FromIPEndPoint(address); |
256 | 255 |
257 bool has_upload_data = request_body_stream_.get() != NULL; | 256 bool has_upload_data = request_body_stream_.get() != NULL; |
258 result = stream_->SendRequest(has_upload_data); | 257 result = stream_->SendRequest(has_upload_data); |
259 if (result == ERR_IO_PENDING) { | 258 if (result == ERR_IO_PENDING) { |
260 CHECK(callback_.is_null()); | 259 CHECK(callback_.is_null()); |
261 callback_ = callback; | 260 callback_ = callback; |
262 } | 261 } |
263 return result; | 262 return result; |
264 } | 263 } |
265 | 264 |
266 void SpdyHttpStream::Cancel() { | 265 void SpdyHttpStream::Cancel() { |
267 if (spdy_session_) | 266 if (spdy_session_) |
268 spdy_session_->CancelPendingCreateStreams(&stream_); | 267 spdy_session_->CancelPendingCreateStreams(&stream_); |
269 callback_.Reset(); | 268 callback_.Reset(); |
270 if (stream_) | 269 if (stream_) |
271 stream_->Cancel(); | 270 stream_->Cancel(); |
272 } | 271 } |
273 | 272 |
273 int SpdyHttpStream::SendData() { | |
274 CHECK(request_body_stream_.get()); | |
275 CHECK_EQ(0, request_body_buf_->BytesRemaining()); | |
276 | |
277 // Read the data from the request body stream. | |
278 const int bytes_read = request_body_stream_->Read( | |
279 raw_request_body_buf_, raw_request_body_buf_->size()); | |
280 DCHECK(!waiting_for_chunk_ || bytes_read != ERR_IO_PENDING); | |
281 | |
282 if (request_body_stream_->is_chunked() && bytes_read == ERR_IO_PENDING) { | |
283 waiting_for_chunk_ = true; | |
284 return ERR_IO_PENDING; | |
285 } | |
286 | |
287 waiting_for_chunk_ = false; | |
288 | |
289 // ERR_IO_PENDING with chunked encoding is the only possible error. | |
290 DCHECK_GE(bytes_read, 0); | |
291 | |
292 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, | |
293 bytes_read); | |
294 | |
295 const bool eof = request_body_stream_->IsEOF(); | |
296 return stream_->WriteStreamData( | |
297 request_body_buf_, | |
298 request_body_buf_->BytesRemaining(), | |
299 eof ? DATA_FLAG_FIN : DATA_FLAG_NONE); | |
300 } | |
301 | |
274 bool SpdyHttpStream::OnSendHeadersComplete(int status) { | 302 bool SpdyHttpStream::OnSendHeadersComplete(int status) { |
275 if (!callback_.is_null()) | 303 if (!callback_.is_null()) |
276 DoCallback(status); | 304 DoCallback(status); |
277 return request_body_stream_.get() == NULL; | 305 return request_body_stream_.get() == NULL; |
278 } | 306 } |
279 | 307 |
280 int SpdyHttpStream::OnSendBody() { | 308 int SpdyHttpStream::OnSendBody() { |
281 CHECK(request_body_stream_.get()); | 309 CHECK(request_body_stream_.get()); |
310 const bool eof = request_body_stream_->IsEOF(); | |
311 if (request_body_buf_->BytesRemaining() > 0) { | |
312 return stream_->WriteStreamData( | |
313 request_body_buf_, | |
314 request_body_buf_->BytesRemaining(), | |
315 eof ? DATA_FLAG_FIN : DATA_FLAG_NONE); | |
316 } | |
282 | 317 |
283 // TODO(satorux): Clean up the logic here. This behavior is weird. Reading | 318 // The entire body data has been sent. |
284 // of upload data should happen in OnSendBody(). crbug.com/113107. | 319 if (eof) |
285 // | |
286 // Nothing to send. This happens when OnSendBody() is first called. | |
287 // A read of the upload data stream is initiated in OnSendBodyComplete(). | |
288 if (request_body_buf_->BytesRemaining() == 0) | |
289 return OK; | 320 return OK; |
290 | 321 |
291 const bool eof = request_body_stream_->IsEOF(); | 322 return SendData(); |
292 return stream_->WriteStreamData( | |
293 request_body_buf_, | |
294 request_body_buf_->BytesRemaining(), | |
295 eof ? DATA_FLAG_FIN : DATA_FLAG_NONE); | |
296 } | 323 } |
297 | 324 |
298 int SpdyHttpStream::OnSendBodyComplete(int status, bool* eof) { | 325 int SpdyHttpStream::OnSendBodyComplete(int status, bool* eof) { |
299 // |status| is the number of bytes written to the SPDY stream. | 326 // |status| is the number of bytes written to the SPDY stream. |
300 CHECK(request_body_stream_.get()); | 327 CHECK(request_body_stream_.get()); |
301 *eof = false; | 328 *eof = false; |
302 | 329 |
303 if (status > 0) { | 330 if (status > 0) { |
304 request_body_buf_->DidConsume(status); | 331 request_body_buf_->DidConsume(status); |
305 if (request_body_buf_->BytesRemaining()) { | 332 if (request_body_buf_->BytesRemaining()) { |
306 // Go back to OnSendBody() to send the remaining data. | 333 // Go back to OnSendBody() to send the remaining data. |
307 return OK; | 334 return OK; |
308 } | 335 } |
309 } | 336 } |
310 | 337 |
311 // Check if the entire body data has been sent. | 338 // Check if the entire body data has been sent. |
312 *eof = (request_body_stream_->IsEOF() && | 339 *eof = (request_body_stream_->IsEOF() && |
313 !request_body_buf_->BytesRemaining()); | 340 !request_body_buf_->BytesRemaining()); |
314 if (*eof) | |
315 return OK; | |
316 | |
317 // Read the data from the request body stream. | |
318 const int bytes_read = request_body_stream_->Read( | |
319 raw_request_body_buf_, raw_request_body_buf_->size()); | |
320 if (request_body_stream_->is_chunked() && bytes_read == ERR_IO_PENDING) | |
321 return ERR_IO_PENDING; | |
322 // ERR_IO_PENDING with chunked encoding is the only possible error. | |
323 DCHECK_GE(bytes_read, 0); | |
324 | |
325 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, | |
326 bytes_read); | |
327 return OK; | 341 return OK; |
328 } | 342 } |
329 | 343 |
330 int SpdyHttpStream::OnResponseReceived(const SpdyHeaderBlock& response, | 344 int SpdyHttpStream::OnResponseReceived(const SpdyHeaderBlock& response, |
331 base::Time response_time, | 345 base::Time response_time, |
332 int status) { | 346 int status) { |
333 if (!response_info_) { | 347 if (!response_info_) { |
334 DCHECK(stream_->pushed()); | 348 DCHECK(stream_->pushed()); |
335 push_response_info_.reset(new HttpResponseInfo); | 349 push_response_info_.reset(new HttpResponseInfo); |
336 response_info_ = push_response_info_.get(); | 350 response_info_ = push_response_info_.get(); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
399 } | 413 } |
400 | 414 |
401 void SpdyHttpStream::OnDataSent(int length) { | 415 void SpdyHttpStream::OnDataSent(int length) { |
402 // For HTTP streams, no data is sent from the client while in the OPEN state, | 416 // For HTTP streams, no data is sent from the client while in the OPEN state, |
403 // so it is never called. | 417 // so it is never called. |
404 NOTREACHED(); | 418 NOTREACHED(); |
405 } | 419 } |
406 | 420 |
407 void SpdyHttpStream::OnClose(int status) { | 421 void SpdyHttpStream::OnClose(int status) { |
408 bool invoked_callback = false; | 422 bool invoked_callback = false; |
423 if (request_body_stream_ != NULL) | |
424 request_body_stream_->set_chunk_callback(NULL); | |
Ryan Sleevi
2012/07/05 06:52:06
Does Cancel also need to be updated?
Not sure the
ramant (doing other things)
2012/07/06 22:55:42
No need. Cancel calls reset spdy stream, which del
| |
409 if (status == net::OK) { | 425 if (status == net::OK) { |
410 // We need to complete any pending buffered read now. | 426 // We need to complete any pending buffered read now. |
411 invoked_callback = DoBufferedReadCallback(); | 427 invoked_callback = DoBufferedReadCallback(); |
412 } | 428 } |
413 if (!invoked_callback && !callback_.is_null()) | 429 if (!invoked_callback && !callback_.is_null()) |
414 DoCallback(status); | 430 DoCallback(status); |
415 } | 431 } |
416 | 432 |
433 void SpdyHttpStream::OnChunkAvailable() { | |
434 if (!waiting_for_chunk_) | |
435 return; | |
436 DCHECK(request_body_stream_->is_chunked()); | |
437 SendData(); | |
438 } | |
439 | |
417 void SpdyHttpStream::ScheduleBufferedReadCallback() { | 440 void SpdyHttpStream::ScheduleBufferedReadCallback() { |
418 // If there is already a scheduled DoBufferedReadCallback, don't issue | 441 // If there is already a scheduled DoBufferedReadCallback, don't issue |
419 // another one. Mark that we have received more data and return. | 442 // another one. Mark that we have received more data and return. |
420 if (buffered_read_callback_pending_) { | 443 if (buffered_read_callback_pending_) { |
421 more_read_data_pending_ = true; | 444 more_read_data_pending_ = true; |
422 return; | 445 return; |
423 } | 446 } |
424 | 447 |
425 more_read_data_pending_ = false; | 448 more_read_data_pending_ = false; |
426 buffered_read_callback_pending_ = true; | 449 buffered_read_callback_pending_ = true; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
504 bool SpdyHttpStream::IsSpdyHttpStream() const { | 527 bool SpdyHttpStream::IsSpdyHttpStream() const { |
505 return true; | 528 return true; |
506 } | 529 } |
507 | 530 |
508 void SpdyHttpStream::Drain(HttpNetworkSession* session) { | 531 void SpdyHttpStream::Drain(HttpNetworkSession* session) { |
509 Close(false); | 532 Close(false); |
510 delete this; | 533 delete this; |
511 } | 534 } |
512 | 535 |
513 } // namespace net | 536 } // namespace net |
OLD | NEW |