OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/net/url_request_slow_download_job.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/message_loop.h" | |
9 #include "base/stringprintf.h" | |
10 #include "base/string_util.h" | |
11 #include "googleurl/src/gurl.h" | |
12 #include "net/base/io_buffer.h" | |
13 #include "net/http/http_response_headers.h" | |
14 #include "net/url_request/url_request.h" | |
15 #include "net/url_request/url_request_filter.h" | |
16 | |
17 const int kFirstDownloadSize = 1024 * 35; | |
18 const int kSecondDownloadSize = 1024 * 10; | |
19 | |
20 const char URLRequestSlowDownloadJob::kUnknownSizeUrl[] = | |
21 "http://url.handled.by.slow.download/download-unknown-size"; | |
22 const char URLRequestSlowDownloadJob::kKnownSizeUrl[] = | |
23 "http://url.handled.by.slow.download/download-known-size"; | |
24 const char URLRequestSlowDownloadJob::kFinishDownloadUrl[] = | |
25 "http://url.handled.by.slow.download/download-finish"; | |
26 | |
27 std::vector<URLRequestSlowDownloadJob*> | |
28 URLRequestSlowDownloadJob::kPendingRequests; | |
29 | |
30 void URLRequestSlowDownloadJob::Start() { | |
31 MessageLoop::current()->PostTask( | |
32 FROM_HERE, | |
33 method_factory_.NewRunnableMethod( | |
34 &URLRequestSlowDownloadJob::StartAsync)); | |
35 } | |
36 | |
37 // static | |
38 void URLRequestSlowDownloadJob::AddUrlHandler() { | |
39 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); | |
40 filter->AddUrlHandler(GURL(kUnknownSizeUrl), | |
41 &URLRequestSlowDownloadJob::Factory); | |
42 filter->AddUrlHandler(GURL(kKnownSizeUrl), | |
43 &URLRequestSlowDownloadJob::Factory); | |
44 filter->AddUrlHandler(GURL(kFinishDownloadUrl), | |
45 &URLRequestSlowDownloadJob::Factory); | |
46 } | |
47 | |
48 /*static */ | |
49 net::URLRequestJob* URLRequestSlowDownloadJob::Factory( | |
50 net::URLRequest* request, | |
51 const std::string& scheme) { | |
52 URLRequestSlowDownloadJob* job = new URLRequestSlowDownloadJob(request); | |
53 if (request->url().spec() != kFinishDownloadUrl) | |
54 URLRequestSlowDownloadJob::kPendingRequests.push_back(job); | |
55 return job; | |
56 } | |
57 | |
58 /* static */ | |
59 void URLRequestSlowDownloadJob::FinishPendingRequests() { | |
60 typedef std::vector<URLRequestSlowDownloadJob*> JobList; | |
61 for (JobList::iterator it = kPendingRequests.begin(); it != | |
62 kPendingRequests.end(); ++it) { | |
63 (*it)->set_should_finish_download(); | |
64 } | |
65 kPendingRequests.clear(); | |
66 } | |
67 | |
68 URLRequestSlowDownloadJob::URLRequestSlowDownloadJob(net::URLRequest* request) | |
69 : net::URLRequestJob(request), | |
70 first_download_size_remaining_(kFirstDownloadSize), | |
71 should_finish_download_(false), | |
72 should_send_second_chunk_(false), | |
73 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {} | |
74 | |
75 void URLRequestSlowDownloadJob::StartAsync() { | |
76 if (LowerCaseEqualsASCII(kFinishDownloadUrl, request_->url().spec().c_str())) | |
77 URLRequestSlowDownloadJob::FinishPendingRequests(); | |
78 | |
79 NotifyHeadersComplete(); | |
80 } | |
81 | |
82 bool URLRequestSlowDownloadJob::ReadRawData(net::IOBuffer* buf, int buf_size, | |
83 int *bytes_read) { | |
84 if (LowerCaseEqualsASCII(kFinishDownloadUrl, | |
85 request_->url().spec().c_str())) { | |
86 *bytes_read = 0; | |
87 return true; | |
88 } | |
89 | |
90 if (should_send_second_chunk_) { | |
91 DCHECK(buf_size > kSecondDownloadSize); | |
92 for (int i = 0; i < kSecondDownloadSize; ++i) { | |
93 buf->data()[i] = '*'; | |
94 } | |
95 *bytes_read = kSecondDownloadSize; | |
96 should_send_second_chunk_ = false; | |
97 return true; | |
98 } | |
99 | |
100 if (first_download_size_remaining_ > 0) { | |
101 int send_size = std::min(first_download_size_remaining_, buf_size); | |
102 for (int i = 0; i < send_size; ++i) { | |
103 buf->data()[i] = '*'; | |
104 } | |
105 *bytes_read = send_size; | |
106 first_download_size_remaining_ -= send_size; | |
107 | |
108 DCHECK(!is_done()); | |
109 return true; | |
110 } | |
111 | |
112 if (should_finish_download_) { | |
113 *bytes_read = 0; | |
114 return true; | |
115 } | |
116 | |
117 // If we make it here, the first chunk has been sent and we need to wait | |
118 // until a request is made for kFinishDownloadUrl. | |
119 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | |
120 MessageLoop::current()->PostDelayedTask( | |
121 FROM_HERE, | |
122 method_factory_.NewRunnableMethod( | |
123 &URLRequestSlowDownloadJob::CheckDoneStatus), | |
124 100); | |
125 | |
126 // Return false to signal there is pending data. | |
127 return false; | |
128 } | |
129 | |
130 void URLRequestSlowDownloadJob::CheckDoneStatus() { | |
131 if (should_finish_download_) { | |
132 should_send_second_chunk_ = true; | |
133 SetStatus(net::URLRequestStatus()); | |
134 NotifyReadComplete(kSecondDownloadSize); | |
135 } else { | |
136 MessageLoop::current()->PostDelayedTask( | |
137 FROM_HERE, | |
138 method_factory_.NewRunnableMethod( | |
139 &URLRequestSlowDownloadJob::CheckDoneStatus), | |
140 100); | |
141 } | |
142 } | |
143 | |
144 // Public virtual version. | |
145 void URLRequestSlowDownloadJob::GetResponseInfo(net::HttpResponseInfo* info) { | |
146 // Forward to private const version. | |
147 GetResponseInfoConst(info); | |
148 } | |
149 | |
150 URLRequestSlowDownloadJob::~URLRequestSlowDownloadJob() {} | |
151 | |
152 // Private const version. | |
153 void URLRequestSlowDownloadJob::GetResponseInfoConst( | |
154 net::HttpResponseInfo* info) const { | |
155 // Send back mock headers. | |
156 std::string raw_headers; | |
157 if (LowerCaseEqualsASCII(kFinishDownloadUrl, | |
158 request_->url().spec().c_str())) { | |
159 raw_headers.append( | |
160 "HTTP/1.1 200 OK\n" | |
161 "Content-type: text/plain\n"); | |
162 } else { | |
163 raw_headers.append( | |
164 "HTTP/1.1 200 OK\n" | |
165 "Content-type: application/octet-stream\n" | |
166 "Cache-Control: max-age=0\n"); | |
167 | |
168 if (LowerCaseEqualsASCII(kKnownSizeUrl, request_->url().spec().c_str())) { | |
169 raw_headers.append(base::StringPrintf( | |
170 "Content-Length: %d\n", | |
171 kFirstDownloadSize + kSecondDownloadSize)); | |
172 } | |
173 } | |
174 | |
175 // ParseRawHeaders expects \0 to end each header line. | |
176 ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1)); | |
177 info->headers = new net::HttpResponseHeaders(raw_headers); | |
178 } | |
179 | |
180 bool URLRequestSlowDownloadJob::GetMimeType(std::string* mime_type) const { | |
181 net::HttpResponseInfo info; | |
182 GetResponseInfoConst(&info); | |
183 return info.headers && info.headers->GetMimeType(mime_type); | |
184 } | |
OLD | NEW |