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

Side by Side Diff: content/browser/net/url_request_slow_download_job.cc

Issue 8468028: Restructure URLRequestSlowDownloadJob to avoid races. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge up to LKGR. Created 9 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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698