[go: nahoru, domu]

blob: 0d189e3fddd8e7e9037fda93f3b28efe8e3482ac [file] [log] [blame]
willchan@chromium.orgef2bf422012-05-11 03:27:091// Copyright (c) 2012 The Chromium Authors. All rights reserved.
wtc@chromium.orgb65ce0942009-03-16 20:13:332// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
phajdan.jr@chromium.orge7fe5282010-03-16 12:40:135#include "net/url_request/url_request_ftp_job.h"
wtc@chromium.orgb65ce0942009-03-16 20:13:336
phajdan.jr@chromium.orgf5393332009-06-03 15:01:297#include "base/compiler_specific.h"
skyostil4891b25b2015-06-11 11:43:458#include "base/location.h"
9#include "base/single_thread_task_runner.h"
avi@chromium.org750b2f3c2013-06-07 18:41:0510#include "base/strings/utf_string_conversions.h"
gabf767595f2016-05-11 18:50:3511#include "base/threading/thread_task_runner_handle.h"
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:5812#include "net/base/auth.h"
bryner@chromium.org6d81b482011-02-22 19:47:1913#include "net/base/host_port_pair.h"
phajdan.jr@chromium.org45499252013-01-23 17:12:5614#include "net/base/load_flags.h"
phajdan.jr@chromium.org597cf6e2009-05-29 09:43:2615#include "net/base/net_errors.h"
pauljensen@chromium.orge0f35c92013-05-08 16:04:3416#include "net/ftp/ftp_auth_cache.h"
wtc@chromium.org581e0d02009-05-11 17:01:1717#include "net/ftp/ftp_response_info.h"
18#include "net/ftp/ftp_transaction_factory.h"
phajdan.jr@chromium.org45499252013-01-23 17:12:5619#include "net/http/http_response_headers.h"
20#include "net/http/http_transaction_factory.h"
wtc@chromium.orgb65ce0942009-03-16 20:13:3321#include "net/url_request/url_request.h"
22#include "net/url_request/url_request_context.h"
23#include "net/url_request/url_request_error_job.h"
24
tfarina@chromium.org03ea3c522010-12-12 01:47:5425namespace net {
26
asanka4cdf16d32016-10-06 22:00:2427class URLRequestFtpJob::AuthData {
28 public:
29 AuthState state; // Whether we need, have, or gave up on authentication.
30 AuthCredentials credentials; // The credentials to use for auth.
31
32 AuthData();
33 ~AuthData();
34};
35
36URLRequestFtpJob::AuthData::AuthData() : state(AUTH_STATE_NEED_AUTH) {}
37
Chris Watkins7a41d3552017-12-01 02:13:2738URLRequestFtpJob::AuthData::~AuthData() = default;
asanka4cdf16d32016-10-06 22:00:2439
shalev@chromium.orgb9cf48b2012-07-11 15:45:5940URLRequestFtpJob::URLRequestFtpJob(
41 URLRequest* request,
42 NetworkDelegate* network_delegate,
43 FtpTransactionFactory* ftp_transaction_factory,
44 FtpAuthCache* ftp_auth_cache)
45 : URLRequestJob(request, network_delegate),
akalin@chromium.org5033ab82013-03-22 20:17:4646 priority_(DEFAULT_PRIORITY),
Lily Houghton8c2f97d2018-01-22 05:06:5947 proxy_resolution_service_(
48 request_->context()->proxy_resolution_service()),
phajdan.jr@chromium.org78862512013-04-08 20:12:4349 http_response_info_(NULL),
wtc@chromium.orgb65ce0942009-03-16 20:13:3350 read_in_progress_(false),
shalev@chromium.orgb9cf48b2012-07-11 15:45:5951 ftp_transaction_factory_(ftp_transaction_factory),
n.bansal@samsung.com09812102014-05-24 00:04:1152 ftp_auth_cache_(ftp_auth_cache),
53 weak_factory_(this) {
Lily Houghton8c2f97d2018-01-22 05:06:5954 DCHECK(proxy_resolution_service_);
shalev@chromium.orgb9cf48b2012-07-11 15:45:5955 DCHECK(ftp_transaction_factory);
56 DCHECK(ftp_auth_cache);
wtc@chromium.orgb65ce0942009-03-16 20:13:3357}
58
akalin@chromium.org5033ab82013-03-22 20:17:4659URLRequestFtpJob::~URLRequestFtpJob() {
mmenke8a79ddb2015-10-27 12:30:5860 Kill();
akalin@chromium.org5033ab82013-03-22 20:17:4661}
62
phajdan.jr@chromium.org45499252013-01-23 17:12:5663bool URLRequestFtpJob::IsSafeRedirect(const GURL& location) {
64 // Disallow all redirects.
65 return false;
66}
67
phajdan.jr@chromium.orge7fe5282010-03-16 12:40:1368bool URLRequestFtpJob::GetMimeType(std::string* mime_type) const {
phajdan.jr@chromium.org45499252013-01-23 17:12:5669 if (proxy_info_.is_direct()) {
70 if (ftp_transaction_->GetResponseInfo()->is_directory_listing) {
71 *mime_type = "text/vnd.chromium.ftp-dir";
72 return true;
73 }
74 } else {
Mike West80462a12018-11-27 16:05:0675 std::string proxy_mime;
76 http_transaction_->GetResponseInfo()->headers->GetMimeType(&proxy_mime);
77 if (proxy_mime == "text/vnd.chromium.ftp-dir") {
78 *mime_type = "text/vnd.chromium.ftp-dir";
79 return true;
80 }
phajdan.jr@chromium.org64d50ed2009-09-22 21:05:4781 }
Mike West80462a12018-11-27 16:05:0682
83 // FTP resources other than directory listings ought to be handled as raw
84 // binary data, not sniffed into HTML or etc.
85 *mime_type = "application/octet-stream";
86 return true;
phajdan.jr@chromium.org64d50ed2009-09-22 21:05:4787}
88
phajdan.jr@chromium.org45499252013-01-23 17:12:5689void URLRequestFtpJob::GetResponseInfo(HttpResponseInfo* info) {
phajdan.jr@chromium.org78862512013-04-08 20:12:4390 if (http_response_info_)
91 *info = *http_response_info_;
phajdan.jr@chromium.org45499252013-01-23 17:12:5692}
93
bryner@chromium.org6d81b482011-02-22 19:47:1994HostPortPair URLRequestFtpJob::GetSocketAddress() const {
phajdan.jr@chromium.org45499252013-01-23 17:12:5695 if (proxy_info_.is_direct()) {
96 if (!ftp_transaction_)
97 return HostPortPair();
98 return ftp_transaction_->GetResponseInfo()->socket_address;
99 } else {
100 if (!http_transaction_)
101 return HostPortPair();
102 return http_transaction_->GetResponseInfo()->socket_address;
bryner@chromium.org6d81b482011-02-22 19:47:19103 }
bryner@chromium.org6d81b482011-02-22 19:47:19104}
105
akalin@chromium.org5033ab82013-03-22 20:17:46106void URLRequestFtpJob::SetPriority(RequestPriority priority) {
107 priority_ = priority;
108 if (http_transaction_)
109 http_transaction_->SetPriority(priority);
110}
111
112void URLRequestFtpJob::Start() {
Lily Houghton00e124d2018-01-12 21:40:39113 DCHECK(!proxy_resolve_request_);
akalin@chromium.org5033ab82013-03-22 20:17:46114 DCHECK(!ftp_transaction_);
115 DCHECK(!http_transaction_);
116
117 int rv = OK;
118 if (request_->load_flags() & LOAD_BYPASS_PROXY) {
119 proxy_info_.UseDirect();
120 } else {
Lily Houghton8c2f97d2018-01-22 05:06:59121 DCHECK_EQ(request_->context()->proxy_resolution_service(),
122 proxy_resolution_service_);
123 rv = proxy_resolution_service_->ResolveProxy(
ryansturm7bd591a2016-07-18 21:57:38124 request_->url(), "GET", &proxy_info_,
akalin@chromium.org5033ab82013-03-22 20:17:46125 base::Bind(&URLRequestFtpJob::OnResolveProxyComplete,
126 base::Unretained(this)),
Eric Roman3d8546a2018-09-10 17:00:52127 &proxy_resolve_request_, request_->net_log());
akalin@chromium.org5033ab82013-03-22 20:17:46128
129 if (rv == ERR_IO_PENDING)
130 return;
131 }
132 OnResolveProxyComplete(rv);
133}
134
135void URLRequestFtpJob::Kill() {
Lily Houghton00e124d2018-01-12 21:40:39136 if (proxy_resolve_request_) {
Lily Houghton0e9a4992018-07-30 22:40:37137 proxy_resolve_request_.reset();
mmenke8a79ddb2015-10-27 12:30:58138 }
akalin@chromium.org5033ab82013-03-22 20:17:46139 if (ftp_transaction_)
140 ftp_transaction_.reset();
141 if (http_transaction_)
142 http_transaction_.reset();
143 URLRequestJob::Kill();
144 weak_factory_.InvalidateWeakPtrs();
erg@google.com5394e422011-01-20 22:07:43145}
146
phajdan.jr@chromium.org45499252013-01-23 17:12:56147void URLRequestFtpJob::OnResolveProxyComplete(int result) {
Lily Houghton00e124d2018-01-12 21:40:39148 proxy_resolve_request_ = NULL;
erg@google.com5394e422011-01-20 22:07:43149
phajdan.jr@chromium.org45499252013-01-23 17:12:56150 if (result != OK) {
151 OnStartCompletedAsync(result);
152 return;
153 }
154
155 // Remove unsupported proxies from the list.
156 proxy_info_.RemoveProxiesWithoutScheme(
157 ProxyServer::SCHEME_DIRECT |
158 ProxyServer::SCHEME_HTTP |
159 ProxyServer::SCHEME_HTTPS);
160
161 // TODO(phajdan.jr): Implement proxy fallback, http://crbug.com/171495 .
162 if (proxy_info_.is_direct())
163 StartFtpTransaction();
164 else if (proxy_info_.is_http() || proxy_info_.is_https())
165 StartHttpTransaction();
166 else
167 OnStartCompletedAsync(ERR_NO_SUPPORTED_PROXIES);
168}
169
170void URLRequestFtpJob::StartFtpTransaction() {
171 // Create a transaction.
172 DCHECK(!ftp_transaction_);
173
174 ftp_request_info_.url = request_->url();
tfh4aeb2a52015-12-24 11:49:35175 ftp_transaction_ = ftp_transaction_factory_->CreateTransaction();
erg@google.com5394e422011-01-20 22:07:43176
erg@google.com5394e422011-01-20 22:07:43177 int rv;
phajdan.jr@chromium.org45499252013-01-23 17:12:56178 if (ftp_transaction_) {
179 rv = ftp_transaction_->Start(
180 &ftp_request_info_,
rhalavati@google.comf0ac81322018-01-16 20:34:41181 base::Bind(&URLRequestFtpJob::OnStartCompleted, base::Unretained(this)),
182 request_->net_log(), request_->traffic_annotation());
erg@google.com5394e422011-01-20 22:07:43183 if (rv == ERR_IO_PENDING)
184 return;
185 } else {
186 rv = ERR_FAILED;
187 }
188 // The transaction started synchronously, but we need to notify the
189 // URLRequest delegate via the message loop.
phajdan.jr@chromium.org45499252013-01-23 17:12:56190 OnStartCompletedAsync(rv);
191}
192
193void URLRequestFtpJob::StartHttpTransaction() {
194 // Create a transaction.
195 DCHECK(!http_transaction_);
196
197 // Do not cache FTP responses sent through HTTP proxy.
akalin@chromium.orgbb1c4662013-11-14 00:00:07198 request_->SetLoadFlags(request_->load_flags() |
199 LOAD_DISABLE_CACHE |
200 LOAD_DO_NOT_SAVE_COOKIES |
201 LOAD_DO_NOT_SEND_COOKIES);
phajdan.jr@chromium.org45499252013-01-23 17:12:56202
203 http_request_info_.url = request_->url();
204 http_request_info_.method = request_->method();
205 http_request_info_.load_flags = request_->load_flags();
Ramin Halavatib5e433e2018-02-07 07:41:10206 http_request_info_.traffic_annotation =
207 net::MutableNetworkTrafficAnnotationTag(request_->traffic_annotation());
phajdan.jr@chromium.org45499252013-01-23 17:12:56208
209 int rv = request_->context()->http_transaction_factory()->CreateTransaction(
rvargas@chromium.org027bd85a2013-12-27 22:39:10210 priority_, &http_transaction_);
phajdan.jr@chromium.org45499252013-01-23 17:12:56211 if (rv == OK) {
212 rv = http_transaction_->Start(
213 &http_request_info_,
214 base::Bind(&URLRequestFtpJob::OnStartCompleted,
rvargas@chromium.org027bd85a2013-12-27 22:39:10215 base::Unretained(this)),
phajdan.jr@chromium.org45499252013-01-23 17:12:56216 request_->net_log());
217 if (rv == ERR_IO_PENDING)
218 return;
219 }
220 // The transaction started synchronously, but we need to notify the
221 // URLRequest delegate via the message loop.
222 OnStartCompletedAsync(rv);
erg@google.com5394e422011-01-20 22:07:43223}
224
225void URLRequestFtpJob::OnStartCompleted(int result) {
phajdan.jr@chromium.org45499252013-01-23 17:12:56226 // Note that ftp_transaction_ may be NULL due to a creation failure.
227 if (ftp_transaction_) {
shalev@chromium.orge072757f2012-07-12 20:16:04228 // FTP obviously doesn't have HTTP Content-Length header. We have to pass
229 // the content size information manually.
230 set_expected_content_size(
phajdan.jr@chromium.org45499252013-01-23 17:12:56231 ftp_transaction_->GetResponseInfo()->expected_content_size);
shalev@chromium.orge072757f2012-07-12 20:16:04232 }
erg@google.com5394e422011-01-20 22:07:43233
234 if (result == OK) {
phajdan.jr@chromium.org78862512013-04-08 20:12:43235 if (http_transaction_) {
236 http_response_info_ = http_transaction_->GetResponseInfo();
bengr@chromium.orgd8fc4722014-06-13 13:17:15237 SetProxyServer(http_response_info_->proxy_server);
phajdan.jr@chromium.org78862512013-04-08 20:12:43238
239 if (http_response_info_->headers->response_code() == 401 ||
240 http_response_info_->headers->response_code() == 407) {
241 HandleAuthNeededResponse();
242 return;
243 }
244 }
erg@google.com5394e422011-01-20 22:07:43245 NotifyHeadersComplete();
phajdan.jr@chromium.org45499252013-01-23 17:12:56246 } else if (ftp_transaction_ &&
247 ftp_transaction_->GetResponseInfo()->needs_auth) {
phajdan.jr@chromium.org78862512013-04-08 20:12:43248 HandleAuthNeededResponse();
249 return;
erg@google.com5394e422011-01-20 22:07:43250 } else {
xunjieli26ede962015-11-23 19:39:13251 NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
erg@google.com5394e422011-01-20 22:07:43252 }
253}
254
phajdan.jr@chromium.org45499252013-01-23 17:12:56255void URLRequestFtpJob::OnStartCompletedAsync(int result) {
skyostil4891b25b2015-06-11 11:43:45256 base::ThreadTaskRunnerHandle::Get()->PostTask(
257 FROM_HERE, base::Bind(&URLRequestFtpJob::OnStartCompleted,
258 weak_factory_.GetWeakPtr(), result));
phajdan.jr@chromium.org45499252013-01-23 17:12:56259}
260
erg@google.com5394e422011-01-20 22:07:43261void URLRequestFtpJob::OnReadCompleted(int result) {
262 read_in_progress_ = false;
xunjieli26ede962015-11-23 19:39:13263 ReadRawDataComplete(result);
erg@google.com5394e422011-01-20 22:07:43264}
265
266void URLRequestFtpJob::RestartTransactionWithAuth() {
rsleevi@chromium.org90499482013-06-01 00:39:50267 DCHECK(auth_data_.get() && auth_data_->state == AUTH_STATE_HAVE_AUTH);
erg@google.com5394e422011-01-20 22:07:43268
phajdan.jr@chromium.org78862512013-04-08 20:12:43269 int rv;
270 if (proxy_info_.is_direct()) {
271 rv = ftp_transaction_->RestartWithAuth(
272 auth_data_->credentials,
273 base::Bind(&URLRequestFtpJob::OnStartCompleted,
274 base::Unretained(this)));
275 } else {
276 rv = http_transaction_->RestartWithAuth(
277 auth_data_->credentials,
278 base::Bind(&URLRequestFtpJob::OnStartCompleted,
279 base::Unretained(this)));
280 }
erg@google.com5394e422011-01-20 22:07:43281 if (rv == ERR_IO_PENDING)
282 return;
283
phajdan.jr@chromium.org45499252013-01-23 17:12:56284 OnStartCompletedAsync(rv);
erg@google.com5394e422011-01-20 22:07:43285}
286
tfarina@chromium.org03ea3c522010-12-12 01:47:54287LoadState URLRequestFtpJob::GetLoadState() const {
Lily Houghton00e124d2018-01-12 21:40:39288 if (proxy_resolve_request_)
Lily Houghton0e9a4992018-07-30 22:40:37289 return proxy_resolve_request_->GetLoadState();
phajdan.jr@chromium.org45499252013-01-23 17:12:56290 if (proxy_info_.is_direct()) {
291 return ftp_transaction_ ?
292 ftp_transaction_->GetLoadState() : LOAD_STATE_IDLE;
293 } else {
294 return http_transaction_ ?
295 http_transaction_->GetLoadState() : LOAD_STATE_IDLE;
296 }
phajdan.jr@chromium.orgbf5ad682009-08-12 19:19:28297}
298
phajdan.jr@chromium.orge7fe5282010-03-16 12:40:13299bool URLRequestFtpJob::NeedsAuth() {
rsleevi@chromium.org90499482013-06-01 00:39:50300 return auth_data_.get() && auth_data_->state == AUTH_STATE_NEED_AUTH;
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58301}
302
phajdan.jr@chromium.orge7fe5282010-03-16 12:40:13303void URLRequestFtpJob::GetAuthChallengeInfo(
tfarina@chromium.org03ea3c522010-12-12 01:47:54304 scoped_refptr<AuthChallengeInfo>* result) {
phajdan.jr@chromium.org78862512013-04-08 20:12:43305 DCHECK(NeedsAuth());
306
307 if (http_response_info_) {
308 *result = http_response_info_->auth_challenge;
309 return;
310 }
311
tfarina@chromium.org03ea3c522010-12-12 01:47:54312 scoped_refptr<AuthChallengeInfo> auth_info(new AuthChallengeInfo);
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58313 auth_info->is_proxy = false;
Daniel Cheng88186bd52017-10-20 08:14:46314 auth_info->challenger = url::Origin::Create(request_->url());
cbentzel@chromium.org79cb5c12011-09-12 13:12:04315 // scheme and realm are kept empty.
316 DCHECK(auth_info->scheme.empty());
317 DCHECK(auth_info->realm.empty());
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58318 result->swap(auth_info);
319}
320
cbentzel@chromium.orgf3cf9802011-10-28 18:44:58321void URLRequestFtpJob::SetAuth(const AuthCredentials& credentials) {
phajdan.jr@chromium.org78862512013-04-08 20:12:43322 DCHECK(ftp_transaction_ || http_transaction_);
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58323 DCHECK(NeedsAuth());
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58324
phajdan.jr@chromium.org78862512013-04-08 20:12:43325 auth_data_->state = AUTH_STATE_HAVE_AUTH;
326 auth_data_->credentials = credentials;
327
328 if (ftp_transaction_) {
329 ftp_auth_cache_->Add(request_->url().GetOrigin(),
330 auth_data_->credentials);
331 }
phajdan.jr@chromium.org60a3df52009-09-22 16:13:24332
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58333 RestartTransactionWithAuth();
334}
335
phajdan.jr@chromium.orge7fe5282010-03-16 12:40:13336void URLRequestFtpJob::CancelAuth() {
phajdan.jr@chromium.org78862512013-04-08 20:12:43337 DCHECK(ftp_transaction_ || http_transaction_);
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58338 DCHECK(NeedsAuth());
phajdan.jr@chromium.org78862512013-04-08 20:12:43339
340 auth_data_->state = AUTH_STATE_CANCELED;
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58341
342 // Once the auth is cancelled, we proceed with the request as though
343 // there were no auth. Schedule this for later so that we don't cause
344 // any recursing into the caller as a result of this call.
phajdan.jr@chromium.org45499252013-01-23 17:12:56345 OnStartCompletedAsync(OK);
phajdan.jr@chromium.org8b8a197d2009-08-26 15:57:58346}
347
xunjieli26ede962015-11-23 19:39:13348int URLRequestFtpJob::ReadRawData(IOBuffer* buf, int buf_size) {
wtc@chromium.org581e0d02009-05-11 17:01:17349 DCHECK_NE(buf_size, 0);
wtc@chromium.org581e0d02009-05-11 17:01:17350 DCHECK(!read_in_progress_);
wtc@chromium.org4c62d8c32009-06-05 02:14:16351
phajdan.jr@chromium.org45499252013-01-23 17:12:56352 int rv;
xunjieli26ede962015-11-23 19:39:13353
phajdan.jr@chromium.org45499252013-01-23 17:12:56354 if (proxy_info_.is_direct()) {
355 rv = ftp_transaction_->Read(buf, buf_size,
356 base::Bind(&URLRequestFtpJob::OnReadCompleted,
357 base::Unretained(this)));
358 } else {
359 rv = http_transaction_->Read(buf, buf_size,
360 base::Bind(&URLRequestFtpJob::OnReadCompleted,
361 base::Unretained(this)));
362 }
363
xunjieli26ede962015-11-23 19:39:13364 if (rv == ERR_IO_PENDING)
wtc@chromium.org581e0d02009-05-11 17:01:17365 read_in_progress_ = true;
xunjieli26ede962015-11-23 19:39:13366 return rv;
wtc@chromium.orgb65ce0942009-03-16 20:13:33367}
368
phajdan.jr@chromium.org78862512013-04-08 20:12:43369void URLRequestFtpJob::HandleAuthNeededResponse() {
370 GURL origin = request_->url().GetOrigin();
371
rsleevi@chromium.org90499482013-06-01 00:39:50372 if (auth_data_.get()) {
phajdan.jr@chromium.org78862512013-04-08 20:12:43373 if (auth_data_->state == AUTH_STATE_CANCELED) {
374 NotifyHeadersComplete();
375 return;
376 }
377
378 if (ftp_transaction_ && auth_data_->state == AUTH_STATE_HAVE_AUTH)
379 ftp_auth_cache_->Remove(origin, auth_data_->credentials);
380 } else {
Jeremy Roman0579ed62017-08-29 15:56:19381 auth_data_ = std::make_unique<AuthData>();
phajdan.jr@chromium.org78862512013-04-08 20:12:43382 }
383 auth_data_->state = AUTH_STATE_NEED_AUTH;
384
385 FtpAuthCache::Entry* cached_auth = NULL;
386 if (ftp_transaction_ && ftp_transaction_->GetResponseInfo()->needs_auth)
387 cached_auth = ftp_auth_cache_->Lookup(origin);
388 if (cached_auth) {
389 // Retry using cached auth data.
390 SetAuth(cached_auth->credentials);
391 } else {
392 // Prompt for a username/password.
393 NotifyHeadersComplete();
394 }
395}
396
tfarina@chromium.org03ea3c522010-12-12 01:47:54397} // namespace net