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 together implement a state |
| 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 |