Home | History | Annotate | Download | only in ftp
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/ftp/ftp_network_transaction.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/compiler_specific.h"
     10 #include "base/metrics/histogram.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/string_split.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "net/base/address_list.h"
     17 #include "net/base/connection_type_histograms.h"
     18 #include "net/base/escape.h"
     19 #include "net/base/net_errors.h"
     20 #include "net/base/net_log.h"
     21 #include "net/base/net_util.h"
     22 #include "net/ftp/ftp_network_session.h"
     23 #include "net/ftp/ftp_request_info.h"
     24 #include "net/ftp/ftp_util.h"
     25 #include "net/socket/client_socket_factory.h"
     26 #include "net/socket/stream_socket.h"
     27 
     28 const char kCRLF[] = "\r\n";
     29 
     30 const int kCtrlBufLen = 1024;
     31 
     32 namespace {
     33 
     34 // Returns true if |input| can be safely used as a part of FTP command.
     35 bool IsValidFTPCommandString(const std::string& input) {
     36   // RFC 959 only allows ASCII strings, but at least Firefox can send non-ASCII
     37   // characters in the command if the request path contains them. To be
     38   // compatible, we do the same and allow non-ASCII characters in a command.
     39 
     40   // Protect agains newline injection attack.
     41   if (input.find_first_of("\r\n") != std::string::npos)
     42     return false;
     43 
     44   return true;
     45 }
     46 
     47 enum ErrorClass {
     48   // The requested action was initiated. The client should expect another
     49   // reply before issuing the next command.
     50   ERROR_CLASS_INITIATED,
     51 
     52   // The requested action has been successfully completed.
     53   ERROR_CLASS_OK,
     54 
     55   // The command has been accepted, but to complete the operation, more
     56   // information must be sent by the client.
     57   ERROR_CLASS_INFO_NEEDED,
     58 
     59   // The command was not accepted and the requested action did not take place.
     60   // This condition is temporary, and the client is encouraged to restart the
     61   // command sequence.
     62   ERROR_CLASS_TRANSIENT_ERROR,
     63 
     64   // The command was not accepted and the requested action did not take place.
     65   // This condition is rather permanent, and the client is discouraged from
     66   // repeating the exact request.
     67   ERROR_CLASS_PERMANENT_ERROR,
     68 };
     69 
     70 // Returns the error class for given response code. Caller should ensure
     71 // that |response_code| is in range 100-599.
     72 ErrorClass GetErrorClass(int response_code) {
     73   if (response_code >= 100 && response_code <= 199)
     74     return ERROR_CLASS_INITIATED;
     75 
     76   if (response_code >= 200 && response_code <= 299)
     77     return ERROR_CLASS_OK;
     78 
     79   if (response_code >= 300 && response_code <= 399)
     80     return ERROR_CLASS_INFO_NEEDED;
     81 
     82   if (response_code >= 400 && response_code <= 499)
     83     return ERROR_CLASS_TRANSIENT_ERROR;
     84 
     85   if (response_code >= 500 && response_code <= 599)
     86     return ERROR_CLASS_PERMANENT_ERROR;
     87 
     88   // We should not be called on invalid error codes.
     89   NOTREACHED() << response_code;
     90   return ERROR_CLASS_PERMANENT_ERROR;
     91 }
     92 
     93 // Returns network error code for received FTP |response_code|.
     94 int GetNetErrorCodeForFtpResponseCode(int response_code) {
     95   switch (response_code) {
     96     case 421:
     97       return net::ERR_FTP_SERVICE_UNAVAILABLE;
     98     case 426:
     99       return net::ERR_FTP_TRANSFER_ABORTED;
    100     case 450:
    101       return net::ERR_FTP_FILE_BUSY;
    102     case 500:
    103     case 501:
    104       return net::ERR_FTP_SYNTAX_ERROR;
    105     case 502:
    106     case 504:
    107       return net::ERR_FTP_COMMAND_NOT_SUPPORTED;
    108     case 503:
    109       return net::ERR_FTP_BAD_COMMAND_SEQUENCE;
    110     default:
    111       return net::ERR_FTP_FAILED;
    112   }
    113 }
    114 
    115 // From RFC 2428 Section 3:
    116 //   The text returned in response to the EPSV command MUST be:
    117 //     <some text> (<d><d><d><tcp-port><d>)
    118 //   <d> is a delimiter character, ideally to be |
    119 bool ExtractPortFromEPSVResponse(const net::FtpCtrlResponse& response,
    120                                  int* port) {
    121   if (response.lines.size() != 1)
    122     return false;
    123   const char* ptr = response.lines[0].c_str();
    124   while (*ptr && *ptr != '(')
    125     ++ptr;
    126   if (!*ptr)
    127     return false;
    128   char sep = *(++ptr);
    129   if (!sep || isdigit(sep) || *(++ptr) != sep || *(++ptr) != sep)
    130     return false;
    131   if (!isdigit(*(++ptr)))
    132     return false;
    133   *port = *ptr - '0';
    134   while (isdigit(*(++ptr))) {
    135     *port *= 10;
    136     *port += *ptr - '0';
    137   }
    138   if (*ptr != sep)
    139     return false;
    140 
    141   return true;
    142 }
    143 
    144 // There are two way we can receive IP address and port.
    145 // (127,0,0,1,23,21) IP address and port encapsulated in ().
    146 // 127,0,0,1,23,21  IP address and port without ().
    147 //
    148 // See RFC 959, Section 4.1.2
    149 bool ExtractPortFromPASVResponse(const net::FtpCtrlResponse& response,
    150                                  int* port) {
    151   if (response.lines.size() != 1)
    152     return false;
    153 
    154   std::string line(response.lines[0]);
    155   if (!IsStringASCII(line))
    156     return false;
    157   if (line.length() < 2)
    158     return false;
    159 
    160   size_t paren_pos = line.find('(');
    161   if (paren_pos == std::string::npos) {
    162     // Find the first comma and use it to locate the beginning
    163     // of the response data.
    164     size_t comma_pos = line.find(',');
    165     if (comma_pos == std::string::npos)
    166       return false;
    167 
    168     size_t space_pos = line.rfind(' ', comma_pos);
    169     if (space_pos != std::string::npos)
    170       line = line.substr(space_pos + 1);
    171   } else {
    172     // Remove the parentheses and use the text inside them.
    173     size_t closing_paren_pos = line.rfind(')');
    174     if (closing_paren_pos == std::string::npos)
    175       return false;
    176     if (closing_paren_pos <= paren_pos)
    177       return false;
    178 
    179     line = line.substr(paren_pos + 1, closing_paren_pos - paren_pos - 1);
    180   }
    181 
    182   // Split the line into comma-separated pieces and extract
    183   // the last two.
    184   std::vector<std::string> pieces;
    185   base::SplitString(line, ',', &pieces);
    186   if (pieces.size() != 6)
    187     return false;
    188 
    189   // Ignore the IP address supplied in the response. We are always going
    190   // to connect back to the same server to prevent FTP PASV port scanning.
    191   int p0, p1;
    192   if (!base::StringToInt(pieces[4], &p0))
    193     return false;
    194   if (!base::StringToInt(pieces[5], &p1))
    195     return false;
    196   *port = (p0 << 8) + p1;
    197 
    198   return true;
    199 }
    200 
    201 }  // namespace
    202 
    203 namespace net {
    204 
    205 FtpNetworkTransaction::FtpNetworkTransaction(
    206     FtpNetworkSession* session,
    207     ClientSocketFactory* socket_factory)
    208     : command_sent_(COMMAND_NONE),
    209       io_callback_(base::Bind(&FtpNetworkTransaction::OnIOComplete,
    210                               base::Unretained(this))),
    211       session_(session),
    212       request_(NULL),
    213       resolver_(session->host_resolver()),
    214       read_ctrl_buf_(new IOBuffer(kCtrlBufLen)),
    215       read_data_buf_len_(0),
    216       last_error_(OK),
    217       system_type_(SYSTEM_TYPE_UNKNOWN),
    218       // Use image (binary) transfer by default. It should always work,
    219       // whereas the ascii transfer may damage binary data.
    220       data_type_(DATA_TYPE_IMAGE),
    221       resource_type_(RESOURCE_TYPE_UNKNOWN),
    222       use_epsv_(true),
    223       data_connection_port_(0),
    224       socket_factory_(socket_factory),
    225       next_state_(STATE_NONE),
    226       state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE) {}
    227 
    228 FtpNetworkTransaction::~FtpNetworkTransaction() {
    229 }
    230 
    231 int FtpNetworkTransaction::Stop(int error) {
    232   if (command_sent_ == COMMAND_QUIT)
    233     return error;
    234 
    235   next_state_ = STATE_CTRL_WRITE_QUIT;
    236   last_error_ = error;
    237   return OK;
    238 }
    239 
    240 int FtpNetworkTransaction::RestartIgnoringLastError(
    241     const CompletionCallback& callback) {
    242   return ERR_NOT_IMPLEMENTED;
    243 }
    244 
    245 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
    246                                  const CompletionCallback& callback,
    247                                  const BoundNetLog& net_log) {
    248   net_log_ = net_log;
    249   request_ = request_info;
    250 
    251   ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_));
    252 
    253   if (request_->url.has_username()) {
    254     base::string16 username;
    255     base::string16 password;
    256     GetIdentityFromURL(request_->url, &username, &password);
    257     credentials_.Set(username, password);
    258   } else {
    259     credentials_.Set(ASCIIToUTF16("anonymous"),
    260                      ASCIIToUTF16("chrome (at) example.com"));
    261   }
    262 
    263   DetectTypecode();
    264 
    265   next_state_ = STATE_CTRL_RESOLVE_HOST;
    266   int rv = DoLoop(OK);
    267   if (rv == ERR_IO_PENDING)
    268     user_callback_ = callback;
    269   return rv;
    270 }
    271 
    272 int FtpNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials,
    273                                            const CompletionCallback& callback) {
    274   ResetStateForRestart();
    275 
    276   credentials_ = credentials;
    277 
    278   next_state_ = STATE_CTRL_RESOLVE_HOST;
    279   int rv = DoLoop(OK);
    280   if (rv == ERR_IO_PENDING)
    281     user_callback_ = callback;
    282   return rv;
    283 }
    284 
    285 int FtpNetworkTransaction::Read(IOBuffer* buf,
    286                                 int buf_len,
    287                                 const CompletionCallback& callback) {
    288   DCHECK(buf);
    289   DCHECK_GT(buf_len, 0);
    290 
    291   read_data_buf_ = buf;
    292   read_data_buf_len_ = buf_len;
    293 
    294   next_state_ = STATE_DATA_READ;
    295   int rv = DoLoop(OK);
    296   if (rv == ERR_IO_PENDING)
    297     user_callback_ = callback;
    298   return rv;
    299 }
    300 
    301 const FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const {
    302   return &response_;
    303 }
    304 
    305 LoadState FtpNetworkTransaction::GetLoadState() const {
    306   if (next_state_ == STATE_CTRL_RESOLVE_HOST_COMPLETE)
    307     return LOAD_STATE_RESOLVING_HOST;
    308 
    309   if (next_state_ == STATE_CTRL_CONNECT_COMPLETE ||
    310       next_state_ == STATE_DATA_CONNECT_COMPLETE)
    311     return LOAD_STATE_CONNECTING;
    312 
    313   if (next_state_ == STATE_DATA_READ_COMPLETE)
    314     return LOAD_STATE_READING_RESPONSE;
    315 
    316   if (command_sent_ == COMMAND_RETR && read_data_buf_.get())
    317     return LOAD_STATE_READING_RESPONSE;
    318 
    319   if (command_sent_ == COMMAND_QUIT)
    320     return LOAD_STATE_IDLE;
    321 
    322   if (command_sent_ != COMMAND_NONE)
    323     return LOAD_STATE_SENDING_REQUEST;
    324 
    325   return LOAD_STATE_IDLE;
    326 }
    327 
    328 uint64 FtpNetworkTransaction::GetUploadProgress() const {
    329   return 0;
    330 }
    331 
    332 void FtpNetworkTransaction::ResetStateForRestart() {
    333   command_sent_ = COMMAND_NONE;
    334   user_callback_.Reset();
    335   response_ = FtpResponseInfo();
    336   read_ctrl_buf_ = new IOBuffer(kCtrlBufLen);
    337   ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_));
    338   read_data_buf_ = NULL;
    339   read_data_buf_len_ = 0;
    340   if (write_buf_.get())
    341     write_buf_->SetOffset(0);
    342   last_error_ = OK;
    343   data_connection_port_ = 0;
    344   ctrl_socket_.reset();
    345   data_socket_.reset();
    346   next_state_ = STATE_NONE;
    347   state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE;
    348 }
    349 
    350 void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) {
    351   // The server _might_ have reset the data connection
    352   // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS:
    353   // "The server MUST close the data connection under the following
    354   // conditions:
    355   // ...
    356   // 5. An irrecoverable error condition occurs.")
    357   //
    358   // It is ambiguous what an irrecoverable error condition is,
    359   // so we take no chances.
    360   state_after_data_connect_complete_ = next_state;
    361   next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
    362 }
    363 
    364 void FtpNetworkTransaction::DoCallback(int rv) {
    365   DCHECK(rv != ERR_IO_PENDING);
    366   DCHECK(!user_callback_.is_null());
    367 
    368   // Since Run may result in Read being called, clear callback_ up front.
    369   CompletionCallback c = user_callback_;
    370   user_callback_.Reset();
    371   c.Run(rv);
    372 }
    373 
    374 void FtpNetworkTransaction::OnIOComplete(int result) {
    375   int rv = DoLoop(result);
    376   if (rv != ERR_IO_PENDING)
    377     DoCallback(rv);
    378 }
    379 
    380 int FtpNetworkTransaction::ProcessCtrlResponse() {
    381   FtpCtrlResponse response = ctrl_response_buffer_->PopResponse();
    382 
    383   int rv = OK;
    384   switch (command_sent_) {
    385     case COMMAND_NONE:
    386       // TODO(phajdan.jr): Check for errors in the welcome message.
    387       next_state_ = STATE_CTRL_WRITE_USER;
    388       break;
    389     case COMMAND_USER:
    390       rv = ProcessResponseUSER(response);
    391       break;
    392     case COMMAND_PASS:
    393       rv = ProcessResponsePASS(response);
    394       break;
    395     case COMMAND_SYST:
    396       rv = ProcessResponseSYST(response);
    397       break;
    398     case COMMAND_PWD:
    399       rv = ProcessResponsePWD(response);
    400       break;
    401     case COMMAND_TYPE:
    402       rv = ProcessResponseTYPE(response);
    403       break;
    404     case COMMAND_EPSV:
    405       rv = ProcessResponseEPSV(response);
    406       break;
    407     case COMMAND_PASV:
    408       rv = ProcessResponsePASV(response);
    409       break;
    410     case COMMAND_SIZE:
    411       rv = ProcessResponseSIZE(response);
    412       break;
    413     case COMMAND_RETR:
    414       rv = ProcessResponseRETR(response);
    415       break;
    416     case COMMAND_CWD:
    417       rv = ProcessResponseCWD(response);
    418       break;
    419     case COMMAND_LIST:
    420       rv = ProcessResponseLIST(response);
    421       break;
    422     case COMMAND_QUIT:
    423       rv = ProcessResponseQUIT(response);
    424       break;
    425     default:
    426       LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_;
    427       return ERR_UNEXPECTED;
    428   }
    429 
    430   // We may get multiple responses for some commands,
    431   // see http://crbug.com/18036.
    432   while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) {
    433     response = ctrl_response_buffer_->PopResponse();
    434 
    435     switch (command_sent_) {
    436       case COMMAND_RETR:
    437         rv = ProcessResponseRETR(response);
    438         break;
    439       case COMMAND_LIST:
    440         rv = ProcessResponseLIST(response);
    441         break;
    442       default:
    443         // Multiple responses for other commands are invalid.
    444         return Stop(ERR_INVALID_RESPONSE);
    445     }
    446   }
    447 
    448   return rv;
    449 }
    450 
    451 // Used to prepare and send FTP command.
    452 int FtpNetworkTransaction::SendFtpCommand(const std::string& command,
    453                                           const std::string& command_for_log,
    454                                           Command cmd) {
    455   // If we send a new command when we still have unprocessed responses
    456   // for previous commands, the response receiving code will have no way to know
    457   // which responses are for which command.
    458   DCHECK(!ctrl_response_buffer_->ResponseAvailable());
    459 
    460   DCHECK(!write_command_buf_.get());
    461   DCHECK(!write_buf_.get());
    462 
    463   if (!IsValidFTPCommandString(command)) {
    464     // Callers should validate the command themselves and return a more specific
    465     // error code.
    466     NOTREACHED();
    467     return Stop(ERR_UNEXPECTED);
    468   }
    469 
    470   command_sent_ = cmd;
    471 
    472   write_command_buf_ = new IOBufferWithSize(command.length() + 2);
    473   write_buf_ = new DrainableIOBuffer(write_command_buf_.get(),
    474                                      write_command_buf_->size());
    475   memcpy(write_command_buf_->data(), command.data(), command.length());
    476   memcpy(write_command_buf_->data() + command.length(), kCRLF, 2);
    477 
    478   net_log_.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT,
    479                     NetLog::StringCallback("command", &command_for_log));
    480 
    481   next_state_ = STATE_CTRL_WRITE;
    482   return OK;
    483 }
    484 
    485 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand(
    486     bool is_directory) const {
    487   std::string path(current_remote_directory_);
    488   if (request_->url.has_path()) {
    489     std::string gurl_path(request_->url.path());
    490 
    491     // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path.
    492     std::string::size_type pos = gurl_path.rfind(';');
    493     if (pos != std::string::npos)
    494       gurl_path.resize(pos);
    495 
    496     path.append(gurl_path);
    497   }
    498   // Make sure that if the path is expected to be a file, it won't end
    499   // with a trailing slash.
    500   if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/')
    501     path.erase(path.length() - 1);
    502   UnescapeRule::Type unescape_rules = UnescapeRule::SPACES |
    503                                       UnescapeRule::URL_SPECIAL_CHARS;
    504   // This may unescape to non-ASCII characters, but we allow that. See the
    505   // comment for IsValidFTPCommandString.
    506   path = net::UnescapeURLComponent(path, unescape_rules);
    507 
    508   if (system_type_ == SYSTEM_TYPE_VMS) {
    509     if (is_directory)
    510       path = FtpUtil::UnixDirectoryPathToVMS(path);
    511     else
    512       path = FtpUtil::UnixFilePathToVMS(path);
    513   }
    514 
    515   DCHECK(IsValidFTPCommandString(path));
    516   return path;
    517 }
    518 
    519 void FtpNetworkTransaction::DetectTypecode() {
    520   if (!request_->url.has_path())
    521     return;
    522   std::string gurl_path(request_->url.path());
    523 
    524   // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path.
    525   std::string::size_type pos = gurl_path.rfind(';');
    526   if (pos == std::string::npos)
    527     return;
    528   std::string typecode_string(gurl_path.substr(pos));
    529   if (typecode_string == ";type=a") {
    530     data_type_ = DATA_TYPE_ASCII;
    531     resource_type_ = RESOURCE_TYPE_FILE;
    532   } else if (typecode_string == ";type=i") {
    533     data_type_ = DATA_TYPE_IMAGE;
    534     resource_type_ = RESOURCE_TYPE_FILE;
    535   } else if (typecode_string == ";type=d") {
    536     resource_type_ = RESOURCE_TYPE_DIRECTORY;
    537   }
    538 }
    539 
    540 int FtpNetworkTransaction::DoLoop(int result) {
    541   DCHECK(next_state_ != STATE_NONE);
    542 
    543   int rv = result;
    544   do {
    545     State state = next_state_;
    546     next_state_ = STATE_NONE;
    547     switch (state) {
    548       case STATE_CTRL_RESOLVE_HOST:
    549         DCHECK(rv == OK);
    550         rv = DoCtrlResolveHost();
    551         break;
    552       case STATE_CTRL_RESOLVE_HOST_COMPLETE:
    553         rv = DoCtrlResolveHostComplete(rv);
    554         break;
    555       case STATE_CTRL_CONNECT:
    556         DCHECK(rv == OK);
    557         rv = DoCtrlConnect();
    558         break;
    559       case STATE_CTRL_CONNECT_COMPLETE:
    560         rv = DoCtrlConnectComplete(rv);
    561         break;
    562       case STATE_CTRL_READ:
    563         DCHECK(rv == OK);
    564         rv = DoCtrlRead();
    565         break;
    566       case STATE_CTRL_READ_COMPLETE:
    567         rv = DoCtrlReadComplete(rv);
    568         break;
    569       case STATE_CTRL_WRITE:
    570         DCHECK(rv == OK);
    571         rv = DoCtrlWrite();
    572         break;
    573       case STATE_CTRL_WRITE_COMPLETE:
    574         rv = DoCtrlWriteComplete(rv);
    575         break;
    576       case STATE_CTRL_WRITE_USER:
    577         DCHECK(rv == OK);
    578         rv = DoCtrlWriteUSER();
    579         break;
    580       case STATE_CTRL_WRITE_PASS:
    581         DCHECK(rv == OK);
    582         rv = DoCtrlWritePASS();
    583         break;
    584       case STATE_CTRL_WRITE_SYST:
    585         DCHECK(rv == OK);
    586         rv = DoCtrlWriteSYST();
    587         break;
    588       case STATE_CTRL_WRITE_PWD:
    589         DCHECK(rv == OK);
    590         rv = DoCtrlWritePWD();
    591         break;
    592       case STATE_CTRL_WRITE_TYPE:
    593         DCHECK(rv == OK);
    594         rv = DoCtrlWriteTYPE();
    595         break;
    596       case STATE_CTRL_WRITE_EPSV:
    597         DCHECK(rv == OK);
    598         rv = DoCtrlWriteEPSV();
    599         break;
    600       case STATE_CTRL_WRITE_PASV:
    601         DCHECK(rv == OK);
    602         rv = DoCtrlWritePASV();
    603         break;
    604       case STATE_CTRL_WRITE_RETR:
    605         DCHECK(rv == OK);
    606         rv = DoCtrlWriteRETR();
    607         break;
    608       case STATE_CTRL_WRITE_SIZE:
    609         DCHECK(rv == OK);
    610         rv = DoCtrlWriteSIZE();
    611         break;
    612       case STATE_CTRL_WRITE_CWD:
    613         DCHECK(rv == OK);
    614         rv = DoCtrlWriteCWD();
    615         break;
    616       case STATE_CTRL_WRITE_LIST:
    617         DCHECK(rv == OK);
    618         rv = DoCtrlWriteLIST();
    619         break;
    620       case STATE_CTRL_WRITE_QUIT:
    621         DCHECK(rv == OK);
    622         rv = DoCtrlWriteQUIT();
    623         break;
    624       case STATE_DATA_CONNECT:
    625         DCHECK(rv == OK);
    626         rv = DoDataConnect();
    627         break;
    628       case STATE_DATA_CONNECT_COMPLETE:
    629         rv = DoDataConnectComplete(rv);
    630         break;
    631       case STATE_DATA_READ:
    632         DCHECK(rv == OK);
    633         rv = DoDataRead();
    634         break;
    635       case STATE_DATA_READ_COMPLETE:
    636         rv = DoDataReadComplete(rv);
    637         break;
    638       default:
    639         NOTREACHED() << "bad state";
    640         rv = ERR_UNEXPECTED;
    641         break;
    642     }
    643   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
    644   return rv;
    645 }
    646 
    647 int FtpNetworkTransaction::DoCtrlResolveHost() {
    648   next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE;
    649 
    650   HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url));
    651   // No known referrer.
    652   return resolver_.Resolve(
    653       info, &addresses_,
    654       base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)),
    655       net_log_);
    656 }
    657 
    658 int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) {
    659   if (result == OK)
    660     next_state_ = STATE_CTRL_CONNECT;
    661   return result;
    662 }
    663 
    664 int FtpNetworkTransaction::DoCtrlConnect() {
    665   next_state_ = STATE_CTRL_CONNECT_COMPLETE;
    666   ctrl_socket_.reset(socket_factory_->CreateTransportClientSocket(
    667         addresses_, net_log_.net_log(), net_log_.source()));
    668   net_log_.AddEvent(
    669       NetLog::TYPE_FTP_CONTROL_CONNECTION,
    670       ctrl_socket_->NetLog().source().ToEventParametersCallback());
    671   return ctrl_socket_->Connect(io_callback_);
    672 }
    673 
    674 int FtpNetworkTransaction::DoCtrlConnectComplete(int result) {
    675   if (result == OK) {
    676     // Put the peer's IP address and port into the response.
    677     IPEndPoint ip_endpoint;
    678     result = ctrl_socket_->GetPeerAddress(&ip_endpoint);
    679     if (result == OK) {
    680       response_.socket_address = HostPortPair::FromIPEndPoint(ip_endpoint);
    681       next_state_ = STATE_CTRL_READ;
    682 
    683       if (ip_endpoint.GetFamily() == ADDRESS_FAMILY_IPV4) {
    684         // Do not use EPSV for IPv4 connections. Some servers become confused
    685         // and we time out while waiting to connect. PASV is perfectly fine for
    686         // IPv4. Note that this blacklists IPv4 not to use EPSV instead of
    687         // whitelisting IPv6 to use it, to make the code more future-proof:
    688         // all future protocols should just use EPSV.
    689         use_epsv_ = false;
    690       }
    691     }
    692   }
    693   return result;
    694 }
    695 
    696 int FtpNetworkTransaction::DoCtrlRead() {
    697   next_state_ = STATE_CTRL_READ_COMPLETE;
    698   return ctrl_socket_->Read(read_ctrl_buf_.get(), kCtrlBufLen, io_callback_);
    699 }
    700 
    701 int FtpNetworkTransaction::DoCtrlReadComplete(int result) {
    702   if (result == 0) {
    703     // Some servers (for example Pure-FTPd) apparently close the control
    704     // connection when anonymous login is not permitted. For more details
    705     // see http://crbug.com/25023.
    706     if (command_sent_ == COMMAND_USER &&
    707         credentials_.username() == ASCIIToUTF16("anonymous")) {
    708       response_.needs_auth = true;
    709     }
    710     return Stop(ERR_EMPTY_RESPONSE);
    711   }
    712   if (result < 0)
    713     return Stop(result);
    714 
    715   ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result);
    716 
    717   if (!ctrl_response_buffer_->ResponseAvailable()) {
    718     // Read more data from the control socket.
    719     next_state_ = STATE_CTRL_READ;
    720     return OK;
    721   }
    722 
    723   return ProcessCtrlResponse();
    724 }
    725 
    726 int FtpNetworkTransaction::DoCtrlWrite() {
    727   next_state_ = STATE_CTRL_WRITE_COMPLETE;
    728 
    729   return ctrl_socket_->Write(
    730       write_buf_.get(), write_buf_->BytesRemaining(), io_callback_);
    731 }
    732 
    733 int FtpNetworkTransaction::DoCtrlWriteComplete(int result) {
    734   if (result < 0)
    735     return result;
    736 
    737   write_buf_->DidConsume(result);
    738   if (write_buf_->BytesRemaining() == 0) {
    739     // Clear the write buffer.
    740     write_buf_ = NULL;
    741     write_command_buf_ = NULL;
    742 
    743     next_state_ = STATE_CTRL_READ;
    744   } else {
    745     next_state_ = STATE_CTRL_WRITE;
    746   }
    747   return OK;
    748 }
    749 
    750 // FTP Commands and responses
    751 
    752 // USER Command.
    753 int FtpNetworkTransaction::DoCtrlWriteUSER() {
    754   std::string command = "USER " + UTF16ToUTF8(credentials_.username());
    755 
    756   if (!IsValidFTPCommandString(command))
    757     return Stop(ERR_MALFORMED_IDENTITY);
    758 
    759   next_state_ = STATE_CTRL_READ;
    760   return SendFtpCommand(command, "USER ***", COMMAND_USER);
    761 }
    762 
    763 int FtpNetworkTransaction::ProcessResponseUSER(
    764     const FtpCtrlResponse& response) {
    765   switch (GetErrorClass(response.status_code)) {
    766     case ERROR_CLASS_OK:
    767       next_state_ = STATE_CTRL_WRITE_SYST;
    768       break;
    769     case ERROR_CLASS_INFO_NEEDED:
    770       next_state_ = STATE_CTRL_WRITE_PASS;
    771       break;
    772     case ERROR_CLASS_TRANSIENT_ERROR:
    773     case ERROR_CLASS_PERMANENT_ERROR:
    774       response_.needs_auth = true;
    775       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    776     default:
    777       NOTREACHED();
    778       return Stop(ERR_UNEXPECTED);
    779   }
    780   return OK;
    781 }
    782 
    783 // PASS command.
    784 int FtpNetworkTransaction::DoCtrlWritePASS() {
    785   std::string command = "PASS " + UTF16ToUTF8(credentials_.password());
    786 
    787   if (!IsValidFTPCommandString(command))
    788     return Stop(ERR_MALFORMED_IDENTITY);
    789 
    790   next_state_ = STATE_CTRL_READ;
    791   return SendFtpCommand(command, "PASS ***", COMMAND_PASS);
    792 }
    793 
    794 int FtpNetworkTransaction::ProcessResponsePASS(
    795     const FtpCtrlResponse& response) {
    796   switch (GetErrorClass(response.status_code)) {
    797     case ERROR_CLASS_OK:
    798       next_state_ = STATE_CTRL_WRITE_SYST;
    799       break;
    800     case ERROR_CLASS_INFO_NEEDED:
    801       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    802     case ERROR_CLASS_TRANSIENT_ERROR:
    803     case ERROR_CLASS_PERMANENT_ERROR:
    804       response_.needs_auth = true;
    805       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    806     default:
    807       NOTREACHED();
    808       return Stop(ERR_UNEXPECTED);
    809   }
    810   return OK;
    811 }
    812 
    813 // SYST command.
    814 int FtpNetworkTransaction::DoCtrlWriteSYST() {
    815   std::string command = "SYST";
    816   next_state_ = STATE_CTRL_READ;
    817   return SendFtpCommand(command, command, COMMAND_SYST);
    818 }
    819 
    820 int FtpNetworkTransaction::ProcessResponseSYST(
    821     const FtpCtrlResponse& response) {
    822   switch (GetErrorClass(response.status_code)) {
    823     case ERROR_CLASS_INITIATED:
    824       return Stop(ERR_INVALID_RESPONSE);
    825     case ERROR_CLASS_OK: {
    826       // All important info should be on the first line.
    827       std::string line = response.lines[0];
    828       // The response should be ASCII, which allows us to do case-insensitive
    829       // comparisons easily. If it is not ASCII, we leave the system type
    830       // as unknown.
    831       if (IsStringASCII(line)) {
    832         line = StringToLowerASCII(line);
    833 
    834         // Remove all whitespace, to correctly handle cases like fancy "V M S"
    835         // response instead of "VMS".
    836         RemoveChars(line, kWhitespaceASCII, &line);
    837 
    838         // The "magic" strings we test for below have been gathered by an
    839         // empirical study. VMS needs to come first because some VMS systems
    840         // also respond with "UNIX emulation", which is not perfect. It is much
    841         // more reliable to talk to these servers in their native language.
    842         if (line.find("vms") != std::string::npos) {
    843           system_type_ = SYSTEM_TYPE_VMS;
    844         } else if (line.find("l8") != std::string::npos ||
    845                    line.find("unix") != std::string::npos ||
    846                    line.find("bsd") != std::string::npos) {
    847           system_type_ = SYSTEM_TYPE_UNIX;
    848         } else if (line.find("win32") != std::string::npos ||
    849                    line.find("windows") != std::string::npos) {
    850           system_type_ = SYSTEM_TYPE_WINDOWS;
    851         } else if (line.find("os/2") != std::string::npos) {
    852           system_type_ = SYSTEM_TYPE_OS2;
    853         }
    854       }
    855       next_state_ = STATE_CTRL_WRITE_PWD;
    856       break;
    857     }
    858     case ERROR_CLASS_INFO_NEEDED:
    859       return Stop(ERR_INVALID_RESPONSE);
    860     case ERROR_CLASS_TRANSIENT_ERROR:
    861       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    862     case ERROR_CLASS_PERMANENT_ERROR:
    863       // Server does not recognize the SYST command so proceed.
    864       next_state_ = STATE_CTRL_WRITE_PWD;
    865       break;
    866     default:
    867       NOTREACHED();
    868       return Stop(ERR_UNEXPECTED);
    869   }
    870   return OK;
    871 }
    872 
    873 // PWD command.
    874 int FtpNetworkTransaction::DoCtrlWritePWD() {
    875   std::string command = "PWD";
    876   next_state_ = STATE_CTRL_READ;
    877   return SendFtpCommand(command, command, COMMAND_PWD);
    878 }
    879 
    880 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) {
    881   switch (GetErrorClass(response.status_code)) {
    882     case ERROR_CLASS_INITIATED:
    883       return Stop(ERR_INVALID_RESPONSE);
    884     case ERROR_CLASS_OK: {
    885       // The info we look for should be on the first line.
    886       std::string line = response.lines[0];
    887       if (line.empty())
    888         return Stop(ERR_INVALID_RESPONSE);
    889       std::string::size_type quote_pos = line.find('"');
    890       if (quote_pos != std::string::npos) {
    891         line = line.substr(quote_pos + 1);
    892         quote_pos = line.find('"');
    893         if (quote_pos == std::string::npos)
    894           return Stop(ERR_INVALID_RESPONSE);
    895         line = line.substr(0, quote_pos);
    896       }
    897       if (system_type_ == SYSTEM_TYPE_VMS)
    898         line = FtpUtil::VMSPathToUnix(line);
    899       if (line.length() && line[line.length() - 1] == '/')
    900         line.erase(line.length() - 1);
    901       current_remote_directory_ = line;
    902       next_state_ = STATE_CTRL_WRITE_TYPE;
    903       break;
    904     }
    905     case ERROR_CLASS_INFO_NEEDED:
    906       return Stop(ERR_INVALID_RESPONSE);
    907     case ERROR_CLASS_TRANSIENT_ERROR:
    908       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    909     case ERROR_CLASS_PERMANENT_ERROR:
    910       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    911     default:
    912       NOTREACHED();
    913       return Stop(ERR_UNEXPECTED);
    914   }
    915   return OK;
    916 }
    917 
    918 // TYPE command.
    919 int FtpNetworkTransaction::DoCtrlWriteTYPE() {
    920   std::string command = "TYPE ";
    921   if (data_type_ == DATA_TYPE_ASCII) {
    922     command += "A";
    923   } else if (data_type_ == DATA_TYPE_IMAGE) {
    924     command += "I";
    925   } else {
    926     NOTREACHED();
    927     return Stop(ERR_UNEXPECTED);
    928   }
    929   next_state_ = STATE_CTRL_READ;
    930   return SendFtpCommand(command, command, COMMAND_TYPE);
    931 }
    932 
    933 int FtpNetworkTransaction::ProcessResponseTYPE(
    934     const FtpCtrlResponse& response) {
    935   switch (GetErrorClass(response.status_code)) {
    936     case ERROR_CLASS_INITIATED:
    937       return Stop(ERR_INVALID_RESPONSE);
    938     case ERROR_CLASS_OK:
    939       next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
    940       break;
    941     case ERROR_CLASS_INFO_NEEDED:
    942       return Stop(ERR_INVALID_RESPONSE);
    943     case ERROR_CLASS_TRANSIENT_ERROR:
    944       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    945     case ERROR_CLASS_PERMANENT_ERROR:
    946       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    947     default:
    948       NOTREACHED();
    949       return Stop(ERR_UNEXPECTED);
    950   }
    951   return OK;
    952 }
    953 
    954 // EPSV command
    955 int FtpNetworkTransaction::DoCtrlWriteEPSV() {
    956   const std::string command = "EPSV";
    957   next_state_ = STATE_CTRL_READ;
    958   return SendFtpCommand(command, command, COMMAND_EPSV);
    959 }
    960 
    961 int FtpNetworkTransaction::ProcessResponseEPSV(
    962     const FtpCtrlResponse& response) {
    963   switch (GetErrorClass(response.status_code)) {
    964     case ERROR_CLASS_INITIATED:
    965       return Stop(ERR_INVALID_RESPONSE);
    966     case ERROR_CLASS_OK:
    967       if (!ExtractPortFromEPSVResponse( response, &data_connection_port_))
    968         return Stop(ERR_INVALID_RESPONSE);
    969       if (data_connection_port_ < 1024 ||
    970           !IsPortAllowedByFtp(data_connection_port_))
    971         return Stop(ERR_UNSAFE_PORT);
    972       next_state_ = STATE_DATA_CONNECT;
    973       break;
    974     case ERROR_CLASS_INFO_NEEDED:
    975       return Stop(ERR_INVALID_RESPONSE);
    976     case ERROR_CLASS_TRANSIENT_ERROR:
    977     case ERROR_CLASS_PERMANENT_ERROR:
    978       use_epsv_ = false;
    979       next_state_ = STATE_CTRL_WRITE_PASV;
    980       return OK;
    981     default:
    982       NOTREACHED();
    983       return Stop(ERR_UNEXPECTED);
    984   }
    985   return OK;
    986 }
    987 
    988 // PASV command
    989 int FtpNetworkTransaction::DoCtrlWritePASV() {
    990   std::string command = "PASV";
    991   next_state_ = STATE_CTRL_READ;
    992   return SendFtpCommand(command, command, COMMAND_PASV);
    993 }
    994 
    995 int FtpNetworkTransaction::ProcessResponsePASV(
    996     const FtpCtrlResponse& response) {
    997   switch (GetErrorClass(response.status_code)) {
    998     case ERROR_CLASS_INITIATED:
    999       return Stop(ERR_INVALID_RESPONSE);
   1000     case ERROR_CLASS_OK:
   1001       if (!ExtractPortFromPASVResponse(response, &data_connection_port_))
   1002         return Stop(ERR_INVALID_RESPONSE);
   1003       if (data_connection_port_ < 1024 ||
   1004           !IsPortAllowedByFtp(data_connection_port_))
   1005         return Stop(ERR_UNSAFE_PORT);
   1006       next_state_ = STATE_DATA_CONNECT;
   1007       break;
   1008     case ERROR_CLASS_INFO_NEEDED:
   1009       return Stop(ERR_INVALID_RESPONSE);
   1010     case ERROR_CLASS_TRANSIENT_ERROR:
   1011       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1012     case ERROR_CLASS_PERMANENT_ERROR:
   1013       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1014     default:
   1015       NOTREACHED();
   1016       return Stop(ERR_UNEXPECTED);
   1017   }
   1018   return OK;
   1019 }
   1020 
   1021 // RETR command
   1022 int FtpNetworkTransaction::DoCtrlWriteRETR() {
   1023   std::string command = "RETR " + GetRequestPathForFtpCommand(false);
   1024   next_state_ = STATE_CTRL_READ;
   1025   return SendFtpCommand(command, command, COMMAND_RETR);
   1026 }
   1027 
   1028 int FtpNetworkTransaction::ProcessResponseRETR(
   1029     const FtpCtrlResponse& response) {
   1030   switch (GetErrorClass(response.status_code)) {
   1031     case ERROR_CLASS_INITIATED:
   1032       // We want the client to start reading the response at this point.
   1033       // It got here either through Start or RestartWithAuth. We want that
   1034       // method to complete. Not setting next state here will make DoLoop exit
   1035       // and in turn make Start/RestartWithAuth complete.
   1036       resource_type_ = RESOURCE_TYPE_FILE;
   1037       break;
   1038     case ERROR_CLASS_OK:
   1039       resource_type_ = RESOURCE_TYPE_FILE;
   1040       next_state_ = STATE_CTRL_WRITE_QUIT;
   1041       break;
   1042     case ERROR_CLASS_INFO_NEEDED:
   1043       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1044     case ERROR_CLASS_TRANSIENT_ERROR:
   1045       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1046     case ERROR_CLASS_PERMANENT_ERROR:
   1047       // Code 550 means "Failed to open file". Other codes are unrelated,
   1048       // like "Not logged in" etc.
   1049       if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE)
   1050         return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1051 
   1052       // It's possible that RETR failed because the path is a directory.
   1053       resource_type_ = RESOURCE_TYPE_DIRECTORY;
   1054 
   1055       // We're going to try CWD next, but first send a PASV one more time,
   1056       // because some FTP servers, including FileZilla, require that.
   1057       // See http://crbug.com/25316.
   1058       next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
   1059       break;
   1060     default:
   1061       NOTREACHED();
   1062       return Stop(ERR_UNEXPECTED);
   1063   }
   1064 
   1065   // We should be sure about our resource type now. Otherwise we risk
   1066   // an infinite loop (RETR can later send CWD, and CWD can later send RETR).
   1067   DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_);
   1068 
   1069   return OK;
   1070 }
   1071 
   1072 // SIZE command
   1073 int FtpNetworkTransaction::DoCtrlWriteSIZE() {
   1074   std::string command = "SIZE " + GetRequestPathForFtpCommand(false);
   1075   next_state_ = STATE_CTRL_READ;
   1076   return SendFtpCommand(command, command, COMMAND_SIZE);
   1077 }
   1078 
   1079 int FtpNetworkTransaction::ProcessResponseSIZE(
   1080     const FtpCtrlResponse& response) {
   1081   State state_after_size;
   1082   if (resource_type_ == RESOURCE_TYPE_FILE)
   1083     state_after_size = STATE_CTRL_WRITE_RETR;
   1084   else
   1085     state_after_size = STATE_CTRL_WRITE_CWD;
   1086 
   1087   switch (GetErrorClass(response.status_code)) {
   1088     case ERROR_CLASS_INITIATED:
   1089       next_state_ = state_after_size;
   1090       break;
   1091     case ERROR_CLASS_OK:
   1092       if (response.lines.size() != 1)
   1093         return Stop(ERR_INVALID_RESPONSE);
   1094       int64 size;
   1095       if (!base::StringToInt64(response.lines[0], &size))
   1096         return Stop(ERR_INVALID_RESPONSE);
   1097       if (size < 0)
   1098         return Stop(ERR_INVALID_RESPONSE);
   1099 
   1100       // A successful response to SIZE does not mean the resource is a file.
   1101       // Some FTP servers (for example, the qnx one) send a SIZE even for
   1102       // directories.
   1103       response_.expected_content_size = size;
   1104 
   1105       next_state_ = state_after_size;
   1106       break;
   1107     case ERROR_CLASS_INFO_NEEDED:
   1108       next_state_ = state_after_size;
   1109       break;
   1110     case ERROR_CLASS_TRANSIENT_ERROR:
   1111       ResetDataConnectionAfterError(state_after_size);
   1112       break;
   1113     case ERROR_CLASS_PERMANENT_ERROR:
   1114       // It's possible that SIZE failed because the path is a directory.
   1115       if (resource_type_ == RESOURCE_TYPE_UNKNOWN &&
   1116           response.status_code != 550) {
   1117         return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1118       }
   1119 
   1120       ResetDataConnectionAfterError(state_after_size);
   1121       break;
   1122     default:
   1123       NOTREACHED();
   1124       return Stop(ERR_UNEXPECTED);
   1125   }
   1126 
   1127   return OK;
   1128 }
   1129 
   1130 // CWD command
   1131 int FtpNetworkTransaction::DoCtrlWriteCWD() {
   1132   std::string command = "CWD " + GetRequestPathForFtpCommand(true);
   1133   next_state_ = STATE_CTRL_READ;
   1134   return SendFtpCommand(command, command, COMMAND_CWD);
   1135 }
   1136 
   1137 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) {
   1138   // We should never issue CWD if we know the target resource is a file.
   1139   DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_);
   1140 
   1141   switch (GetErrorClass(response.status_code)) {
   1142     case ERROR_CLASS_INITIATED:
   1143       return Stop(ERR_INVALID_RESPONSE);
   1144     case ERROR_CLASS_OK:
   1145       next_state_ = STATE_CTRL_WRITE_LIST;
   1146       break;
   1147     case ERROR_CLASS_INFO_NEEDED:
   1148       return Stop(ERR_INVALID_RESPONSE);
   1149     case ERROR_CLASS_TRANSIENT_ERROR:
   1150       // Some FTP servers send response 451 (not a valid CWD response according
   1151       // to RFC 959) instead of 550.
   1152       if (response.status_code == 451)
   1153         return ProcessResponseCWDNotADirectory();
   1154 
   1155       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1156     case ERROR_CLASS_PERMANENT_ERROR:
   1157       if (response.status_code == 550)
   1158         return ProcessResponseCWDNotADirectory();
   1159 
   1160       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1161     default:
   1162       NOTREACHED();
   1163       return Stop(ERR_UNEXPECTED);
   1164   }
   1165 
   1166   return OK;
   1167 }
   1168 
   1169 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() {
   1170   if (resource_type_ == RESOURCE_TYPE_DIRECTORY) {
   1171     // We're assuming that the resource is a directory, but the server
   1172     // says it's not true. The most probable interpretation is that it
   1173     // doesn't exist (with FTP we can't be sure).
   1174     return Stop(ERR_FILE_NOT_FOUND);
   1175   }
   1176 
   1177   // We are here because SIZE failed and we are not sure what the resource
   1178   // type is. It could still be file, and SIZE could fail because of
   1179   // an access error (http://crbug.com/56734). Try RETR just to be sure.
   1180   resource_type_ = RESOURCE_TYPE_FILE;
   1181 
   1182   ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR);
   1183   return OK;
   1184 }
   1185 
   1186 // LIST command
   1187 int FtpNetworkTransaction::DoCtrlWriteLIST() {
   1188   // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option
   1189   // forces LIST output instead of NLST (which would be ambiguous for us
   1190   // to parse).
   1191   std::string command("LIST -l");
   1192   if (system_type_ == SYSTEM_TYPE_VMS)
   1193     command = "LIST *.*;0";
   1194 
   1195   next_state_ = STATE_CTRL_READ;
   1196   return SendFtpCommand(command, command, COMMAND_LIST);
   1197 }
   1198 
   1199 int FtpNetworkTransaction::ProcessResponseLIST(
   1200     const FtpCtrlResponse& response) {
   1201   switch (GetErrorClass(response.status_code)) {
   1202     case ERROR_CLASS_INITIATED:
   1203       // We want the client to start reading the response at this point.
   1204       // It got here either through Start or RestartWithAuth. We want that
   1205       // method to complete. Not setting next state here will make DoLoop exit
   1206       // and in turn make Start/RestartWithAuth complete.
   1207       response_.is_directory_listing = true;
   1208       break;
   1209     case ERROR_CLASS_OK:
   1210       response_.is_directory_listing = true;
   1211       next_state_ = STATE_CTRL_WRITE_QUIT;
   1212       break;
   1213     case ERROR_CLASS_INFO_NEEDED:
   1214       return Stop(ERR_INVALID_RESPONSE);
   1215     case ERROR_CLASS_TRANSIENT_ERROR:
   1216       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1217     case ERROR_CLASS_PERMANENT_ERROR:
   1218       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1219     default:
   1220       NOTREACHED();
   1221       return Stop(ERR_UNEXPECTED);
   1222   }
   1223   return OK;
   1224 }
   1225 
   1226 // QUIT command
   1227 int FtpNetworkTransaction::DoCtrlWriteQUIT() {
   1228   std::string command = "QUIT";
   1229   next_state_ = STATE_CTRL_READ;
   1230   return SendFtpCommand(command, command, COMMAND_QUIT);
   1231 }
   1232 
   1233 int FtpNetworkTransaction::ProcessResponseQUIT(
   1234     const FtpCtrlResponse& response) {
   1235   ctrl_socket_->Disconnect();
   1236   return last_error_;
   1237 }
   1238 
   1239 // Data Connection
   1240 
   1241 int FtpNetworkTransaction::DoDataConnect() {
   1242   next_state_ = STATE_DATA_CONNECT_COMPLETE;
   1243   IPEndPoint ip_endpoint;
   1244   AddressList data_address;
   1245   // Connect to the same host as the control socket to prevent PASV port
   1246   // scanning attacks.
   1247   int rv = ctrl_socket_->GetPeerAddress(&ip_endpoint);
   1248   if (rv != OK)
   1249     return Stop(rv);
   1250   data_address = AddressList::CreateFromIPAddress(
   1251       ip_endpoint.address(), data_connection_port_);
   1252   data_socket_.reset(socket_factory_->CreateTransportClientSocket(
   1253         data_address, net_log_.net_log(), net_log_.source()));
   1254   net_log_.AddEvent(
   1255       NetLog::TYPE_FTP_DATA_CONNECTION,
   1256       data_socket_->NetLog().source().ToEventParametersCallback());
   1257   return data_socket_->Connect(io_callback_);
   1258 }
   1259 
   1260 int FtpNetworkTransaction::DoDataConnectComplete(int result) {
   1261   if (result != OK && use_epsv_) {
   1262     // It's possible we hit a broken server, sadly. They can break in different
   1263     // ways. Some time out, some reset a connection. Fall back to PASV.
   1264     // TODO(phajdan.jr): remember it for future transactions with this server.
   1265     // TODO(phajdan.jr): write a test for this code path.
   1266     use_epsv_ = false;
   1267     next_state_ = STATE_CTRL_WRITE_PASV;
   1268     return OK;
   1269   }
   1270 
   1271   // Only record the connection error after we've applied all our fallbacks.
   1272   // We want to capture the final error, one we're not going to recover from.
   1273   RecordDataConnectionError(result);
   1274 
   1275   if (result != OK)
   1276     return Stop(result);
   1277 
   1278   next_state_ = state_after_data_connect_complete_;
   1279   return OK;
   1280 }
   1281 
   1282 int FtpNetworkTransaction::DoDataRead() {
   1283   DCHECK(read_data_buf_.get());
   1284   DCHECK_GT(read_data_buf_len_, 0);
   1285 
   1286   if (data_socket_ == NULL || !data_socket_->IsConnected()) {
   1287     // If we don't destroy the data socket completely, some servers will wait
   1288     // for us (http://crbug.com/21127). The half-closed TCP connection needs
   1289     // to be closed on our side too.
   1290     data_socket_.reset();
   1291 
   1292     if (ctrl_socket_->IsConnected()) {
   1293       // Wait for the server's response, we should get it before sending QUIT.
   1294       next_state_ = STATE_CTRL_READ;
   1295       return OK;
   1296     }
   1297 
   1298     // We are no longer connected to the server, so just finish the transaction.
   1299     return Stop(OK);
   1300   }
   1301 
   1302   next_state_ = STATE_DATA_READ_COMPLETE;
   1303   read_data_buf_->data()[0] = 0;
   1304   return data_socket_->Read(
   1305       read_data_buf_.get(), read_data_buf_len_, io_callback_);
   1306 }
   1307 
   1308 int FtpNetworkTransaction::DoDataReadComplete(int result) {
   1309   return result;
   1310 }
   1311 
   1312 // We're using a histogram as a group of counters, with one bucket for each
   1313 // enumeration value.  We're only interested in the values of the counters.
   1314 // Ignore the shape, average, and standard deviation of the histograms because
   1315 // they are meaningless.
   1316 //
   1317 // We use two histograms.  In the first histogram we tally whether the user has
   1318 // seen an error of that type during the session.  In the second histogram we
   1319 // tally the total number of times the users sees each errer.
   1320 void FtpNetworkTransaction::RecordDataConnectionError(int result) {
   1321   // Gather data for http://crbug.com/3073. See how many users have trouble
   1322   // establishing FTP data connection in passive FTP mode.
   1323   enum {
   1324     // Data connection successful.
   1325     NET_ERROR_OK = 0,
   1326 
   1327     // Local firewall blocked the connection.
   1328     NET_ERROR_ACCESS_DENIED = 1,
   1329 
   1330     // Connection timed out.
   1331     NET_ERROR_TIMED_OUT = 2,
   1332 
   1333     // Connection has been estabilished, but then got broken (either reset
   1334     // or aborted).
   1335     NET_ERROR_CONNECTION_BROKEN = 3,
   1336 
   1337     // Connection has been refused.
   1338     NET_ERROR_CONNECTION_REFUSED = 4,
   1339 
   1340     // No connection to the internet.
   1341     NET_ERROR_INTERNET_DISCONNECTED = 5,
   1342 
   1343     // Could not reach the destination address.
   1344     NET_ERROR_ADDRESS_UNREACHABLE = 6,
   1345 
   1346     // A programming error in our network stack.
   1347     NET_ERROR_UNEXPECTED = 7,
   1348 
   1349     // Other kind of error.
   1350     NET_ERROR_OTHER = 20,
   1351 
   1352     NUM_OF_NET_ERROR_TYPES
   1353   } type;
   1354   switch (result) {
   1355     case OK:
   1356       type = NET_ERROR_OK;
   1357       break;
   1358     case ERR_ACCESS_DENIED:
   1359     case ERR_NETWORK_ACCESS_DENIED:
   1360       type = NET_ERROR_ACCESS_DENIED;
   1361       break;
   1362     case ERR_TIMED_OUT:
   1363       type = NET_ERROR_TIMED_OUT;
   1364       break;
   1365     case ERR_CONNECTION_ABORTED:
   1366     case ERR_CONNECTION_RESET:
   1367     case ERR_CONNECTION_CLOSED:
   1368       type = NET_ERROR_CONNECTION_BROKEN;
   1369       break;
   1370     case ERR_CONNECTION_FAILED:
   1371     case ERR_CONNECTION_REFUSED:
   1372       type = NET_ERROR_CONNECTION_REFUSED;
   1373       break;
   1374     case ERR_INTERNET_DISCONNECTED:
   1375       type = NET_ERROR_INTERNET_DISCONNECTED;
   1376       break;
   1377     case ERR_ADDRESS_INVALID:
   1378     case ERR_ADDRESS_UNREACHABLE:
   1379       type = NET_ERROR_ADDRESS_UNREACHABLE;
   1380       break;
   1381     case ERR_UNEXPECTED:
   1382       type = NET_ERROR_UNEXPECTED;
   1383       break;
   1384     default:
   1385       type = NET_ERROR_OTHER;
   1386       break;
   1387   };
   1388   static bool had_error_type[NUM_OF_NET_ERROR_TYPES];
   1389 
   1390   DCHECK(type >= 0 && type < NUM_OF_NET_ERROR_TYPES);
   1391   if (!had_error_type[type]) {
   1392     had_error_type[type] = true;
   1393     UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened",
   1394         type, NUM_OF_NET_ERROR_TYPES);
   1395   }
   1396   UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount",
   1397       type, NUM_OF_NET_ERROR_TYPES);
   1398 }
   1399 
   1400 }  // namespace net
   1401