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

Side by Side Diff: pdf/url_loader_wrapper_impl.cc

Issue 2349753003: Improve linearized pdf load/show time. (Closed)
Patch Set: remove useless code. Created 4 years, 3 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
« pdf/timer.h ('K') | « pdf/url_loader_wrapper_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "pdf/url_loader_wrapper_impl.h"
6
7 #include "base/strings/string_util.h"
8 #include "net/http/http_util.h"
9 #include "pdf/timer.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/cpp/logging.h"
12 #include "ppapi/cpp/url_request_info.h"
13 #include "ppapi/cpp/url_response_info.h"
14
15 namespace chrome_pdf {
16 namespace {
17 // We should read with delay to prevent block UI thread, and reduce CPU usage.
18 const int kReadDelayMs = 2;
19
20 pp::URLRequestInfo MakeRangeRequest(pp::Instance* plugin_instance,
21 const std::string& url,
22 const std::string& referrer_url,
23 uint32_t position,
24 uint32_t size) {
25 pp::URLRequestInfo request(plugin_instance);
26 request.SetURL(url);
27 request.SetMethod("GET");
28 request.SetFollowRedirects(true);
29 request.SetCustomReferrerURL(referrer_url);
30
31 const size_t kBufSize = 100;
32 char buf[kBufSize];
33 // According to rfc2616, byte range specifies position of the first and last
34 // bytes in the requested range inclusively. Therefore we should subtract 1
35 // from the position + size, to get index of the last byte that needs to be
36 // downloaded.
37 base::snprintf(buf, kBufSize, "Range: bytes=%d-%d", position,
Lei Zhang 2016/10/05 07:18:08 Use base::StringPrintf() and don't worry about a f
snake 2016/10/05 14:14:10 Done.
38 position + size - 1);
39 pp::Var header(buf);
40 request.SetHeaders(header);
41
42 return request;
43 }
44
45 bool GetByteRangeFromStr(const std::string& content_range_str,
46 int* start,
47 int* end) {
48 std::string range = content_range_str;
49 if (base::StartsWith(range, "bytes", base::CompareCase::INSENSITIVE_ASCII)) {
50 range = range.substr(strlen("bytes"));
51 std::string::size_type pos = range.find('-');
52 std::string range_end;
53 if (pos != std::string::npos)
54 range_end = range.substr(pos + 1);
55 base::TrimWhitespaceASCII(range, base::TRIM_LEADING, &range);
56 base::TrimWhitespaceASCII(range_end, base::TRIM_LEADING, &range_end);
57 *start = atoi(range.c_str());
58 *end = atoi(range_end.c_str());
59 return true;
60 }
61 return false;
62 }
63
64 // If the headers have a byte-range response, writes the start and end
65 // positions and returns true if at least the start position was parsed.
66 // The end position will be set to 0 if it was not found or parsed from the
67 // response.
68 // Returns false if not even a start position could be parsed.
69 bool GetByteRangeFromHeaders(const std::string& headers, int* start, int* end) {
70 net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
71 while (it.GetNext()) {
72 if (base::LowerCaseEqualsASCII(it.name(), "content-range")) {
73 if (GetByteRangeFromStr(it.values().c_str(), start, end))
74 return true;
75 }
76 }
77 return false;
78 }
79 } // namespace
80
81 class URLLoaderWrapperImpl::ReadStarter : public Timer {
82 public:
83 explicit ReadStarter(URLLoaderWrapperImpl* owner)
84 : Timer(kReadDelayMs), owner_(owner) {}
85 ~ReadStarter() override {}
86
87 // Timer overrides:
88 void OnTimer() override { owner_->ReadResponseBodyImpl(); }
89
90 private:
91 URLLoaderWrapperImpl* owner_;
92 };
93
94 URLLoaderWrapperImpl::URLLoaderWrapperImpl(pp::Instance* plugin_instance,
95 const pp::URLLoader& url_loader)
96 : plugin_instance_(plugin_instance),
97 url_loader_(url_loader),
98 callback_factory_(this) {
99 SetHeadersFromLoader();
100 }
101
102 URLLoaderWrapperImpl::~URLLoaderWrapperImpl() {
103 Close();
104 }
105
106 int URLLoaderWrapperImpl::GetContentLength() const {
107 return content_length_;
108 }
109
110 bool URLLoaderWrapperImpl::IsAcceptRangesBytes() const {
111 return accept_ranges_bytes_;
112 }
113
114 bool URLLoaderWrapperImpl::IsContentEncoded() const {
115 return content_encoded_;
116 }
117
118 std::string URLLoaderWrapperImpl::GetContentType() const {
119 return content_type_;
120 }
121 std::string URLLoaderWrapperImpl::GetContentDisposition() const {
122 return content_disposition_;
123 }
124
125 int URLLoaderWrapperImpl::GetStatusCode() const {
126 return url_loader_.GetResponseInfo().GetStatusCode();
127 }
128
129 bool URLLoaderWrapperImpl::IsMultipart() const {
130 return is_multipart_;
131 }
132
133 bool URLLoaderWrapperImpl::GetByteRange(int* start, int* end) const {
134 PP_DCHECK(start);
135 PP_DCHECK(end);
136 *start = byte_range_.start();
137 *end = byte_range_.end();
138 return byte_range_.IsValid();
139 }
140
141 bool URLLoaderWrapperImpl::GetDownloadProgress(
142 int64_t* bytes_received,
143 int64_t* total_bytes_to_be_received) const {
144 return url_loader_.GetDownloadProgress(bytes_received,
145 total_bytes_to_be_received);
146 }
147
148 void URLLoaderWrapperImpl::Close() {
149 url_loader_.Close();
150 read_starter_.reset();
151 }
152
153 void URLLoaderWrapperImpl::OpenRange(const std::string& url,
154 const std::string& referrer_url,
155 uint32_t position,
156 uint32_t size,
157 const pp::CompletionCallback& cc) {
158 did_open_callback_ = cc;
159 pp::CompletionCallback callback =
160 callback_factory_.NewCallback(&URLLoaderWrapperImpl::DidOpen);
161 int rv = url_loader_.Open(
162 MakeRangeRequest(plugin_instance_, url, referrer_url, position, size),
163 callback);
164 if (rv != PP_OK_COMPLETIONPENDING)
165 callback.Run(rv);
166 }
167
168 void URLLoaderWrapperImpl::ReadResponseBody(char* buffer,
169 int buffer_size,
170 const pp::CompletionCallback& cc) {
171 did_read_callback_ = cc;
172 buffer_ = buffer;
173 buffer_size_ = buffer_size;
174 read_starter_.reset(new ReadStarter(this));
175 }
176
177 void URLLoaderWrapperImpl::ReadResponseBodyImpl() {
178 read_starter_.reset();
179 pp::CompletionCallback callback =
180 callback_factory_.NewCallback(&URLLoaderWrapperImpl::DidRead);
181 int rv = url_loader_.ReadResponseBody(buffer_, buffer_size_, callback);
182 if (rv != PP_OK_COMPLETIONPENDING) {
183 callback.Run(rv);
184 }
185 }
186
187 void URLLoaderWrapperImpl::SetResponseHeaders(
188 const std::string& response_headers) {
189 response_headers_ = response_headers;
190 ParseHeaders();
191 }
192
193 void URLLoaderWrapperImpl::ParseHeaders() {
194 content_length_ = -1;
195 accept_ranges_bytes_ = false;
196 content_encoded_ = false;
197 content_type_.clear();
198 content_disposition_.clear();
199 multipart_boundary_.clear();
200 byte_range_ = gfx::Range::InvalidRange();
201 is_multipart_ = false;
202
203 if (response_headers_.empty())
204 return;
205 net::HttpUtil::HeadersIterator it(response_headers_.begin(),
206 response_headers_.end(), "\n");
207 while (it.GetNext()) {
208 if (base::LowerCaseEqualsASCII(it.name(), "content-length")) {
209 content_length_ = atoi(it.values().c_str());
210 } else if (base::LowerCaseEqualsASCII(it.name(), "accept-ranges")) {
211 accept_ranges_bytes_ = base::LowerCaseEqualsASCII(it.values(), "bytes");
212 } else if (base::LowerCaseEqualsASCII(it.name(), "content-encoding")) {
213 content_encoded_ = true;
214 } else if (base::LowerCaseEqualsASCII(it.name(), "content-type")) {
215 content_type_ = it.values();
216 size_t semi_colon_pos = content_type_.find(';');
217 if (semi_colon_pos != std::string::npos) {
218 content_type_ = content_type_.substr(0, semi_colon_pos);
219 }
220 base::TrimWhitespaceASCII(content_type_, base::TRIM_ALL, &content_type_);
221 // multipart boundary.
222 std::string type = base::ToLowerASCII(it.values());
223 if (base::StartsWith(type, "multipart/", base::CompareCase::SENSITIVE)) {
224 const char* boundary = strstr(type.c_str(), "boundary=");
225 PP_DCHECK(boundary);
226 if (boundary) {
227 multipart_boundary_ = std::string(boundary + 9);
228 is_multipart_ = !multipart_boundary_.empty();
229 }
230 }
231 } else if (base::LowerCaseEqualsASCII(it.name(), "content-disposition")) {
232 content_disposition_ = it.values();
233 } else if (base::LowerCaseEqualsASCII(it.name(), "content-range")) {
234 int start = 0;
235 int end = 0;
236 if (GetByteRangeFromStr(it.values().c_str(), &start, &end)) {
237 byte_range_ = gfx::Range(start, end);
238 }
239 }
240 }
241 }
242
243 void URLLoaderWrapperImpl::DidOpen(int32_t result) {
244 SetHeadersFromLoader();
245 did_open_callback_.Run(result);
246 }
247
248 void URLLoaderWrapperImpl::DidRead(int32_t result) {
249 if (result > 0) {
250 char* start = buffer_;
251 size_t length = result;
252 if (!multi_part_processed_ && is_multipart_ && result > 2) {
253 multi_part_processed_ = true;
254 for (int i = 2; i < result; ++i) {
255 if ((buffer_[i - 1] == '\n' && buffer_[i - 2] == '\n') ||
256 (i >= 4 && buffer_[i - 1] == '\n' && buffer_[i - 2] == '\r' &&
257 buffer_[i - 3] == '\n' && buffer_[i - 4] == '\r')) {
258 int start_pos, end_pos;
259 if (GetByteRangeFromHeaders(std::string(buffer_, i), &start_pos,
260 &end_pos)) {
261 byte_range_ = gfx::Range(start_pos, end_pos);
262 start += i;
263 length -= i;
264 }
265 break;
266 }
267 }
268 result = length;
269 if (result == 0) {
270 return;
271 }
272 PP_DCHECK(result > 0);
273 memmove(buffer_, start, result);
274 }
275 }
276 did_read_callback_.Run(result);
277 // Reset this flag so we don't look inside the buffer in future calls of
278 // DidRead for this response. Note that this code DOES NOT handle multi-
279 // part responses with more than one part (we don't issue them at the
280 // moment, so they shouldn't arrive).
281 is_multipart_ = false;
282 }
283
284 void URLLoaderWrapperImpl::SetHeadersFromLoader() {
285 pp::URLResponseInfo response = url_loader_.GetResponseInfo();
286 pp::Var headers_var = response.GetHeaders();
287
288 if (headers_var.is_string()) {
289 SetResponseHeaders(headers_var.AsString());
290 } else {
291 SetResponseHeaders("");
292 }
293 }
294
295 } // namespace chrome_pdf
OLDNEW
« pdf/timer.h ('K') | « pdf/url_loader_wrapper_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698