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

Side by Side Diff: net/spdy/spdy_http_stream.cc

Issue 10689034: SPDY - chunked upload - speech recognition doesn't work with SPDY/3 (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 5 months 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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698