Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "content/browser/net/url_request_slow_download_job.h" | 5 #include "content/browser/net/url_request_slow_download_job.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 typedef std::set<URLRequestSlowDownloadJob*> JobList; | 76 typedef std::set<URLRequestSlowDownloadJob*> JobList; |
| 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 78 for (JobList::iterator it = pending_requests_.Get().begin(); it != | 78 for (JobList::iterator it = pending_requests_.Get().begin(); it != |
| 79 pending_requests_.Get().end(); ++it) { | 79 pending_requests_.Get().end(); ++it) { |
| 80 (*it)->set_should_finish_download(); | 80 (*it)->set_should_finish_download(); |
| 81 } | 81 } |
| 82 } | 82 } |
| 83 | 83 |
| 84 URLRequestSlowDownloadJob::URLRequestSlowDownloadJob(net::URLRequest* request) | 84 URLRequestSlowDownloadJob::URLRequestSlowDownloadJob(net::URLRequest* request) |
| 85 : net::URLRequestJob(request), | 85 : net::URLRequestJob(request), |
| 86 first_download_size_remaining_(kFirstDownloadSize), | 86 bytes_already_sent_(0), |
| 87 should_finish_download_(false), | 87 should_finish_download_(false), |
| 88 buffer_size_(0), | 88 buffer_size_(0), |
| 89 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 89 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
| 90 } | 90 } |
| 91 | 91 |
| 92 void URLRequestSlowDownloadJob::StartAsync() { | 92 void URLRequestSlowDownloadJob::StartAsync() { |
| 93 if (LowerCaseEqualsASCII(kFinishDownloadUrl, request_->url().spec().c_str())) | 93 if (LowerCaseEqualsASCII(kFinishDownloadUrl, request_->url().spec().c_str())) |
| 94 URLRequestSlowDownloadJob::FinishPendingRequests(); | 94 URLRequestSlowDownloadJob::FinishPendingRequests(); |
| 95 | 95 |
| 96 NotifyHeadersComplete(); | 96 NotifyHeadersComplete(); |
| 97 } | 97 } |
| 98 | 98 |
| 99 // ReadRawData and CheckDoneStatus implement together implement a state | |
|
eroman
2011/11/18 01:54:46
nit: redundant "implement".
Randy Smith (Not in Mondays)
2011/11/18 15:30:18
Done.
| |
| 100 // machine. ReadRawData may be called arbitrarily by the network stack. | |
| 101 // It responds by: | |
| 102 // * If there are bytes remaining in the first chunk, they are | |
| 103 // returned. | |
| 104 // [No bytes remaining in first chunk. ] | |
| 105 // * If should_finish_download_ is not set, it returns IO_PENDING, | |
| 106 // and starts calling CheckDoneStatus on a regular timer. | |
| 107 // [should_finish_download_ set.] | |
| 108 // * If there are bytes remaining in the second chunk, they are filled. | |
| 109 // * Otherwise, return *bytes_read = 0 to indicate end of request. | |
| 110 // CheckDoneStatus is called on a regular basis, in the specific | |
| 111 // case where we have transmitted all of the first chunk and none of the | |
| 112 // second. If should_finish_download_ becomes set, it will "complete" | |
| 113 // the ReadRawData call that spawned off the CheckDoneStatus() repeated call. | |
| 114 // | |
| 115 // FillBufferHelper is a helper function that does the actual work of figuring | |
| 116 // out where in the state machine we are and how we should fill the buffer. | |
| 117 // It returns an enum indicating the state of the read. | |
| 118 URLRequestSlowDownloadJob::ReadStatus | |
| 119 URLRequestSlowDownloadJob::FillBufferHelper( | |
| 120 net::IOBuffer* buf, int buf_size, int* bytes_written) { | |
| 121 if (bytes_already_sent_ < kFirstDownloadSize) { | |
| 122 int bytes_to_write = std::min(kFirstDownloadSize - bytes_already_sent_, | |
| 123 buf_size); | |
| 124 for (int i = 0; i < bytes_to_write; ++i) { | |
| 125 buf->data()[i] = '*'; | |
| 126 } | |
| 127 *bytes_written = bytes_to_write; | |
| 128 bytes_already_sent_ += bytes_to_write; | |
| 129 return BUFFER_FILLED; | |
| 130 } | |
| 131 | |
| 132 if (!should_finish_download_) | |
| 133 return REQUEST_BLOCKED; | |
| 134 | |
| 135 if (bytes_already_sent_ < kFirstDownloadSize + kSecondDownloadSize) { | |
| 136 int bytes_to_write = | |
| 137 std::min(kFirstDownloadSize + kSecondDownloadSize - bytes_already_sent_, | |
| 138 buf_size); | |
| 139 for (int i = 0; i < bytes_to_write; ++i) { | |
| 140 buf->data()[i] = '*'; | |
| 141 } | |
| 142 *bytes_written = bytes_to_write; | |
| 143 bytes_already_sent_ += bytes_to_write; | |
| 144 return BUFFER_FILLED; | |
| 145 } | |
| 146 | |
| 147 return REQUEST_COMPLETE; | |
| 148 } | |
| 149 | |
| 99 bool URLRequestSlowDownloadJob::ReadRawData(net::IOBuffer* buf, int buf_size, | 150 bool URLRequestSlowDownloadJob::ReadRawData(net::IOBuffer* buf, int buf_size, |
| 100 int *bytes_read) { | 151 int* bytes_read) { |
| 101 if (LowerCaseEqualsASCII(kFinishDownloadUrl, | 152 if (LowerCaseEqualsASCII(kFinishDownloadUrl, |
| 102 request_->url().spec().c_str())) { | 153 request_->url().spec().c_str())) { |
| 154 VLOG(10) << __FUNCTION__ << " called w/ kFinishDownloadUrl."; | |
| 103 *bytes_read = 0; | 155 *bytes_read = 0; |
| 104 return true; | 156 return true; |
| 105 } | 157 } |
| 106 | 158 |
| 107 if (first_download_size_remaining_ > 0) { | 159 VLOG(10) << __FUNCTION__ << " called at position " |
| 108 int send_size = std::min(first_download_size_remaining_, buf_size); | 160 << bytes_already_sent_ << " in the stream."; |
| 109 for (int i = 0; i < send_size; ++i) { | 161 ReadStatus status = FillBufferHelper(buf, buf_size, bytes_read); |
| 110 buf->data()[i] = '*'; | 162 switch (status) { |
| 111 } | 163 case BUFFER_FILLED: |
| 112 *bytes_read = send_size; | 164 return true; |
| 113 first_download_size_remaining_ -= send_size; | 165 case REQUEST_BLOCKED: |
| 114 | 166 buffer_ = buf; |
| 115 DCHECK(!is_done()); | 167 buffer_size_ = buf_size; |
| 116 return true; | 168 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); |
| 169 MessageLoop::current()->PostDelayedTask( | |
| 170 FROM_HERE, | |
| 171 base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus, | |
| 172 weak_factory_.GetWeakPtr()), | |
| 173 100); | |
| 174 return false; | |
| 175 case REQUEST_COMPLETE: | |
| 176 *bytes_read = 0; | |
| 177 return true; | |
| 117 } | 178 } |
| 118 | 179 NOTREACHED(); |
| 119 if (should_finish_download_) { | 180 return true; |
| 120 *bytes_read = 0; | |
| 121 return true; | |
| 122 } | |
| 123 | |
| 124 // If we make it here, the first chunk has been sent and we need to wait | |
| 125 // until a request is made for kFinishDownloadUrl. | |
| 126 buffer_ = buf; | |
| 127 buffer_size_ = buf_size; | |
| 128 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | |
| 129 MessageLoop::current()->PostDelayedTask( | |
| 130 FROM_HERE, | |
| 131 base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus, | |
| 132 weak_factory_.GetWeakPtr()), | |
| 133 100); | |
| 134 | |
| 135 // Return false to signal there is pending data. | |
| 136 return false; | |
| 137 } | 181 } |
| 138 | 182 |
| 139 void URLRequestSlowDownloadJob::CheckDoneStatus() { | 183 void URLRequestSlowDownloadJob::CheckDoneStatus() { |
| 140 if (should_finish_download_) { | 184 if (should_finish_download_) { |
| 185 VLOG(10) << __FUNCTION__ << " called w/ should_finish_download_ set."; | |
| 141 DCHECK(NULL != buffer_); | 186 DCHECK(NULL != buffer_); |
| 142 // Send the rest of the data. | 187 int bytes_written = 0; |
| 143 DCHECK_GT(buffer_size_, kSecondDownloadSize); | 188 ReadStatus status = FillBufferHelper(buffer_, buffer_size_, &bytes_written); |
| 144 for (int i = 0; i < kSecondDownloadSize; ++i) { | 189 DCHECK_EQ(BUFFER_FILLED, status); |
| 145 buffer_->data()[i] = '*'; | |
| 146 } | |
| 147 SetStatus(net::URLRequestStatus()); | 190 SetStatus(net::URLRequestStatus()); |
| 148 NotifyReadComplete(kSecondDownloadSize); // Deletes this. | 191 NotifyReadComplete(bytes_written); |
| 149 } else { | 192 } else { |
| 150 MessageLoop::current()->PostDelayedTask( | 193 MessageLoop::current()->PostDelayedTask( |
| 151 FROM_HERE, | 194 FROM_HERE, |
| 152 base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus, | 195 base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus, |
| 153 weak_factory_.GetWeakPtr()), | 196 weak_factory_.GetWeakPtr()), |
| 154 100); | 197 100); |
| 155 } | 198 } |
| 156 } | 199 } |
| 157 | 200 |
| 158 // Public virtual version. | 201 // Public virtual version. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 // ParseRawHeaders expects \0 to end each header line. | 235 // ParseRawHeaders expects \0 to end each header line. |
| 193 ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1)); | 236 ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1)); |
| 194 info->headers = new net::HttpResponseHeaders(raw_headers); | 237 info->headers = new net::HttpResponseHeaders(raw_headers); |
| 195 } | 238 } |
| 196 | 239 |
| 197 bool URLRequestSlowDownloadJob::GetMimeType(std::string* mime_type) const { | 240 bool URLRequestSlowDownloadJob::GetMimeType(std::string* mime_type) const { |
| 198 net::HttpResponseInfo info; | 241 net::HttpResponseInfo info; |
| 199 GetResponseInfoConst(&info); | 242 GetResponseInfoConst(&info); |
| 200 return info.headers && info.headers->GetMimeType(mime_type); | 243 return info.headers && info.headers->GetMimeType(mime_type); |
| 201 } | 244 } |
| OLD | NEW |