| 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()); |
| 226 CHECK(response); | 225 CHECK(response); |
| 227 | 226 |
| 228 if (!stream_->pushed() && stream_->closed()) { | 227 if (!stream_->pushed() && stream_->closed()) { |
| 229 if (stream_->response_status() == OK) | 228 if (stream_->response_status() == OK) |
| 230 return ERR_FAILED; | 229 return ERR_FAILED; |
| 231 else | 230 else |
| 232 return stream_->response_status(); | 231 return stream_->response_status(); |
| 233 } | 232 } |
| 234 | 233 |
| 235 // SendRequest can be called in two cases. | 234 // SendRequest can be called in two cases. |
| 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(); |
| 243 } else { |
| 244 DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_); |
| 244 } | 245 } |
| 245 else | |
| 246 DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_); | |
| 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); |
| 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 |