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 |