ftp_network_transaction.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Copyright (c) 2012 The Chromium Authors. All rights reserved. 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Use of this source code is governed by a BSD-style license that can be 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// found in the LICENSE file. 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/ftp/ftp_network_transaction.h" 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt 7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#include "base/bind.h" 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/bind_helpers.h" 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/compiler_specific.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/metrics/histogram.h" 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/strings/string_number_conversions.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/strings/string_util.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/strings/string_split.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/strings/utf_string_conversions.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base/values.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/base/address_list.h" 17b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt#include "net/base/connection_type_histograms.h" 18cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt#include "net/base/escape.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/base/net_errors.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/base/net_log.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/base/net_util.h" 221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "net/ftp/ftp_network_session.h" 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/ftp/ftp_request_info.h" 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/ftp/ftp_util.h" 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/socket/client_socket_factory.h" 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "net/socket/stream_socket.h" 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char kCRLF[] = "\r\n"; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst int kCtrlBufLen = 1024; 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnamespace { 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Returns true if |input| can be safely used as a part of FTP command. 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtbool IsValidFTPCommandString(const std::string& input) { 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // RFC 959 only allows ASCII strings, but at least Firefox can send non-ASCII 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // characters in the command if the request path contains them. To be 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // compatible, we do the same and allow non-ASCII characters in a command. 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Protect agains newline injection attack. 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (input.find_first_of("\r\n") != std::string::npos) 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return false; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return true; 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 4768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtenum ErrorClass { 4868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // The requested action was initiated. The client should expect another 4968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // reply before issuing the next command. 5068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt ERROR_CLASS_INITIATED, 5168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 5268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // The requested action has been successfully completed. 5368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt ERROR_CLASS_OK, 5468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 5568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // The command has been accepted, but to complete the operation, more 5668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // information must be sent by the client. 5768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt ERROR_CLASS_INFO_NEEDED, 5868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 5968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // The command was not accepted and the requested action did not take place. 6068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // This condition is temporary, and the client is encouraged to restart the 6168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // command sequence. 6268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt ERROR_CLASS_TRANSIENT_ERROR, 6368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 6468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // The command was not accepted and the requested action did not take place. 6568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // This condition is rather permanent, and the client is discouraged from 6668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt // repeating the exact request. 6768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt ERROR_CLASS_PERMANENT_ERROR, 6868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt}; 6968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt 7068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt// Returns the error class for given response code. Caller should ensure 7168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt// that |response_code| is in range 100-599. 7268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry ShmidtErrorClass GetErrorClass(int response_code) { 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response_code >= 100 && response_code <= 199) 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ERROR_CLASS_INITIATED; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response_code >= 200 && response_code <= 299) 77cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt return ERROR_CLASS_OK; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response_code >= 300 && response_code <= 399) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ERROR_CLASS_INFO_NEEDED; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response_code >= 400 && response_code <= 499) 83b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return ERROR_CLASS_TRANSIENT_ERROR; 84b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 85b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (response_code >= 500 && response_code <= 599) 86b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return ERROR_CLASS_PERMANENT_ERROR; 87b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt 88b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt // We should not be called on invalid error codes. 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED() << response_code; 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ERROR_CLASS_PERMANENT_ERROR; 91c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt} 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Returns network error code for received FTP |response_code|. 94c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidtint GetNetErrorCodeForFtpResponseCode(int response_code) { 95c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt switch (response_code) { 961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt case 421: 971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return net::ERR_FTP_SERVICE_UNAVAILABLE; 98c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt case 426: 991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return net::ERR_FTP_TRANSFER_ABORTED; 100c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt case 450: 1011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return net::ERR_FTP_FILE_BUSY; 102c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt case 500: 10304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case 501: 1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return net::ERR_FTP_SYNTAX_ERROR; 1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt case 502: 1061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt case 504: 107c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt return net::ERR_FTP_COMMAND_NOT_SUPPORTED; 108c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt case 503: 109c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt return net::ERR_FTP_BAD_COMMAND_SEQUENCE; 11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return net::ERR_FTP_FAILED; 11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt// From RFC 2428 Section 3: 11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt// The text returned in response to the EPSV command MUST be: 11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt// <some text> (<d><d><d><tcp-port><d>) 11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt// <d> is a delimiter character, ideally to be | 11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtbool ExtractPortFromEPSVResponse(const net::FtpCtrlResponse& response, 120c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt int* port) { 12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (response.lines.size() != 1) 12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return false; 12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt const char* ptr = response.lines[0].c_str(); 12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt while (*ptr && *ptr != '(') 12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt ++ptr; 12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!*ptr) 12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return false; 12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt char sep = *(++ptr); 12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!sep || isdigit(sep) || *(++ptr) != sep || *(++ptr) != sep) 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return false; 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!isdigit(*(++ptr))) 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return false; 1331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *port = *ptr - '0'; 1341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while (isdigit(*(++ptr))) { 1351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *port *= 10; 1361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *port += *ptr - '0'; 1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (*ptr != sep) 1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return false; 1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return true; 1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt// There are two way we can receive IP address and port. 14568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt// (127,0,0,1,23,21) IP address and port encapsulated in (). 14668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt// 127,0,0,1,23,21 IP address and port without (). 14768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt// 14868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt// See RFC 959, Section 4.1.2 14968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtbool ExtractPortFromPASVResponse(const net::FtpCtrlResponse& response, 1501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int* port) { 151c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt if (response.lines.size() != 1) 152c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt return false; 153c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string line(response.lines[0]); 15534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt if (!IsStringASCII(line)) 15634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt return false; 15734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt if (line.length() < 2) 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return false; 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t paren_pos = line.find('('); 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (paren_pos == std::string::npos) { 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Find the first comma and use it to locate the beginning 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // of the response data. 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t comma_pos = line.find(','); 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (comma_pos == std::string::npos) 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return false; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t space_pos = line.rfind(' ', comma_pos); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (space_pos != std::string::npos) 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line = line.substr(space_pos + 1); 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Remove the parentheses and use the text inside them. 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t closing_paren_pos = line.rfind(')'); 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (closing_paren_pos == std::string::npos) 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return false; 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (closing_paren_pos <= paren_pos) 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return false; 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line = line.substr(paren_pos + 1, closing_paren_pos - paren_pos - 1); 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // Split the line into comma-separated pieces and extract 1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // the last two. 184391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt std::vector<std::string> pieces; 185cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt base::SplitString(line, ',', &pieces); 186cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (pieces.size() != 6) 187cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return false; 188cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 189cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // Ignore the IP address supplied in the response. We are always going 190cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // to connect back to the same server to prevent FTP PASV port scanning. 191cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt int p0, p1; 192cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (!base::StringToInt(pieces[4], &p0)) 193cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return false; 194cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (!base::StringToInt(pieces[5], &p1)) 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return false; 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *port = (p0 << 8) + p1; 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return true; 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} // namespace 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnamespace net { 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 20504949598a23f501be6eec21697465fd46a28840aDmitry ShmidtFtpNetworkTransaction::FtpNetworkTransaction( 20604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt FtpNetworkSession* session, 2071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt ClientSocketFactory* socket_factory) 2081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt : command_sent_(COMMAND_NONE), 2091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt io_callback_(base::Bind(&FtpNetworkTransaction::OnIOComplete, 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base::Unretained(this))), 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt session_(session), 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt request_(NULL), 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resolver_(session->host_resolver()), 214d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt read_data_buf_len_(0), 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt last_error_(OK), 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt system_type_(SYSTEM_TYPE_UNKNOWN), 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Use image (binary) transfer by default. It should always work, 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // whereas the ascii transfer may damage binary data. 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data_type_(DATA_TYPE_IMAGE), 221d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt resource_type_(RESOURCE_TYPE_UNKNOWN), 222d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt use_epsv_(true), 2231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt data_connection_port_(0), 2241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt socket_factory_(socket_factory), 2251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt next_state_(STATE_NONE), 2261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE) {} 2271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry ShmidtFtpNetworkTransaction::~FtpNetworkTransaction() { 2291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint FtpNetworkTransaction::Stop(int error) { 2321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (command_sent_ == COMMAND_QUIT) 2331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return error; 2341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt next_state_ = STATE_CTRL_WRITE_QUIT; 2361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt last_error_ = error; 2371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return OK; 2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::RestartIgnoringLastError( 24104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const CompletionCallback& callback) { 24204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return ERR_NOT_IMPLEMENTED; 24304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 24404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 24504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, 2467a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt const CompletionCallback& callback, 2477a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt const BoundNetLog& net_log) { 2487a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt net_log_ = net_log; 2497a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt request_ = request_info; 2507a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt 2517a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 2527a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt 25304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (request_->url.has_username()) { 254a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt base::string16 username; 255a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt base::string16 password; 256a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt GetIdentityFromURL(request_->url, &username, &password); 257a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt credentials_.Set(username, password); 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt credentials_.Set(base::ASCIIToUTF16("anonymous"), 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base::ASCIIToUTF16("chrome@example.com")); 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DetectTypecode(); 2641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_RESOLVE_HOST; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int rv = DoLoop(OK); 2671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (rv == ERR_IO_PENDING) 2681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt user_callback_ = callback; 2691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return rv; 2701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint FtpNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials, 2731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const CompletionCallback& callback) { 2741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt ResetStateForRestart(); 2751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt credentials_ = credentials; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt next_state_ = STATE_CTRL_RESOLVE_HOST; 2791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int rv = DoLoop(OK); 2801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (rv == ERR_IO_PENDING) 2811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt user_callback_ = callback; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return rv; 2831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 2841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint FtpNetworkTransaction::Read(IOBuffer* buf, 2861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt int buf_len, 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const CompletionCallback& callback) { 2888da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt DCHECK(buf); 2898da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt DCHECK_GT(buf_len, 0); 290fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 291fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt read_data_buf_ = buf; 292fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt read_data_buf_len_ = buf_len; 2938da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt 2948da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt next_state_ = STATE_DATA_READ; 2958da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt int rv = DoLoop(OK); 2968da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt if (rv == ERR_IO_PENDING) 2978da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt user_callback_ = callback; 2988da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt return rv; 2998da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt} 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const { 3021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return &response_; 3031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 3041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtLoadState FtpNetworkTransaction::GetLoadState() const { 3061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (next_state_ == STATE_CTRL_RESOLVE_HOST_COMPLETE) 3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return LOAD_STATE_RESOLVING_HOST; 3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (next_state_ == STATE_CTRL_CONNECT_COMPLETE || 3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt next_state_ == STATE_DATA_CONNECT_COMPLETE) 311a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return LOAD_STATE_CONNECTING; 3121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 3131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (next_state_ == STATE_DATA_READ_COMPLETE) 3141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return LOAD_STATE_READING_RESPONSE; 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 31604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (command_sent_ == COMMAND_RETR && read_data_buf_.get()) 31704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return LOAD_STATE_READING_RESPONSE; 31804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 31904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (command_sent_ == COMMAND_QUIT) 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return LOAD_STATE_IDLE; 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (command_sent_ != COMMAND_NONE) 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return LOAD_STATE_SENDING_REQUEST; 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return LOAD_STATE_IDLE; 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtuint64 FtpNetworkTransaction::GetUploadProgress() const { 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid FtpNetworkTransaction::ResetStateForRestart() { 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt command_sent_ = COMMAND_NONE; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt user_callback_.Reset(); 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt response_ = FtpResponseInfo(); 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt read_data_buf_ = NULL; 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt read_data_buf_len_ = 0; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (write_buf_.get()) 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_buf_->SetOffset(0); 34204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt last_error_ = OK; 3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt data_connection_port_ = 0; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ctrl_socket_.reset(); 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data_socket_.reset(); 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_NONE; 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) { 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // The server _might_ have reset the data connection 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS: 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // "The server MUST close the data connection under the following 3540ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt // conditions: 3550ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt // ... 3560ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt // 5. An irrecoverable error condition occurs.") 3570ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt // 3580ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt // It is ambiguous what an irrecoverable error condition is, 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // so we take no chances. 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt state_after_data_connect_complete_ = next_state; 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid FtpNetworkTransaction::DoCallback(int rv) { 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv != ERR_IO_PENDING); 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(!user_callback_.is_null()); 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Since Run may result in Read being called, clear callback_ up front. 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt CompletionCallback c = user_callback_; 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt user_callback_.Reset(); 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c.Run(rv); 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3741846323989242844f0e857458a8939fa5836429cDmitry Shmidtvoid FtpNetworkTransaction::OnIOComplete(int result) { 3751846323989242844f0e857458a8939fa5836429cDmitry Shmidt int rv = DoLoop(result); 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (rv != ERR_IO_PENDING) 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DoCallback(rv); 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::ProcessCtrlResponse() { 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int rv = OK; 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (command_sent_) { 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_NONE: 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // TODO(phajdan.jr): Check for errors in the welcome message. 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_USER; 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_USER: 39075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen rv = ProcessResponseUSER(response); 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_PASS: 39375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen rv = ProcessResponsePASS(response); 39475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen break; 39575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen case COMMAND_SYST: 39675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen rv = ProcessResponseSYST(response); 39775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen break; 39875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen case COMMAND_PWD: 39975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen rv = ProcessResponsePWD(response); 40075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen break; 40175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen case COMMAND_TYPE: 40275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen rv = ProcessResponseTYPE(response); 40375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen break; 40475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen case COMMAND_EPSV: 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = ProcessResponseEPSV(response); 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_PASV: 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = ProcessResponsePASV(response); 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_SIZE: 4111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rv = ProcessResponseSIZE(response); 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt case COMMAND_RETR: 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = ProcessResponseRETR(response); 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_CWD: 417391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt rv = ProcessResponseCWD(response); 418391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 419391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case COMMAND_LIST: 420391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt rv = ProcessResponseLIST(response); 421391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 422391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case COMMAND_QUIT: 423391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt rv = ProcessResponseQUIT(response); 424391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt break; 425391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt default: 426391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; 427391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt return ERR_UNEXPECTED; 428391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt } 429391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // We may get multiple responses for some commands, 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // see http://crbug.com/18036. 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) { 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt response = ctrl_response_buffer_->PopResponse(); 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (command_sent_) { 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_RETR: 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = ProcessResponseRETR(response); 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case COMMAND_LIST: 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = ProcessResponseLIST(response); 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Multiple responses for other commands are invalid. 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return rv; 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 45104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt// Used to prepare and send FTP command. 45204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint FtpNetworkTransaction::SendFtpCommand(const std::string& command, 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const std::string& command_for_log, 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Command cmd) { 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // If we send a new command when we still have unprocessed responses 45604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt // for previous commands, the response receiving code will have no way to know 45704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt // which responses are for which command. 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(!ctrl_response_buffer_->ResponseAvailable()); 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(!write_command_buf_.get()); 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(!write_buf_.get()); 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!IsValidFTPCommandString(command)) { 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Callers should validate the command themselves and return a more specific 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // error code. 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt command_sent_ = cmd; 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_command_buf_ = new IOBufferWithSize(command.length() + 2); 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_buf_ = new DrainableIOBuffer(write_command_buf_.get(), 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_command_buf_->size()); 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memcpy(write_command_buf_->data(), command.data(), command.length()); 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt net_log_.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT, 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NetLog::StringCallback("command", &command_for_log)); 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE; 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstd::string FtpNetworkTransaction::GetRequestPathForFtpCommand( 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bool is_directory) const { 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string path(current_remote_directory_); 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (request_->url.has_path()) { 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string gurl_path(request_->url.path()); 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string::size_type pos = gurl_path.rfind(';'); 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos != std::string::npos) 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt gurl_path.resize(pos); 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt path.append(gurl_path); 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Make sure that if the path is expected to be a file, it won't end 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // with a trailing slash. 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/') 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt path.erase(path.length() - 1); 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt UnescapeRule::URL_SPECIAL_CHARS; 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // This may unescape to non-ASCII characters, but we allow that. See the 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // comment for IsValidFTPCommandString. 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt path = net::UnescapeURLComponent(path, unescape_rules); 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (system_type_ == SYSTEM_TYPE_VMS) { 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (is_directory) 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt path = FtpUtil::UnixDirectoryPathToVMS(path); 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt path = FtpUtil::UnixFilePathToVMS(path); 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(IsValidFTPCommandString(path)); 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return path; 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid FtpNetworkTransaction::DetectTypecode() { 520b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (!request_->url.has_path()) 521b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt return; 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string gurl_path(request_->url.path()); 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path. 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string::size_type pos = gurl_path.rfind(';'); 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == std::string::npos) 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string typecode_string(gurl_path.substr(pos)); 529fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt if (typecode_string == ";type=a") { 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data_type_ = DATA_TYPE_ASCII; 531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt resource_type_ = RESOURCE_TYPE_FILE; 532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } else if (typecode_string == ";type=i") { 533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt data_type_ = DATA_TYPE_IMAGE; 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resource_type_ = RESOURCE_TYPE_FILE; 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (typecode_string == ";type=d") { 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resource_type_ = RESOURCE_TYPE_DIRECTORY; 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 538fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt} 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoLoop(int result) { 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(next_state_ != STATE_NONE); 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int rv = result; 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt do { 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt State state = next_state_; 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_NONE; 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (state) { 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_RESOLVE_HOST: 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlResolveHost(); 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_RESOLVE_HOST_COMPLETE: 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlResolveHostComplete(rv); 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_CONNECT: 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlConnect(); 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_CONNECT_COMPLETE: 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlConnectComplete(rv); 5611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt break; 5621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt case STATE_CTRL_READ: 563444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt DCHECK(rv == OK); 564444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt rv = DoCtrlRead(); 565444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt break; 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_READ_COMPLETE: 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlReadComplete(rv); 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE: 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWrite(); 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 57361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case STATE_CTRL_WRITE_COMPLETE: 57461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt rv = DoCtrlWriteComplete(rv); 57561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 57661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt case STATE_CTRL_WRITE_USER: 5771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt DCHECK(rv == OK); 578cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt rv = DoCtrlWriteUSER(); 579cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt break; 5801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt case STATE_CTRL_WRITE_PASS: 5811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt DCHECK(rv == OK); 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWritePASS(); 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_SYST: 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWriteSYST(); 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_PWD: 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 590cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt rv = DoCtrlWritePWD(); 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 592cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt case STATE_CTRL_WRITE_TYPE: 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWriteTYPE(); 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_EPSV: 59761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt DCHECK(rv == OK); 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWriteEPSV(); 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_PASV: 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWritePASV(); 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_RETR: 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWriteRETR(); 607cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt break; 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_SIZE: 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWriteSIZE(); 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_CWD: 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 614497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt rv = DoCtrlWriteCWD(); 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_LIST: 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWriteLIST(); 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_CTRL_WRITE_QUIT: 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoCtrlWriteQUIT(); 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_DATA_CONNECT: 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK(rv == OK); 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoDataConnect(); 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 628391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt case STATE_DATA_CONNECT_COMPLETE: 629391c59f0632df8db1c325da1d31d479b2eedce45Dmitry Shmidt rv = DoDataConnectComplete(rv); 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 63104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case STATE_DATA_READ: 63204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt DCHECK(rv == OK); 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoDataRead(); 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case STATE_DATA_READ_COMPLETE: 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = DoDataReadComplete(rv); 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED() << "bad state"; 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rv = ERR_UNEXPECTED; 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 643b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return rv; 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlResolveHost() { 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE; 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url)); 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // No known referrer. 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return resolver_.Resolve( 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt info, 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DEFAULT_PRIORITY, 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &addresses_, 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)), 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt net_log_); 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (result == OK) 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_CONNECT; 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return result; 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlConnect() { 667b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt next_state_ = STATE_CTRL_CONNECT_COMPLETE; 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ctrl_socket_ = socket_factory_->CreateTransportClientSocket( 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addresses_, net_log_.net_log(), net_log_.source()); 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt net_log_.AddEvent( 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NetLog::TYPE_FTP_CONTROL_CONNECTION, 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ctrl_socket_->NetLog().source().ToEventParametersCallback()); 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ctrl_socket_->Connect(io_callback_); 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlConnectComplete(int result) { 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (result == OK) { 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Put the peer's IP address and port into the response. 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IPEndPoint ip_endpoint; 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt result = ctrl_socket_->GetPeerAddress(&ip_endpoint); 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (result == OK) { 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt response_.socket_address = HostPortPair::FromIPEndPoint(ip_endpoint); 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ip_endpoint.GetFamily() == ADDRESS_FAMILY_IPV4) { 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Do not use EPSV for IPv4 connections. Some servers become confused 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // and we time out while waiting to connect. PASV is perfectly fine for 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // IPv4. Note that this blacklists IPv4 not to use EPSV instead of 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // whitelisting IPv6 to use it, to make the code more future-proof: 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // all future protocols should just use EPSV. 6911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt use_epsv_ = false; 6921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return result; 696fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt} 697fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt 6981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint FtpNetworkTransaction::DoCtrlRead() { 6991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt next_state_ = STATE_CTRL_READ_COMPLETE; 7001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return ctrl_socket_->Read(read_ctrl_buf_.get(), kCtrlBufLen, io_callback_); 7011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} 7021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 7031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint FtpNetworkTransaction::DoCtrlReadComplete(int result) { 7041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (result == 0) { 7051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // Some servers (for example Pure-FTPd) apparently close the control 7061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // connection when anonymous login is not permitted. For more details 7071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // see http://crbug.com/25023. 7081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (command_sent_ == COMMAND_USER && 7091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt credentials_.username() == base::ASCIIToUTF16("anonymous")) { 7101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt response_.needs_auth = true; 7111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 7121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return Stop(ERR_EMPTY_RESPONSE); 7131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 7141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt if (result < 0) 7151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt return Stop(result); 7161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 7171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result); 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ctrl_response_buffer_->ResponseAvailable()) { 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Read more data from the control socket. 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ProcessCtrlResponse(); 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWrite() { 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_COMPLETE; 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ctrl_socket_->Write( 7321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt write_buf_.get(), write_buf_->BytesRemaining(), io_callback_); 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteComplete(int result) { 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (result < 0) 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return result; 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_buf_->DidConsume(result); 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (write_buf_->BytesRemaining() == 0) { 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Clear the write buffer. 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_buf_ = NULL; 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt write_command_buf_ = NULL; 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE; 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// FTP Commands and responses 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// USER Command. 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteUSER() { 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string command = "USER " + base::UTF16ToUTF8(credentials_.username()); 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!IsValidFTPCommandString(command)) 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_MALFORMED_IDENTITY); 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, "USER ***", COMMAND_USER); 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::ProcessResponseUSER( 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const FtpCtrlResponse& response) { 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_OK: 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_SYST; 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_PASS; 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 77504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt response_.needs_auth = true; 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// PASS command. 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWritePASS() { 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string command = "PASS " + base::UTF16ToUTF8(credentials_.password()); 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!IsValidFTPCommandString(command)) 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_MALFORMED_IDENTITY); 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, "PASS ***", COMMAND_PASS); 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 795d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt 796d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtint FtpNetworkTransaction::ProcessResponsePASS( 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const FtpCtrlResponse& response) { 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_OK: 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_SYST; 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 8051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt response_.needs_auth = true; 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 811d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt } 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// SYST command. 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteSYST() { 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string command = "SYST"; 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, command, COMMAND_SYST); 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::ProcessResponseSYST( 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const FtpCtrlResponse& response) { 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INITIATED: 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_OK: { 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // All important info should be on the first line. 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string line = response.lines[0]; 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // The response should be ASCII, which allows us to do case-insensitive 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // comparisons easily. If it is not ASCII, we leave the system type 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // as unknown. 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (IsStringASCII(line)) { 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line = StringToLowerASCII(line); 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Remove all whitespace, to correctly handle cases like fancy "V M S" 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // response instead of "VMS". 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base::RemoveChars(line, base::kWhitespaceASCII, &line); 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // The "magic" strings we test for below have been gathered by an 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // empirical study. VMS needs to come first because some VMS systems 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // also respond with "UNIX emulation", which is not perfect. It is much 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // more reliable to talk to these servers in their native language. 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (line.find("vms") != std::string::npos) { 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt system_type_ = SYSTEM_TYPE_VMS; 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (line.find("l8") != std::string::npos || 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line.find("unix") != std::string::npos || 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line.find("bsd") != std::string::npos) { 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt system_type_ = SYSTEM_TYPE_UNIX; 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (line.find("win32") != std::string::npos || 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line.find("windows") != std::string::npos) { 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt system_type_ = SYSTEM_TYPE_WINDOWS; 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (line.find("os/2") != std::string::npos) { 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt system_type_ = SYSTEM_TYPE_OS2; 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_PWD; 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Server does not recognize the SYST command so proceed. 8661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt next_state_ = STATE_CTRL_WRITE_PWD; 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// PWD command. 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWritePWD() { 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string command = "PWD"; 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, command, COMMAND_PWD); 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INITIATED: 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_OK: { 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // The info we look for should be on the first line. 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string line = response.lines[0]; 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (line.empty()) 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string::size_type quote_pos = line.find('"'); 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (quote_pos != std::string::npos) { 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line = line.substr(quote_pos + 1); 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt quote_pos = line.find('"'); 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (quote_pos == std::string::npos) 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line = line.substr(0, quote_pos); 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (system_type_ == SYSTEM_TYPE_VMS) 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line = FtpUtil::VMSPathToUnix(line); 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (line.length() && line[line.length() - 1] == '/') 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt line.erase(line.length() - 1); 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt current_remote_directory_ = line; 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_TYPE; 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// TYPE command. 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteTYPE() { 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string command = "TYPE "; 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_type_ == DATA_TYPE_ASCII) { 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt command += "A"; 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (data_type_ == DATA_TYPE_IMAGE) { 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt command += "I"; 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, command, COMMAND_TYPE); 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 934f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 935f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtint FtpNetworkTransaction::ProcessResponseTYPE( 936f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt const FtpCtrlResponse& response) { 937f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 938f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt case ERROR_CLASS_INITIATED: 939f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 940f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt case ERROR_CLASS_OK: 941f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 942f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt break; 943f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 944f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 945f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 946f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 947f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 948f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 949f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt default: 950f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt NOTREACHED(); 951f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return Stop(ERR_UNEXPECTED); 952f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt } 953f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return OK; 954f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt} 955f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt 956f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt// EPSV command 957f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteEPSV() { 958f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt const std::string command = "EPSV"; 959f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt next_state_ = STATE_CTRL_READ; 960cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return SendFtpCommand(command, command, COMMAND_EPSV); 961cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt} 962cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 963cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint FtpNetworkTransaction::ProcessResponseEPSV( 964cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt const FtpCtrlResponse& response) { 965cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt switch (GetErrorClass(response.status_code)) { 966cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt case ERROR_CLASS_INITIATED: 967cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 968cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt case ERROR_CLASS_OK: 969cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (!ExtractPortFromEPSVResponse( response, &data_connection_port_)) 970cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 971cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (data_connection_port_ < 1024 || 972cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt !IsPortAllowedByFtp(data_connection_port_)) 973f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt return Stop(ERR_UNSAFE_PORT); 974f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt next_state_ = STATE_DATA_CONNECT; 9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt use_epsv_ = false; 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_PASV; 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// PASV command 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWritePASV() { 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string command = "PASV"; 9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, command, COMMAND_PASV); 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::ProcessResponsePASV( 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const FtpCtrlResponse& response) { 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INITIATED: 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_OK: 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ExtractPortFromPASVResponse(response, &data_connection_port_)) 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data_connection_port_ < 1024 || 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !IsPortAllowedByFtp(data_connection_port_)) 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNSAFE_PORT); 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_DATA_CONNECT; 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 101004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 101104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 101204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 101304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 101404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 101504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 101604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 101704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NOTREACHED(); 101804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return Stop(ERR_UNEXPECTED); 101904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 102004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return OK; 102104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 102204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 102304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt// RETR command 102404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteRETR() { 102504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt std::string command = "RETR " + GetRequestPathForFtpCommand(false); 102604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt next_state_ = STATE_CTRL_READ; 102704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return SendFtpCommand(command, command, COMMAND_RETR); 102804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 102904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::ProcessResponseRETR( 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const FtpCtrlResponse& response) { 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INITIATED: 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // We want the client to start reading the response at this point. 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // It got here either through Start or RestartWithAuth. We want that 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // method to complete. Not setting next state here will make DoLoop exit 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // and in turn make Start/RestartWithAuth complete. 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resource_type_ = RESOURCE_TYPE_FILE; 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_OK: 10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resource_type_ = RESOURCE_TYPE_FILE; 10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_QUIT; 10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Code 550 means "Failed to open file". Other codes are unrelated, 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // like "Not logged in" etc. 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // It's possible that RETR failed because the path is a directory. 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resource_type_ = RESOURCE_TYPE_DIRECTORY; 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // We're going to try CWD next, but first send a PASV one more time, 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // because some FTP servers, including FileZilla, require that. 10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // See http://crbug.com/25316. 10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // We should be sure about our resource type now. Otherwise we risk 10681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt // an infinite loop (RETR can later send CWD, and CWD can later send RETR). 10691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); 10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1074cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt// SIZE command 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteSIZE() { 1076cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, command, COMMAND_SIZE); 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint FtpNetworkTransaction::ProcessResponseSIZE( 10821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt const FtpCtrlResponse& response) { 10831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt State state_after_size; 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (resource_type_ == RESOURCE_TYPE_FILE) 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt state_after_size = STATE_CTRL_WRITE_RETR; 10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt state_after_size = STATE_CTRL_WRITE_CWD; 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 1090e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt case ERROR_CLASS_INITIATED: 1091e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt next_state_ = state_after_size; 1092e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt break; 1093e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt case ERROR_CLASS_OK: 1094e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt if (response.lines.size() != 1) 1095e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 1096e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt int64 size; 1097e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt if (!base::StringToInt64(response.lines[0], &size)) 1098e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 1099e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt if (size < 0) 1100e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 1101e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt 1102e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt // A successful response to SIZE does not mean the resource is a file. 1103e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt // Some FTP servers (for example, the qnx one) send a SIZE even for 1104e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt // directories. 1105e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt response_.expected_content_size = size; 1106e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt 1107e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt next_state_ = state_after_size; 1108e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt break; 1109e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 1110e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt next_state_ = state_after_size; 1111e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt break; 1112e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 1113e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt ResetDataConnectionAfterError(state_after_size); 1114e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt break; 1115e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 111604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt // It's possible that SIZE failed because the path is a directory. 111704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 111804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt response.status_code != 550) { 111904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 112004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 112104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 112204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ResetDataConnectionAfterError(state_after_size); 112304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt break; 112404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 112504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt NOTREACHED(); 112604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return Stop(ERR_UNEXPECTED); 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return OK; 11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// CWD command 11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteCWD() { 11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt std::string command = "CWD " + GetRequestPathForFtpCommand(true); 11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_READ; 11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return SendFtpCommand(command, command, COMMAND_CWD); 11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // We should never issue CWD if we know the target resource is a file. 11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); 11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (GetErrorClass(response.status_code)) { 11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INITIATED: 11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_OK: 11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_state_ = STATE_CTRL_WRITE_LIST; 11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_INFO_NEEDED: 11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_INVALID_RESPONSE); 11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_TRANSIENT_ERROR: 11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Some FTP servers send response 451 (not a valid CWD response according 11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // to RFC 959) instead of 550. 11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response.status_code == 451) 11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ProcessResponseCWDNotADirectory(); 11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ERROR_CLASS_PERMANENT_ERROR: 11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response.status_code == 550) 11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ProcessResponseCWDNotADirectory(); 11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NOTREACHED(); 11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Stop(ERR_UNEXPECTED); 1166cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt } 1167cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1168cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return OK; 1169cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt} 1170cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1171cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { 1172cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { 1173cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // We're assuming that the resource is a directory, but the server 1174cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // says it's not true. The most probable interpretation is that it 1175cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // doesn't exist (with FTP we can't be sure). 1176cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return Stop(ERR_FILE_NOT_FOUND); 1177cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt } 1178cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1179cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // We are here because SIZE failed and we are not sure what the resource 1180cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // type is. It could still be file, and SIZE could fail because of 1181cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // an access error (http://crbug.com/56734). Try RETR just to be sure. 1182cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt resource_type_ = RESOURCE_TYPE_FILE; 1183cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1184cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); 1185cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return OK; 1186cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt} 1187cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1188cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt// LIST command 1189cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint FtpNetworkTransaction::DoCtrlWriteLIST() { 1190cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option 1191cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // forces LIST output instead of NLST (which would be ambiguous for us 1192cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // to parse). 1193cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt std::string command("LIST -l"); 1194cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt if (system_type_ == SYSTEM_TYPE_VMS) 1195cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt command = "LIST *.*;0"; 1196cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1197cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt next_state_ = STATE_CTRL_READ; 1198cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt return SendFtpCommand(command, command, COMMAND_LIST); 1199cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt} 1200cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt 1201cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint FtpNetworkTransaction::ProcessResponseLIST( 1202cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt const FtpCtrlResponse& response) { 1203cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt switch (GetErrorClass(response.status_code)) { 1204cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt case ERROR_CLASS_INITIATED: 1205cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // We want the client to start reading the response at this point. 1206cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // It got here either through Start or RestartWithAuth. We want that 1207cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // method to complete. Not setting next state here will make DoLoop exit 1208cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt // and in turn make Start/RestartWithAuth complete. 1209cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt response_.is_directory_listing = true; 1210cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt break; 1211 case ERROR_CLASS_OK: 1212 response_.is_directory_listing = true; 1213 next_state_ = STATE_CTRL_WRITE_QUIT; 1214 break; 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)); 1221 default: 1222 NOTREACHED(); 1223 return Stop(ERR_UNEXPECTED); 1224 } 1225 return OK; 1226} 1227 1228// QUIT command 1229int FtpNetworkTransaction::DoCtrlWriteQUIT() { 1230 std::string command = "QUIT"; 1231 next_state_ = STATE_CTRL_READ; 1232 return SendFtpCommand(command, command, COMMAND_QUIT); 1233} 1234 1235int FtpNetworkTransaction::ProcessResponseQUIT( 1236 const FtpCtrlResponse& response) { 1237 ctrl_socket_->Disconnect(); 1238 return last_error_; 1239} 1240 1241// Data Connection 1242 1243int 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); 1250 if (rv != OK) 1251 return Stop(rv); 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()); 1256 net_log_.AddEvent( 1257 NetLog::TYPE_FTP_DATA_CONNECTION, 1258 data_socket_->NetLog().source().ToEventParametersCallback()); 1259 return data_socket_->Connect(io_callback_); 1260} 1261 1262int 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. 1268 use_epsv_ = false; 1269 next_state_ = STATE_CTRL_WRITE_PASV; 1270 return OK; 1271 } 1272 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); 1276 1277 if (result != OK) 1278 return Stop(result); 1279 1280 next_state_ = state_after_data_connect_complete_; 1281 return OK; 1282} 1283 1284int FtpNetworkTransaction::DoDataRead() { 1285 DCHECK(read_data_buf_.get()); 1286 DCHECK_GT(read_data_buf_len_, 0); 1287 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(); 1293 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; 1297 return OK; 1298 } 1299 1300 // We are no longer connected to the server, so just finish the transaction. 1301 return Stop(OK); 1302 } 1303 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_); 1308} 1309 1310int FtpNetworkTransaction::DoDataReadComplete(int result) { 1311 return result; 1312} 1313 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. 1318// 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. 1322void 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. 1325 enum { 1326 // Data connection successful. 1327 NET_ERROR_OK = 0, 1328 1329 // Local firewall blocked the connection. 1330 NET_ERROR_ACCESS_DENIED = 1, 1331 1332 // Connection timed out. 1333 NET_ERROR_TIMED_OUT = 2, 1334 1335 // Connection has been estabilished, but then got broken (either reset 1336 // or aborted). 1337 NET_ERROR_CONNECTION_BROKEN = 3, 1338 1339 // Connection has been refused. 1340 NET_ERROR_CONNECTION_REFUSED = 4, 1341 1342 // No connection to the internet. 1343 NET_ERROR_INTERNET_DISCONNECTED = 5, 1344 1345 // Could not reach the destination address. 1346 NET_ERROR_ADDRESS_UNREACHABLE = 6, 1347 1348 // A programming error in our network stack. 1349 NET_ERROR_UNEXPECTED = 7, 1350 1351 // Other kind of error. 1352 NET_ERROR_OTHER = 20, 1353 1354 NUM_OF_NET_ERROR_TYPES 1355 } type; 1356 switch (result) { 1357 case OK: 1358 type = NET_ERROR_OK; 1359 break; 1360 case ERR_ACCESS_DENIED: 1361 case ERR_NETWORK_ACCESS_DENIED: 1362 type = NET_ERROR_ACCESS_DENIED; 1363 break; 1364 case ERR_TIMED_OUT: 1365 type = NET_ERROR_TIMED_OUT; 1366 break; 1367 case ERR_CONNECTION_ABORTED: 1368 case ERR_CONNECTION_RESET: 1369 case ERR_CONNECTION_CLOSED: 1370 type = NET_ERROR_CONNECTION_BROKEN; 1371 break; 1372 case ERR_CONNECTION_FAILED: 1373 case ERR_CONNECTION_REFUSED: 1374 type = NET_ERROR_CONNECTION_REFUSED; 1375 break; 1376 case ERR_INTERNET_DISCONNECTED: 1377 type = NET_ERROR_INTERNET_DISCONNECTED; 1378 break; 1379 case ERR_ADDRESS_INVALID: 1380 case ERR_ADDRESS_UNREACHABLE: 1381 type = NET_ERROR_ADDRESS_UNREACHABLE; 1382 break; 1383 case ERR_UNEXPECTED: 1384 type = NET_ERROR_UNEXPECTED; 1385 break; 1386 default: 1387 type = NET_ERROR_OTHER; 1388 break; 1389 }; 1390 static bool had_error_type[NUM_OF_NET_ERROR_TYPES]; 1391 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); 1397 } 1398 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 1399 type, NUM_OF_NET_ERROR_TYPES); 1400} 1401 1402} // namespace net 1403