1 // Copyright (c) 2012 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.
5 #include "net/ftp/ftp_network_transaction.h"
8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "net/base/address_list.h"
17 #include "net/base/connection_type_histograms.h"
18 #include "net/base/escape.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/net_log.h"
21 #include "net/base/net_util.h"
22 #include "net/ftp/ftp_network_session.h"
23 #include "net/ftp/ftp_request_info.h"
24 #include "net/ftp/ftp_util.h"
25 #include "net/socket/client_socket_factory.h"
26 #include "net/socket/stream_socket.h"
28 const char kCRLF
[] = "\r\n";
30 const int kCtrlBufLen
= 1024;
34 // Returns true if |input| can be safely used as a part of FTP command.
35 bool IsValidFTPCommandString(const std::string
& input
) {
36 // RFC 959 only allows ASCII strings, but at least Firefox can send non-ASCII
37 // characters in the command if the request path contains them. To be
38 // compatible, we do the same and allow non-ASCII characters in a command.
40 // Protect agains newline injection attack.
41 if (input
.find_first_of("\r\n") != std::string::npos
)
48 // The requested action was initiated. The client should expect another
49 // reply before issuing the next command.
50 ERROR_CLASS_INITIATED
,
52 // The requested action has been successfully completed.
55 // The command has been accepted, but to complete the operation, more
56 // information must be sent by the client.
57 ERROR_CLASS_INFO_NEEDED
,
59 // The command was not accepted and the requested action did not take place.
60 // This condition is temporary, and the client is encouraged to restart the
62 ERROR_CLASS_TRANSIENT_ERROR
,
64 // The command was not accepted and the requested action did not take place.
65 // This condition is rather permanent, and the client is discouraged from
66 // repeating the exact request.
67 ERROR_CLASS_PERMANENT_ERROR
,
70 // Returns the error class for given response code. Caller should ensure
71 // that |response_code| is in range 100-599.
72 ErrorClass
GetErrorClass(int response_code
) {
73 if (response_code
>= 100 && response_code
<= 199)
74 return ERROR_CLASS_INITIATED
;
76 if (response_code
>= 200 && response_code
<= 299)
77 return ERROR_CLASS_OK
;
79 if (response_code
>= 300 && response_code
<= 399)
80 return ERROR_CLASS_INFO_NEEDED
;
82 if (response_code
>= 400 && response_code
<= 499)
83 return ERROR_CLASS_TRANSIENT_ERROR
;
85 if (response_code
>= 500 && response_code
<= 599)
86 return ERROR_CLASS_PERMANENT_ERROR
;
88 // We should not be called on invalid error codes.
89 NOTREACHED() << response_code
;
90 return ERROR_CLASS_PERMANENT_ERROR
;
93 // Returns network error code for received FTP |response_code|.
94 int GetNetErrorCodeForFtpResponseCode(int response_code
) {
95 switch (response_code
) {
97 return net::ERR_FTP_SERVICE_UNAVAILABLE
;
99 return net::ERR_FTP_TRANSFER_ABORTED
;
101 return net::ERR_FTP_FILE_BUSY
;
104 return net::ERR_FTP_SYNTAX_ERROR
;
107 return net::ERR_FTP_COMMAND_NOT_SUPPORTED
;
109 return net::ERR_FTP_BAD_COMMAND_SEQUENCE
;
111 return net::ERR_FTP_FAILED
;
115 // From RFC 2428 Section 3:
116 // The text returned in response to the EPSV command MUST be:
117 // <some text> (<d><d><d><tcp-port><d>)
118 // <d> is a delimiter character, ideally to be |
119 bool ExtractPortFromEPSVResponse(const net::FtpCtrlResponse
& response
,
121 if (response
.lines
.size() != 1)
123 const char* ptr
= response
.lines
[0].c_str();
124 while (*ptr
&& *ptr
!= '(')
129 if (!sep
|| isdigit(sep
) || *(++ptr
) != sep
|| *(++ptr
) != sep
)
131 if (!isdigit(*(++ptr
)))
134 while (isdigit(*(++ptr
))) {
144 // There are two way we can receive IP address and port.
145 // (127,0,0,1,23,21) IP address and port encapsulated in ().
146 // 127,0,0,1,23,21 IP address and port without ().
148 // See RFC 959, Section 4.1.2
149 bool ExtractPortFromPASVResponse(const net::FtpCtrlResponse
& response
,
151 if (response
.lines
.size() != 1)
154 std::string
line(response
.lines
[0]);
155 if (!base::IsStringASCII(line
))
157 if (line
.length() < 2)
160 size_t paren_pos
= line
.find('(');
161 if (paren_pos
== std::string::npos
) {
162 // Find the first comma and use it to locate the beginning
163 // of the response data.
164 size_t comma_pos
= line
.find(',');
165 if (comma_pos
== std::string::npos
)
168 size_t space_pos
= line
.rfind(' ', comma_pos
);
169 if (space_pos
!= std::string::npos
)
170 line
= line
.substr(space_pos
+ 1);
172 // Remove the parentheses and use the text inside them.
173 size_t closing_paren_pos
= line
.rfind(')');
174 if (closing_paren_pos
== std::string::npos
)
176 if (closing_paren_pos
<= paren_pos
)
179 line
= line
.substr(paren_pos
+ 1, closing_paren_pos
- paren_pos
- 1);
182 // Split the line into comma-separated pieces and extract
184 std::vector
<std::string
> pieces
;
185 base::SplitString(line
, ',', &pieces
);
186 if (pieces
.size() != 6)
189 // Ignore the IP address supplied in the response. We are always going
190 // to connect back to the same server to prevent FTP PASV port scanning.
192 if (!base::StringToInt(pieces
[4], &p0
))
194 if (!base::StringToInt(pieces
[5], &p1
))
196 *port
= (p0
<< 8) + p1
;
205 FtpNetworkTransaction::FtpNetworkTransaction(
206 FtpNetworkSession
* session
,
207 ClientSocketFactory
* socket_factory
)
208 : command_sent_(COMMAND_NONE
),
209 io_callback_(base::Bind(&FtpNetworkTransaction::OnIOComplete
,
210 base::Unretained(this))),
213 resolver_(session
->host_resolver()),
214 read_ctrl_buf_(new IOBuffer(kCtrlBufLen
)),
215 read_data_buf_len_(0),
217 system_type_(SYSTEM_TYPE_UNKNOWN
),
218 // Use image (binary) transfer by default. It should always work,
219 // whereas the ascii transfer may damage binary data.
220 data_type_(DATA_TYPE_IMAGE
),
221 resource_type_(RESOURCE_TYPE_UNKNOWN
),
223 data_connection_port_(0),
224 socket_factory_(socket_factory
),
225 next_state_(STATE_NONE
),
226 state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE
) {}
228 FtpNetworkTransaction::~FtpNetworkTransaction() {
231 int FtpNetworkTransaction::Stop(int error
) {
232 if (command_sent_
== COMMAND_QUIT
)
235 next_state_
= STATE_CTRL_WRITE_QUIT
;
240 int FtpNetworkTransaction::RestartIgnoringLastError(
241 const CompletionCallback
& callback
) {
242 return ERR_NOT_IMPLEMENTED
;
245 int FtpNetworkTransaction::Start(const FtpRequestInfo
* request_info
,
246 const CompletionCallback
& callback
,
247 const BoundNetLog
& net_log
) {
249 request_
= request_info
;
251 ctrl_response_buffer_
.reset(new FtpCtrlResponseBuffer(net_log_
));
253 if (request_
->url
.has_username()) {
254 base::string16 username
;
255 base::string16 password
;
256 GetIdentityFromURL(request_
->url
, &username
, &password
);
257 credentials_
.Set(username
, password
);
259 credentials_
.Set(base::ASCIIToUTF16("anonymous"),
260 base::ASCIIToUTF16("chrome@example.com"));
265 next_state_
= STATE_CTRL_RESOLVE_HOST
;
267 if (rv
== ERR_IO_PENDING
)
268 user_callback_
= callback
;
272 int FtpNetworkTransaction::RestartWithAuth(const AuthCredentials
& credentials
,
273 const CompletionCallback
& callback
) {
274 ResetStateForRestart();
276 credentials_
= credentials
;
278 next_state_
= STATE_CTRL_RESOLVE_HOST
;
280 if (rv
== ERR_IO_PENDING
)
281 user_callback_
= callback
;
285 int FtpNetworkTransaction::Read(IOBuffer
* buf
,
287 const CompletionCallback
& callback
) {
289 DCHECK_GT(buf_len
, 0);
291 read_data_buf_
= buf
;
292 read_data_buf_len_
= buf_len
;
294 next_state_
= STATE_DATA_READ
;
296 if (rv
== ERR_IO_PENDING
)
297 user_callback_
= callback
;
301 const FtpResponseInfo
* FtpNetworkTransaction::GetResponseInfo() const {
305 LoadState
FtpNetworkTransaction::GetLoadState() const {
306 if (next_state_
== STATE_CTRL_RESOLVE_HOST_COMPLETE
)
307 return LOAD_STATE_RESOLVING_HOST
;
309 if (next_state_
== STATE_CTRL_CONNECT_COMPLETE
||
310 next_state_
== STATE_DATA_CONNECT_COMPLETE
)
311 return LOAD_STATE_CONNECTING
;
313 if (next_state_
== STATE_DATA_READ_COMPLETE
)
314 return LOAD_STATE_READING_RESPONSE
;
316 if (command_sent_
== COMMAND_RETR
&& read_data_buf_
.get())
317 return LOAD_STATE_READING_RESPONSE
;
319 if (command_sent_
== COMMAND_QUIT
)
320 return LOAD_STATE_IDLE
;
322 if (command_sent_
!= COMMAND_NONE
)
323 return LOAD_STATE_SENDING_REQUEST
;
325 return LOAD_STATE_IDLE
;
328 uint64
FtpNetworkTransaction::GetUploadProgress() const {
332 void FtpNetworkTransaction::ResetStateForRestart() {
333 command_sent_
= COMMAND_NONE
;
334 user_callback_
.Reset();
335 response_
= FtpResponseInfo();
336 read_ctrl_buf_
= new IOBuffer(kCtrlBufLen
);
337 ctrl_response_buffer_
.reset(new FtpCtrlResponseBuffer(net_log_
));
338 read_data_buf_
= NULL
;
339 read_data_buf_len_
= 0;
340 if (write_buf_
.get())
341 write_buf_
->SetOffset(0);
343 data_connection_port_
= 0;
344 ctrl_socket_
.reset();
345 data_socket_
.reset();
346 next_state_
= STATE_NONE
;
347 state_after_data_connect_complete_
= STATE_CTRL_WRITE_SIZE
;
350 void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state
) {
351 // The server _might_ have reset the data connection
352 // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS:
353 // "The server MUST close the data connection under the following
356 // 5. An irrecoverable error condition occurs.")
358 // It is ambiguous what an irrecoverable error condition is,
359 // so we take no chances.
360 state_after_data_connect_complete_
= next_state
;
361 next_state_
= use_epsv_
? STATE_CTRL_WRITE_EPSV
: STATE_CTRL_WRITE_PASV
;
364 void FtpNetworkTransaction::DoCallback(int rv
) {
365 DCHECK(rv
!= ERR_IO_PENDING
);
366 DCHECK(!user_callback_
.is_null());
368 // Since Run may result in Read being called, clear callback_ up front.
369 CompletionCallback c
= user_callback_
;
370 user_callback_
.Reset();
374 void FtpNetworkTransaction::OnIOComplete(int result
) {
375 int rv
= DoLoop(result
);
376 if (rv
!= ERR_IO_PENDING
)
380 int FtpNetworkTransaction::ProcessCtrlResponse() {
381 FtpCtrlResponse response
= ctrl_response_buffer_
->PopResponse();
384 switch (command_sent_
) {
386 // TODO(phajdan.jr): Check for errors in the welcome message.
387 next_state_
= STATE_CTRL_WRITE_USER
;
390 rv
= ProcessResponseUSER(response
);
393 rv
= ProcessResponsePASS(response
);
396 rv
= ProcessResponseSYST(response
);
399 rv
= ProcessResponsePWD(response
);
402 rv
= ProcessResponseTYPE(response
);
405 rv
= ProcessResponseEPSV(response
);
408 rv
= ProcessResponsePASV(response
);
411 rv
= ProcessResponseSIZE(response
);
414 rv
= ProcessResponseRETR(response
);
417 rv
= ProcessResponseCWD(response
);
420 rv
= ProcessResponseLIST(response
);
423 rv
= ProcessResponseQUIT(response
);
426 LOG(DFATAL
) << "Unexpected value of command_sent_: " << command_sent_
;
427 return ERR_UNEXPECTED
;
430 // We may get multiple responses for some commands,
431 // see http://crbug.com/18036.
432 while (ctrl_response_buffer_
->ResponseAvailable() && rv
== OK
) {
433 response
= ctrl_response_buffer_
->PopResponse();
435 switch (command_sent_
) {
437 rv
= ProcessResponseRETR(response
);
440 rv
= ProcessResponseLIST(response
);
443 // Multiple responses for other commands are invalid.
444 return Stop(ERR_INVALID_RESPONSE
);
451 // Used to prepare and send FTP command.
452 int FtpNetworkTransaction::SendFtpCommand(const std::string
& command
,
453 const std::string
& command_for_log
,
455 // If we send a new command when we still have unprocessed responses
456 // for previous commands, the response receiving code will have no way to know
457 // which responses are for which command.
458 DCHECK(!ctrl_response_buffer_
->ResponseAvailable());
460 DCHECK(!write_command_buf_
.get());
461 DCHECK(!write_buf_
.get());
463 if (!IsValidFTPCommandString(command
)) {
464 // Callers should validate the command themselves and return a more specific
467 return Stop(ERR_UNEXPECTED
);
472 write_command_buf_
= new IOBufferWithSize(command
.length() + 2);
473 write_buf_
= new DrainableIOBuffer(write_command_buf_
.get(),
474 write_command_buf_
->size());
475 memcpy(write_command_buf_
->data(), command
.data(), command
.length());
476 memcpy(write_command_buf_
->data() + command
.length(), kCRLF
, 2);
478 net_log_
.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT
,
479 NetLog::StringCallback("command", &command_for_log
));
481 next_state_
= STATE_CTRL_WRITE
;
485 std::string
FtpNetworkTransaction::GetRequestPathForFtpCommand(
486 bool is_directory
) const {
487 std::string
path(current_remote_directory_
);
488 if (request_
->url
.has_path()) {
489 std::string
gurl_path(request_
->url
.path());
491 // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path.
492 std::string::size_type pos
= gurl_path
.rfind(';');
493 if (pos
!= std::string::npos
)
494 gurl_path
.resize(pos
);
496 path
.append(gurl_path
);
498 // Make sure that if the path is expected to be a file, it won't end
499 // with a trailing slash.
500 if (!is_directory
&& path
.length() > 1 && path
[path
.length() - 1] == '/')
501 path
.erase(path
.length() - 1);
502 UnescapeRule::Type unescape_rules
= UnescapeRule::SPACES
|
503 UnescapeRule::URL_SPECIAL_CHARS
;
504 // This may unescape to non-ASCII characters, but we allow that. See the
505 // comment for IsValidFTPCommandString.
506 path
= net::UnescapeURLComponent(path
, unescape_rules
);
508 if (system_type_
== SYSTEM_TYPE_VMS
) {
510 path
= FtpUtil::UnixDirectoryPathToVMS(path
);
512 path
= FtpUtil::UnixFilePathToVMS(path
);
515 DCHECK(IsValidFTPCommandString(path
));
519 void FtpNetworkTransaction::DetectTypecode() {
520 if (!request_
->url
.has_path())
522 std::string
gurl_path(request_
->url
.path());
524 // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path.
525 std::string::size_type pos
= gurl_path
.rfind(';');
526 if (pos
== std::string::npos
)
528 std::string
typecode_string(gurl_path
.substr(pos
));
529 if (typecode_string
== ";type=a") {
530 data_type_
= DATA_TYPE_ASCII
;
531 resource_type_
= RESOURCE_TYPE_FILE
;
532 } else if (typecode_string
== ";type=i") {
533 data_type_
= DATA_TYPE_IMAGE
;
534 resource_type_
= RESOURCE_TYPE_FILE
;
535 } else if (typecode_string
== ";type=d") {
536 resource_type_
= RESOURCE_TYPE_DIRECTORY
;
540 int FtpNetworkTransaction::DoLoop(int result
) {
541 DCHECK(next_state_
!= STATE_NONE
);
545 State state
= next_state_
;
546 next_state_
= STATE_NONE
;
548 case STATE_CTRL_RESOLVE_HOST
:
550 rv
= DoCtrlResolveHost();
552 case STATE_CTRL_RESOLVE_HOST_COMPLETE
:
553 rv
= DoCtrlResolveHostComplete(rv
);
555 case STATE_CTRL_CONNECT
:
557 rv
= DoCtrlConnect();
559 case STATE_CTRL_CONNECT_COMPLETE
:
560 rv
= DoCtrlConnectComplete(rv
);
562 case STATE_CTRL_READ
:
566 case STATE_CTRL_READ_COMPLETE
:
567 rv
= DoCtrlReadComplete(rv
);
569 case STATE_CTRL_WRITE
:
573 case STATE_CTRL_WRITE_COMPLETE
:
574 rv
= DoCtrlWriteComplete(rv
);
576 case STATE_CTRL_WRITE_USER
:
578 rv
= DoCtrlWriteUSER();
580 case STATE_CTRL_WRITE_PASS
:
582 rv
= DoCtrlWritePASS();
584 case STATE_CTRL_WRITE_SYST
:
586 rv
= DoCtrlWriteSYST();
588 case STATE_CTRL_WRITE_PWD
:
590 rv
= DoCtrlWritePWD();
592 case STATE_CTRL_WRITE_TYPE
:
594 rv
= DoCtrlWriteTYPE();
596 case STATE_CTRL_WRITE_EPSV
:
598 rv
= DoCtrlWriteEPSV();
600 case STATE_CTRL_WRITE_PASV
:
602 rv
= DoCtrlWritePASV();
604 case STATE_CTRL_WRITE_RETR
:
606 rv
= DoCtrlWriteRETR();
608 case STATE_CTRL_WRITE_SIZE
:
610 rv
= DoCtrlWriteSIZE();
612 case STATE_CTRL_WRITE_CWD
:
614 rv
= DoCtrlWriteCWD();
616 case STATE_CTRL_WRITE_LIST
:
618 rv
= DoCtrlWriteLIST();
620 case STATE_CTRL_WRITE_QUIT
:
622 rv
= DoCtrlWriteQUIT();
624 case STATE_DATA_CONNECT
:
626 rv
= DoDataConnect();
628 case STATE_DATA_CONNECT_COMPLETE
:
629 rv
= DoDataConnectComplete(rv
);
631 case STATE_DATA_READ
:
635 case STATE_DATA_READ_COMPLETE
:
636 rv
= DoDataReadComplete(rv
);
639 NOTREACHED() << "bad state";
643 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
647 int FtpNetworkTransaction::DoCtrlResolveHost() {
648 next_state_
= STATE_CTRL_RESOLVE_HOST_COMPLETE
;
650 HostResolver::RequestInfo
info(HostPortPair::FromURL(request_
->url
));
651 // No known referrer.
652 return resolver_
.Resolve(
656 base::Bind(&FtpNetworkTransaction::OnIOComplete
, base::Unretained(this)),
660 int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result
) {
662 next_state_
= STATE_CTRL_CONNECT
;
666 int FtpNetworkTransaction::DoCtrlConnect() {
667 next_state_
= STATE_CTRL_CONNECT_COMPLETE
;
668 ctrl_socket_
= socket_factory_
->CreateTransportClientSocket(
669 addresses_
, net_log_
.net_log(), net_log_
.source());
671 NetLog::TYPE_FTP_CONTROL_CONNECTION
,
672 ctrl_socket_
->NetLog().source().ToEventParametersCallback());
673 return ctrl_socket_
->Connect(io_callback_
);
676 int FtpNetworkTransaction::DoCtrlConnectComplete(int result
) {
678 // Put the peer's IP address and port into the response.
679 IPEndPoint ip_endpoint
;
680 result
= ctrl_socket_
->GetPeerAddress(&ip_endpoint
);
682 response_
.socket_address
= HostPortPair::FromIPEndPoint(ip_endpoint
);
683 next_state_
= STATE_CTRL_READ
;
685 if (ip_endpoint
.GetFamily() == ADDRESS_FAMILY_IPV4
) {
686 // Do not use EPSV for IPv4 connections. Some servers become confused
687 // and we time out while waiting to connect. PASV is perfectly fine for
688 // IPv4. Note that this blacklists IPv4 not to use EPSV instead of
689 // whitelisting IPv6 to use it, to make the code more future-proof:
690 // all future protocols should just use EPSV.
698 int FtpNetworkTransaction::DoCtrlRead() {
699 next_state_
= STATE_CTRL_READ_COMPLETE
;
700 return ctrl_socket_
->Read(read_ctrl_buf_
.get(), kCtrlBufLen
, io_callback_
);
703 int FtpNetworkTransaction::DoCtrlReadComplete(int result
) {
705 // Some servers (for example Pure-FTPd) apparently close the control
706 // connection when anonymous login is not permitted. For more details
707 // see http://crbug.com/25023.
708 if (command_sent_
== COMMAND_USER
&&
709 credentials_
.username() == base::ASCIIToUTF16("anonymous")) {
710 response_
.needs_auth
= true;
712 return Stop(ERR_EMPTY_RESPONSE
);
717 ctrl_response_buffer_
->ConsumeData(read_ctrl_buf_
->data(), result
);
719 if (!ctrl_response_buffer_
->ResponseAvailable()) {
720 // Read more data from the control socket.
721 next_state_
= STATE_CTRL_READ
;
725 return ProcessCtrlResponse();
728 int FtpNetworkTransaction::DoCtrlWrite() {
729 next_state_
= STATE_CTRL_WRITE_COMPLETE
;
731 return ctrl_socket_
->Write(
732 write_buf_
.get(), write_buf_
->BytesRemaining(), io_callback_
);
735 int FtpNetworkTransaction::DoCtrlWriteComplete(int result
) {
739 write_buf_
->DidConsume(result
);
740 if (write_buf_
->BytesRemaining() == 0) {
741 // Clear the write buffer.
743 write_command_buf_
= NULL
;
745 next_state_
= STATE_CTRL_READ
;
747 next_state_
= STATE_CTRL_WRITE
;
752 // FTP Commands and responses
755 int FtpNetworkTransaction::DoCtrlWriteUSER() {
756 std::string command
= "USER " + base::UTF16ToUTF8(credentials_
.username());
758 if (!IsValidFTPCommandString(command
))
759 return Stop(ERR_MALFORMED_IDENTITY
);
761 next_state_
= STATE_CTRL_READ
;
762 return SendFtpCommand(command
, "USER ***", COMMAND_USER
);
765 int FtpNetworkTransaction::ProcessResponseUSER(
766 const FtpCtrlResponse
& response
) {
767 switch (GetErrorClass(response
.status_code
)) {
769 next_state_
= STATE_CTRL_WRITE_SYST
;
771 case ERROR_CLASS_INFO_NEEDED
:
772 next_state_
= STATE_CTRL_WRITE_PASS
;
774 case ERROR_CLASS_TRANSIENT_ERROR
:
775 case ERROR_CLASS_PERMANENT_ERROR
:
776 response_
.needs_auth
= true;
777 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
780 return Stop(ERR_UNEXPECTED
);
786 int FtpNetworkTransaction::DoCtrlWritePASS() {
787 std::string command
= "PASS " + base::UTF16ToUTF8(credentials_
.password());
789 if (!IsValidFTPCommandString(command
))
790 return Stop(ERR_MALFORMED_IDENTITY
);
792 next_state_
= STATE_CTRL_READ
;
793 return SendFtpCommand(command
, "PASS ***", COMMAND_PASS
);
796 int FtpNetworkTransaction::ProcessResponsePASS(
797 const FtpCtrlResponse
& response
) {
798 switch (GetErrorClass(response
.status_code
)) {
800 next_state_
= STATE_CTRL_WRITE_SYST
;
802 case ERROR_CLASS_INFO_NEEDED
:
803 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
804 case ERROR_CLASS_TRANSIENT_ERROR
:
805 case ERROR_CLASS_PERMANENT_ERROR
:
806 response_
.needs_auth
= true;
807 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
810 return Stop(ERR_UNEXPECTED
);
816 int FtpNetworkTransaction::DoCtrlWriteSYST() {
817 std::string command
= "SYST";
818 next_state_
= STATE_CTRL_READ
;
819 return SendFtpCommand(command
, command
, COMMAND_SYST
);
822 int FtpNetworkTransaction::ProcessResponseSYST(
823 const FtpCtrlResponse
& response
) {
824 switch (GetErrorClass(response
.status_code
)) {
825 case ERROR_CLASS_INITIATED
:
826 return Stop(ERR_INVALID_RESPONSE
);
827 case ERROR_CLASS_OK
: {
828 // All important info should be on the first line.
829 std::string line
= response
.lines
[0];
830 // The response should be ASCII, which allows us to do case-insensitive
831 // comparisons easily. If it is not ASCII, we leave the system type
833 if (base::IsStringASCII(line
)) {
834 line
= base::StringToLowerASCII(line
);
836 // Remove all whitespace, to correctly handle cases like fancy "V M S"
837 // response instead of "VMS".
838 base::RemoveChars(line
, base::kWhitespaceASCII
, &line
);
840 // The "magic" strings we test for below have been gathered by an
841 // empirical study. VMS needs to come first because some VMS systems
842 // also respond with "UNIX emulation", which is not perfect. It is much
843 // more reliable to talk to these servers in their native language.
844 if (line
.find("vms") != std::string::npos
) {
845 system_type_
= SYSTEM_TYPE_VMS
;
846 } else if (line
.find("l8") != std::string::npos
||
847 line
.find("unix") != std::string::npos
||
848 line
.find("bsd") != std::string::npos
) {
849 system_type_
= SYSTEM_TYPE_UNIX
;
850 } else if (line
.find("win32") != std::string::npos
||
851 line
.find("windows") != std::string::npos
) {
852 system_type_
= SYSTEM_TYPE_WINDOWS
;
853 } else if (line
.find("os/2") != std::string::npos
) {
854 system_type_
= SYSTEM_TYPE_OS2
;
857 next_state_
= STATE_CTRL_WRITE_PWD
;
860 case ERROR_CLASS_INFO_NEEDED
:
861 return Stop(ERR_INVALID_RESPONSE
);
862 case ERROR_CLASS_TRANSIENT_ERROR
:
863 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
864 case ERROR_CLASS_PERMANENT_ERROR
:
865 // Server does not recognize the SYST command so proceed.
866 next_state_
= STATE_CTRL_WRITE_PWD
;
870 return Stop(ERR_UNEXPECTED
);
876 int FtpNetworkTransaction::DoCtrlWritePWD() {
877 std::string command
= "PWD";
878 next_state_
= STATE_CTRL_READ
;
879 return SendFtpCommand(command
, command
, COMMAND_PWD
);
882 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse
& response
) {
883 switch (GetErrorClass(response
.status_code
)) {
884 case ERROR_CLASS_INITIATED
:
885 return Stop(ERR_INVALID_RESPONSE
);
886 case ERROR_CLASS_OK
: {
887 // The info we look for should be on the first line.
888 std::string line
= response
.lines
[0];
890 return Stop(ERR_INVALID_RESPONSE
);
891 std::string::size_type quote_pos
= line
.find('"');
892 if (quote_pos
!= std::string::npos
) {
893 line
= line
.substr(quote_pos
+ 1);
894 quote_pos
= line
.find('"');
895 if (quote_pos
== std::string::npos
)
896 return Stop(ERR_INVALID_RESPONSE
);
897 line
= line
.substr(0, quote_pos
);
899 if (system_type_
== SYSTEM_TYPE_VMS
)
900 line
= FtpUtil::VMSPathToUnix(line
);
901 if (line
.length() && line
[line
.length() - 1] == '/')
902 line
.erase(line
.length() - 1);
903 current_remote_directory_
= line
;
904 next_state_
= STATE_CTRL_WRITE_TYPE
;
907 case ERROR_CLASS_INFO_NEEDED
:
908 return Stop(ERR_INVALID_RESPONSE
);
909 case ERROR_CLASS_TRANSIENT_ERROR
:
910 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
911 case ERROR_CLASS_PERMANENT_ERROR
:
912 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
915 return Stop(ERR_UNEXPECTED
);
921 int FtpNetworkTransaction::DoCtrlWriteTYPE() {
922 std::string command
= "TYPE ";
923 if (data_type_
== DATA_TYPE_ASCII
) {
925 } else if (data_type_
== DATA_TYPE_IMAGE
) {
929 return Stop(ERR_UNEXPECTED
);
931 next_state_
= STATE_CTRL_READ
;
932 return SendFtpCommand(command
, command
, COMMAND_TYPE
);
935 int FtpNetworkTransaction::ProcessResponseTYPE(
936 const FtpCtrlResponse
& response
) {
937 switch (GetErrorClass(response
.status_code
)) {
938 case ERROR_CLASS_INITIATED
:
939 return Stop(ERR_INVALID_RESPONSE
);
941 next_state_
= use_epsv_
? STATE_CTRL_WRITE_EPSV
: STATE_CTRL_WRITE_PASV
;
943 case ERROR_CLASS_INFO_NEEDED
:
944 return Stop(ERR_INVALID_RESPONSE
);
945 case ERROR_CLASS_TRANSIENT_ERROR
:
946 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
947 case ERROR_CLASS_PERMANENT_ERROR
:
948 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
951 return Stop(ERR_UNEXPECTED
);
957 int FtpNetworkTransaction::DoCtrlWriteEPSV() {
958 const std::string command
= "EPSV";
959 next_state_
= STATE_CTRL_READ
;
960 return SendFtpCommand(command
, command
, COMMAND_EPSV
);
963 int FtpNetworkTransaction::ProcessResponseEPSV(
964 const FtpCtrlResponse
& response
) {
965 switch (GetErrorClass(response
.status_code
)) {
966 case ERROR_CLASS_INITIATED
:
967 return Stop(ERR_INVALID_RESPONSE
);
969 if (!ExtractPortFromEPSVResponse( response
, &data_connection_port_
))
970 return Stop(ERR_INVALID_RESPONSE
);
971 if (data_connection_port_
< 1024 ||
972 !IsPortAllowedByFtp(data_connection_port_
))
973 return Stop(ERR_UNSAFE_PORT
);
974 next_state_
= STATE_DATA_CONNECT
;
976 case ERROR_CLASS_INFO_NEEDED
:
977 return Stop(ERR_INVALID_RESPONSE
);
978 case ERROR_CLASS_TRANSIENT_ERROR
:
979 case ERROR_CLASS_PERMANENT_ERROR
:
981 next_state_
= STATE_CTRL_WRITE_PASV
;
985 return Stop(ERR_UNEXPECTED
);
991 int FtpNetworkTransaction::DoCtrlWritePASV() {
992 std::string command
= "PASV";
993 next_state_
= STATE_CTRL_READ
;
994 return SendFtpCommand(command
, command
, COMMAND_PASV
);
997 int FtpNetworkTransaction::ProcessResponsePASV(
998 const FtpCtrlResponse
& response
) {
999 switch (GetErrorClass(response
.status_code
)) {
1000 case ERROR_CLASS_INITIATED
:
1001 return Stop(ERR_INVALID_RESPONSE
);
1002 case ERROR_CLASS_OK
:
1003 if (!ExtractPortFromPASVResponse(response
, &data_connection_port_
))
1004 return Stop(ERR_INVALID_RESPONSE
);
1005 if (data_connection_port_
< 1024 ||
1006 !IsPortAllowedByFtp(data_connection_port_
))
1007 return Stop(ERR_UNSAFE_PORT
);
1008 next_state_
= STATE_DATA_CONNECT
;
1010 case ERROR_CLASS_INFO_NEEDED
:
1011 return Stop(ERR_INVALID_RESPONSE
);
1012 case ERROR_CLASS_TRANSIENT_ERROR
:
1013 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1014 case ERROR_CLASS_PERMANENT_ERROR
:
1015 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1018 return Stop(ERR_UNEXPECTED
);
1024 int FtpNetworkTransaction::DoCtrlWriteRETR() {
1025 std::string command
= "RETR " + GetRequestPathForFtpCommand(false);
1026 next_state_
= STATE_CTRL_READ
;
1027 return SendFtpCommand(command
, command
, COMMAND_RETR
);
1030 int FtpNetworkTransaction::ProcessResponseRETR(
1031 const FtpCtrlResponse
& response
) {
1032 switch (GetErrorClass(response
.status_code
)) {
1033 case ERROR_CLASS_INITIATED
:
1034 // We want the client to start reading the response at this point.
1035 // It got here either through Start or RestartWithAuth. We want that
1036 // method to complete. Not setting next state here will make DoLoop exit
1037 // and in turn make Start/RestartWithAuth complete.
1038 resource_type_
= RESOURCE_TYPE_FILE
;
1040 case ERROR_CLASS_OK
:
1041 resource_type_
= RESOURCE_TYPE_FILE
;
1042 next_state_
= STATE_CTRL_WRITE_QUIT
;
1044 case ERROR_CLASS_INFO_NEEDED
:
1045 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1046 case ERROR_CLASS_TRANSIENT_ERROR
:
1047 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1048 case ERROR_CLASS_PERMANENT_ERROR
:
1049 // Code 550 means "Failed to open file". Other codes are unrelated,
1050 // like "Not logged in" etc.
1051 if (response
.status_code
!= 550 || resource_type_
== RESOURCE_TYPE_FILE
)
1052 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1054 // It's possible that RETR failed because the path is a directory.
1055 resource_type_
= RESOURCE_TYPE_DIRECTORY
;
1057 // We're going to try CWD next, but first send a PASV one more time,
1058 // because some FTP servers, including FileZilla, require that.
1059 // See http://crbug.com/25316.
1060 next_state_
= use_epsv_
? STATE_CTRL_WRITE_EPSV
: STATE_CTRL_WRITE_PASV
;
1064 return Stop(ERR_UNEXPECTED
);
1067 // We should be sure about our resource type now. Otherwise we risk
1068 // an infinite loop (RETR can later send CWD, and CWD can later send RETR).
1069 DCHECK_NE(RESOURCE_TYPE_UNKNOWN
, resource_type_
);
1075 int FtpNetworkTransaction::DoCtrlWriteSIZE() {
1076 std::string command
= "SIZE " + GetRequestPathForFtpCommand(false);
1077 next_state_
= STATE_CTRL_READ
;
1078 return SendFtpCommand(command
, command
, COMMAND_SIZE
);
1081 int FtpNetworkTransaction::ProcessResponseSIZE(
1082 const FtpCtrlResponse
& response
) {
1083 State state_after_size
;
1084 if (resource_type_
== RESOURCE_TYPE_FILE
)
1085 state_after_size
= STATE_CTRL_WRITE_RETR
;
1087 state_after_size
= STATE_CTRL_WRITE_CWD
;
1089 switch (GetErrorClass(response
.status_code
)) {
1090 case ERROR_CLASS_INITIATED
:
1091 next_state_
= state_after_size
;
1093 case ERROR_CLASS_OK
:
1094 if (response
.lines
.size() != 1)
1095 return Stop(ERR_INVALID_RESPONSE
);
1097 if (!base::StringToInt64(response
.lines
[0], &size
))
1098 return Stop(ERR_INVALID_RESPONSE
);
1100 return Stop(ERR_INVALID_RESPONSE
);
1102 // A successful response to SIZE does not mean the resource is a file.
1103 // Some FTP servers (for example, the qnx one) send a SIZE even for
1105 response_
.expected_content_size
= size
;
1107 next_state_
= state_after_size
;
1109 case ERROR_CLASS_INFO_NEEDED
:
1110 next_state_
= state_after_size
;
1112 case ERROR_CLASS_TRANSIENT_ERROR
:
1113 ResetDataConnectionAfterError(state_after_size
);
1115 case ERROR_CLASS_PERMANENT_ERROR
:
1116 // It's possible that SIZE failed because the path is a directory.
1117 if (resource_type_
== RESOURCE_TYPE_UNKNOWN
&&
1118 response
.status_code
!= 550) {
1119 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1122 ResetDataConnectionAfterError(state_after_size
);
1126 return Stop(ERR_UNEXPECTED
);
1133 int FtpNetworkTransaction::DoCtrlWriteCWD() {
1134 std::string command
= "CWD " + GetRequestPathForFtpCommand(true);
1135 next_state_
= STATE_CTRL_READ
;
1136 return SendFtpCommand(command
, command
, COMMAND_CWD
);
1139 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse
& response
) {
1140 // We should never issue CWD if we know the target resource is a file.
1141 DCHECK_NE(RESOURCE_TYPE_FILE
, resource_type_
);
1143 switch (GetErrorClass(response
.status_code
)) {
1144 case ERROR_CLASS_INITIATED
:
1145 return Stop(ERR_INVALID_RESPONSE
);
1146 case ERROR_CLASS_OK
:
1147 next_state_
= STATE_CTRL_WRITE_LIST
;
1149 case ERROR_CLASS_INFO_NEEDED
:
1150 return Stop(ERR_INVALID_RESPONSE
);
1151 case ERROR_CLASS_TRANSIENT_ERROR
:
1152 // Some FTP servers send response 451 (not a valid CWD response according
1153 // to RFC 959) instead of 550.
1154 if (response
.status_code
== 451)
1155 return ProcessResponseCWDNotADirectory();
1157 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1158 case ERROR_CLASS_PERMANENT_ERROR
:
1159 if (response
.status_code
== 550)
1160 return ProcessResponseCWDNotADirectory();
1162 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1165 return Stop(ERR_UNEXPECTED
);
1171 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() {
1172 if (resource_type_
== RESOURCE_TYPE_DIRECTORY
) {
1173 // We're assuming that the resource is a directory, but the server
1174 // says it's not true. The most probable interpretation is that it
1175 // doesn't exist (with FTP we can't be sure).
1176 return Stop(ERR_FILE_NOT_FOUND
);
1179 // We are here because SIZE failed and we are not sure what the resource
1180 // type is. It could still be file, and SIZE could fail because of
1181 // an access error (http://crbug.com/56734). Try RETR just to be sure.
1182 resource_type_
= RESOURCE_TYPE_FILE
;
1184 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR
);
1189 int FtpNetworkTransaction::DoCtrlWriteLIST() {
1190 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option
1191 // forces LIST output instead of NLST (which would be ambiguous for us
1193 std::string
command("LIST -l");
1194 if (system_type_
== SYSTEM_TYPE_VMS
)
1195 command
= "LIST *.*;0";
1197 next_state_
= STATE_CTRL_READ
;
1198 return SendFtpCommand(command
, command
, COMMAND_LIST
);
1201 int FtpNetworkTransaction::ProcessResponseLIST(
1202 const FtpCtrlResponse
& response
) {
1203 switch (GetErrorClass(response
.status_code
)) {
1204 case ERROR_CLASS_INITIATED
:
1205 // We want the client to start reading the response at this point.
1206 // It got here either through Start or RestartWithAuth. We want that
1207 // method to complete. Not setting next state here will make DoLoop exit
1208 // and in turn make Start/RestartWithAuth complete.
1209 response_
.is_directory_listing
= true;
1211 case ERROR_CLASS_OK
:
1212 response_
.is_directory_listing
= true;
1213 next_state_
= STATE_CTRL_WRITE_QUIT
;
1215 case ERROR_CLASS_INFO_NEEDED
:
1216 return Stop(ERR_INVALID_RESPONSE
);
1217 case ERROR_CLASS_TRANSIENT_ERROR
:
1218 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1219 case ERROR_CLASS_PERMANENT_ERROR
:
1220 return Stop(GetNetErrorCodeForFtpResponseCode(response
.status_code
));
1223 return Stop(ERR_UNEXPECTED
);
1229 int FtpNetworkTransaction::DoCtrlWriteQUIT() {
1230 std::string command
= "QUIT";
1231 next_state_
= STATE_CTRL_READ
;
1232 return SendFtpCommand(command
, command
, COMMAND_QUIT
);
1235 int FtpNetworkTransaction::ProcessResponseQUIT(
1236 const FtpCtrlResponse
& response
) {
1237 ctrl_socket_
->Disconnect();
1243 int FtpNetworkTransaction::DoDataConnect() {
1244 next_state_
= STATE_DATA_CONNECT_COMPLETE
;
1245 IPEndPoint ip_endpoint
;
1246 AddressList data_address
;
1247 // Connect to the same host as the control socket to prevent PASV port
1248 // scanning attacks.
1249 int rv
= ctrl_socket_
->GetPeerAddress(&ip_endpoint
);
1252 data_address
= AddressList::CreateFromIPAddress(
1253 ip_endpoint
.address(), data_connection_port_
);
1254 data_socket_
= socket_factory_
->CreateTransportClientSocket(
1255 data_address
, net_log_
.net_log(), net_log_
.source());
1257 NetLog::TYPE_FTP_DATA_CONNECTION
,
1258 data_socket_
->NetLog().source().ToEventParametersCallback());
1259 return data_socket_
->Connect(io_callback_
);
1262 int FtpNetworkTransaction::DoDataConnectComplete(int result
) {
1263 if (result
!= OK
&& use_epsv_
) {
1264 // It's possible we hit a broken server, sadly. They can break in different
1265 // ways. Some time out, some reset a connection. Fall back to PASV.
1266 // TODO(phajdan.jr): remember it for future transactions with this server.
1267 // TODO(phajdan.jr): write a test for this code path.
1269 next_state_
= STATE_CTRL_WRITE_PASV
;
1273 // Only record the connection error after we've applied all our fallbacks.
1274 // We want to capture the final error, one we're not going to recover from.
1275 RecordDataConnectionError(result
);
1278 return Stop(result
);
1280 next_state_
= state_after_data_connect_complete_
;
1284 int FtpNetworkTransaction::DoDataRead() {
1285 DCHECK(read_data_buf_
.get());
1286 DCHECK_GT(read_data_buf_len_
, 0);
1288 if (data_socket_
== NULL
|| !data_socket_
->IsConnected()) {
1289 // If we don't destroy the data socket completely, some servers will wait
1290 // for us (http://crbug.com/21127). The half-closed TCP connection needs
1291 // to be closed on our side too.
1292 data_socket_
.reset();
1294 if (ctrl_socket_
->IsConnected()) {
1295 // Wait for the server's response, we should get it before sending QUIT.
1296 next_state_
= STATE_CTRL_READ
;
1300 // We are no longer connected to the server, so just finish the transaction.
1304 next_state_
= STATE_DATA_READ_COMPLETE
;
1305 read_data_buf_
->data()[0] = 0;
1306 return data_socket_
->Read(
1307 read_data_buf_
.get(), read_data_buf_len_
, io_callback_
);
1310 int FtpNetworkTransaction::DoDataReadComplete(int result
) {
1314 // We're using a histogram as a group of counters, with one bucket for each
1315 // enumeration value. We're only interested in the values of the counters.
1316 // Ignore the shape, average, and standard deviation of the histograms because
1317 // they are meaningless.
1319 // We use two histograms. In the first histogram we tally whether the user has
1320 // seen an error of that type during the session. In the second histogram we
1321 // tally the total number of times the users sees each errer.
1322 void FtpNetworkTransaction::RecordDataConnectionError(int result
) {
1323 // Gather data for http://crbug.com/3073. See how many users have trouble
1324 // establishing FTP data connection in passive FTP mode.
1326 // Data connection successful.
1329 // Local firewall blocked the connection.
1330 NET_ERROR_ACCESS_DENIED
= 1,
1332 // Connection timed out.
1333 NET_ERROR_TIMED_OUT
= 2,
1335 // Connection has been estabilished, but then got broken (either reset
1337 NET_ERROR_CONNECTION_BROKEN
= 3,
1339 // Connection has been refused.
1340 NET_ERROR_CONNECTION_REFUSED
= 4,
1342 // No connection to the internet.
1343 NET_ERROR_INTERNET_DISCONNECTED
= 5,
1345 // Could not reach the destination address.
1346 NET_ERROR_ADDRESS_UNREACHABLE
= 6,
1348 // A programming error in our network stack.
1349 NET_ERROR_UNEXPECTED
= 7,
1351 // Other kind of error.
1352 NET_ERROR_OTHER
= 20,
1354 NUM_OF_NET_ERROR_TYPES
1358 type
= NET_ERROR_OK
;
1360 case ERR_ACCESS_DENIED
:
1361 case ERR_NETWORK_ACCESS_DENIED
:
1362 type
= NET_ERROR_ACCESS_DENIED
;
1365 type
= NET_ERROR_TIMED_OUT
;
1367 case ERR_CONNECTION_ABORTED
:
1368 case ERR_CONNECTION_RESET
:
1369 case ERR_CONNECTION_CLOSED
:
1370 type
= NET_ERROR_CONNECTION_BROKEN
;
1372 case ERR_CONNECTION_FAILED
:
1373 case ERR_CONNECTION_REFUSED
:
1374 type
= NET_ERROR_CONNECTION_REFUSED
;
1376 case ERR_INTERNET_DISCONNECTED
:
1377 type
= NET_ERROR_INTERNET_DISCONNECTED
;
1379 case ERR_ADDRESS_INVALID
:
1380 case ERR_ADDRESS_UNREACHABLE
:
1381 type
= NET_ERROR_ADDRESS_UNREACHABLE
;
1383 case ERR_UNEXPECTED
:
1384 type
= NET_ERROR_UNEXPECTED
;
1387 type
= NET_ERROR_OTHER
;
1390 static bool had_error_type
[NUM_OF_NET_ERROR_TYPES
];
1392 DCHECK(type
>= 0 && type
< NUM_OF_NET_ERROR_TYPES
);
1393 if (!had_error_type
[type
]) {
1394 had_error_type
[type
] = true;
1395 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened",
1396 type
, NUM_OF_NET_ERROR_TYPES
);
1398 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount",
1399 type
, NUM_OF_NET_ERROR_TYPES
);