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 (!base::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(base::ASCIIToUTF16("anonymous"),
    260                      base::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,
    654       DEFAULT_PRIORITY,
    655       &addresses_,
    656       base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)),
    657       net_log_);
    658 }
    659 
    660 int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) {
    661   if (result == OK)
    662     next_state_ = STATE_CTRL_CONNECT;
    663   return result;
    664 }
    665 
    666 int FtpNetworkTransaction::DoCtrlConnect() {
    667   next_state_ = STATE_CTRL_CONNECT_COMPLETE;
    668   ctrl_socket_ = socket_factory_->CreateTransportClientSocket(
    669       addresses_, net_log_.net_log(), net_log_.source());
    670   net_log_.AddEvent(
    671       NetLog::TYPE_FTP_CONTROL_CONNECTION,
    672       ctrl_socket_->NetLog().source().ToEventParametersCallback());
    673   return ctrl_socket_->Connect(io_callback_);
    674 }
    675 
    676 int FtpNetworkTransaction::DoCtrlConnectComplete(int result) {
    677   if (result == OK) {
    678     // Put the peer's IP address and port into the response.
    679     IPEndPoint ip_endpoint;
    680     result = ctrl_socket_->GetPeerAddress(&ip_endpoint);
    681     if (result == OK) {
    682       response_.socket_address = HostPortPair::FromIPEndPoint(ip_endpoint);
    683       next_state_ = STATE_CTRL_READ;
    684 
    685       if (ip_endpoint.GetFamily() == ADDRESS_FAMILY_IPV4) {
    686         // Do not use EPSV for IPv4 connections. Some servers become confused
    687         // and we time out while waiting to connect. PASV is perfectly fine for
    688         // IPv4. Note that this blacklists IPv4 not to use EPSV instead of
    689         // whitelisting IPv6 to use it, to make the code more future-proof:
    690         // all future protocols should just use EPSV.
    691         use_epsv_ = false;
    692       }
    693     }
    694   }
    695   return result;
    696 }
    697 
    698 int FtpNetworkTransaction::DoCtrlRead() {
    699   next_state_ = STATE_CTRL_READ_COMPLETE;
    700   return ctrl_socket_->Read(read_ctrl_buf_.get(), kCtrlBufLen, io_callback_);
    701 }
    702 
    703 int FtpNetworkTransaction::DoCtrlReadComplete(int result) {
    704   if (result == 0) {
    705     // Some servers (for example Pure-FTPd) apparently close the control
    706     // connection when anonymous login is not permitted. For more details
    707     // see http://crbug.com/25023.
    708     if (command_sent_ == COMMAND_USER &&
    709         credentials_.username() == base::ASCIIToUTF16("anonymous")) {
    710       response_.needs_auth = true;
    711     }
    712     return Stop(ERR_EMPTY_RESPONSE);
    713   }
    714   if (result < 0)
    715     return Stop(result);
    716 
    717   ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result);
    718 
    719   if (!ctrl_response_buffer_->ResponseAvailable()) {
    720     // Read more data from the control socket.
    721     next_state_ = STATE_CTRL_READ;
    722     return OK;
    723   }
    724 
    725   return ProcessCtrlResponse();
    726 }
    727 
    728 int FtpNetworkTransaction::DoCtrlWrite() {
    729   next_state_ = STATE_CTRL_WRITE_COMPLETE;
    730 
    731   return ctrl_socket_->Write(
    732       write_buf_.get(), write_buf_->BytesRemaining(), io_callback_);
    733 }
    734 
    735 int FtpNetworkTransaction::DoCtrlWriteComplete(int result) {
    736   if (result < 0)
    737     return result;
    738 
    739   write_buf_->DidConsume(result);
    740   if (write_buf_->BytesRemaining() == 0) {
    741     // Clear the write buffer.
    742     write_buf_ = NULL;
    743     write_command_buf_ = NULL;
    744 
    745     next_state_ = STATE_CTRL_READ;
    746   } else {
    747     next_state_ = STATE_CTRL_WRITE;
    748   }
    749   return OK;
    750 }
    751 
    752 // FTP Commands and responses
    753 
    754 // USER Command.
    755 int FtpNetworkTransaction::DoCtrlWriteUSER() {
    756   std::string command = "USER " + base::UTF16ToUTF8(credentials_.username());
    757 
    758   if (!IsValidFTPCommandString(command))
    759     return Stop(ERR_MALFORMED_IDENTITY);
    760 
    761   next_state_ = STATE_CTRL_READ;
    762   return SendFtpCommand(command, "USER ***", COMMAND_USER);
    763 }
    764 
    765 int FtpNetworkTransaction::ProcessResponseUSER(
    766     const FtpCtrlResponse& response) {
    767   switch (GetErrorClass(response.status_code)) {
    768     case ERROR_CLASS_OK:
    769       next_state_ = STATE_CTRL_WRITE_SYST;
    770       break;
    771     case ERROR_CLASS_INFO_NEEDED:
    772       next_state_ = STATE_CTRL_WRITE_PASS;
    773       break;
    774     case ERROR_CLASS_TRANSIENT_ERROR:
    775     case ERROR_CLASS_PERMANENT_ERROR:
    776       response_.needs_auth = true;
    777       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    778     default:
    779       NOTREACHED();
    780       return Stop(ERR_UNEXPECTED);
    781   }
    782   return OK;
    783 }
    784 
    785 // PASS command.
    786 int FtpNetworkTransaction::DoCtrlWritePASS() {
    787   std::string command = "PASS " + base::UTF16ToUTF8(credentials_.password());
    788 
    789   if (!IsValidFTPCommandString(command))
    790     return Stop(ERR_MALFORMED_IDENTITY);
    791 
    792   next_state_ = STATE_CTRL_READ;
    793   return SendFtpCommand(command, "PASS ***", COMMAND_PASS);
    794 }
    795 
    796 int FtpNetworkTransaction::ProcessResponsePASS(
    797     const FtpCtrlResponse& response) {
    798   switch (GetErrorClass(response.status_code)) {
    799     case ERROR_CLASS_OK:
    800       next_state_ = STATE_CTRL_WRITE_SYST;
    801       break;
    802     case ERROR_CLASS_INFO_NEEDED:
    803       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    804     case ERROR_CLASS_TRANSIENT_ERROR:
    805     case ERROR_CLASS_PERMANENT_ERROR:
    806       response_.needs_auth = true;
    807       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    808     default:
    809       NOTREACHED();
    810       return Stop(ERR_UNEXPECTED);
    811   }
    812   return OK;
    813 }
    814 
    815 // SYST command.
    816 int FtpNetworkTransaction::DoCtrlWriteSYST() {
    817   std::string command = "SYST";
    818   next_state_ = STATE_CTRL_READ;
    819   return SendFtpCommand(command, command, COMMAND_SYST);
    820 }
    821 
    822 int FtpNetworkTransaction::ProcessResponseSYST(
    823     const FtpCtrlResponse& response) {
    824   switch (GetErrorClass(response.status_code)) {
    825     case ERROR_CLASS_INITIATED:
    826       return Stop(ERR_INVALID_RESPONSE);
    827     case ERROR_CLASS_OK: {
    828       // All important info should be on the first line.
    829       std::string line = response.lines[0];
    830       // The response should be ASCII, which allows us to do case-insensitive
    831       // comparisons easily. If it is not ASCII, we leave the system type
    832       // as unknown.
    833       if (base::IsStringASCII(line)) {
    834         line = base::StringToLowerASCII(line);
    835 
    836         // Remove all whitespace, to correctly handle cases like fancy "V M S"
    837         // response instead of "VMS".
    838         base::RemoveChars(line, base::kWhitespaceASCII, &line);
    839 
    840         // The "magic" strings we test for below have been gathered by an
    841         // empirical study. VMS needs to come first because some VMS systems
    842         // also respond with "UNIX emulation", which is not perfect. It is much
    843         // more reliable to talk to these servers in their native language.
    844         if (line.find("vms") != std::string::npos) {
    845           system_type_ = SYSTEM_TYPE_VMS;
    846         } else if (line.find("l8") != std::string::npos ||
    847                    line.find("unix") != std::string::npos ||
    848                    line.find("bsd") != std::string::npos) {
    849           system_type_ = SYSTEM_TYPE_UNIX;
    850         } else if (line.find("win32") != std::string::npos ||
    851                    line.find("windows") != std::string::npos) {
    852           system_type_ = SYSTEM_TYPE_WINDOWS;
    853         } else if (line.find("os/2") != std::string::npos) {
    854           system_type_ = SYSTEM_TYPE_OS2;
    855         }
    856       }
    857       next_state_ = STATE_CTRL_WRITE_PWD;
    858       break;
    859     }
    860     case ERROR_CLASS_INFO_NEEDED:
    861       return Stop(ERR_INVALID_RESPONSE);
    862     case ERROR_CLASS_TRANSIENT_ERROR:
    863       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    864     case ERROR_CLASS_PERMANENT_ERROR:
    865       // Server does not recognize the SYST command so proceed.
    866       next_state_ = STATE_CTRL_WRITE_PWD;
    867       break;
    868     default:
    869       NOTREACHED();
    870       return Stop(ERR_UNEXPECTED);
    871   }
    872   return OK;
    873 }
    874 
    875 // PWD command.
    876 int FtpNetworkTransaction::DoCtrlWritePWD() {
    877   std::string command = "PWD";
    878   next_state_ = STATE_CTRL_READ;
    879   return SendFtpCommand(command, command, COMMAND_PWD);
    880 }
    881 
    882 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) {
    883   switch (GetErrorClass(response.status_code)) {
    884     case ERROR_CLASS_INITIATED:
    885       return Stop(ERR_INVALID_RESPONSE);
    886     case ERROR_CLASS_OK: {
    887       // The info we look for should be on the first line.
    888       std::string line = response.lines[0];
    889       if (line.empty())
    890         return Stop(ERR_INVALID_RESPONSE);
    891       std::string::size_type quote_pos = line.find('"');
    892       if (quote_pos != std::string::npos) {
    893         line = line.substr(quote_pos + 1);
    894         quote_pos = line.find('"');
    895         if (quote_pos == std::string::npos)
    896           return Stop(ERR_INVALID_RESPONSE);
    897         line = line.substr(0, quote_pos);
    898       }
    899       if (system_type_ == SYSTEM_TYPE_VMS)
    900         line = FtpUtil::VMSPathToUnix(line);
    901       if (line.length() && line[line.length() - 1] == '/')
    902         line.erase(line.length() - 1);
    903       current_remote_directory_ = line;
    904       next_state_ = STATE_CTRL_WRITE_TYPE;
    905       break;
    906     }
    907     case ERROR_CLASS_INFO_NEEDED:
    908       return Stop(ERR_INVALID_RESPONSE);
    909     case ERROR_CLASS_TRANSIENT_ERROR:
    910       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    911     case ERROR_CLASS_PERMANENT_ERROR:
    912       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    913     default:
    914       NOTREACHED();
    915       return Stop(ERR_UNEXPECTED);
    916   }
    917   return OK;
    918 }
    919 
    920 // TYPE command.
    921 int FtpNetworkTransaction::DoCtrlWriteTYPE() {
    922   std::string command = "TYPE ";
    923   if (data_type_ == DATA_TYPE_ASCII) {
    924     command += "A";
    925   } else if (data_type_ == DATA_TYPE_IMAGE) {
    926     command += "I";
    927   } else {
    928     NOTREACHED();
    929     return Stop(ERR_UNEXPECTED);
    930   }
    931   next_state_ = STATE_CTRL_READ;
    932   return SendFtpCommand(command, command, COMMAND_TYPE);
    933 }
    934 
    935 int FtpNetworkTransaction::ProcessResponseTYPE(
    936     const FtpCtrlResponse& response) {
    937   switch (GetErrorClass(response.status_code)) {
    938     case ERROR_CLASS_INITIATED:
    939       return Stop(ERR_INVALID_RESPONSE);
    940     case ERROR_CLASS_OK:
    941       next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
    942       break;
    943     case ERROR_CLASS_INFO_NEEDED:
    944       return Stop(ERR_INVALID_RESPONSE);
    945     case ERROR_CLASS_TRANSIENT_ERROR:
    946       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    947     case ERROR_CLASS_PERMANENT_ERROR:
    948       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
    949     default:
    950       NOTREACHED();
    951       return Stop(ERR_UNEXPECTED);
    952   }
    953   return OK;
    954 }
    955 
    956 // EPSV command
    957 int FtpNetworkTransaction::DoCtrlWriteEPSV() {
    958   const std::string command = "EPSV";
    959   next_state_ = STATE_CTRL_READ;
    960   return SendFtpCommand(command, command, COMMAND_EPSV);
    961 }
    962 
    963 int FtpNetworkTransaction::ProcessResponseEPSV(
    964     const FtpCtrlResponse& response) {
    965   switch (GetErrorClass(response.status_code)) {
    966     case ERROR_CLASS_INITIATED:
    967       return Stop(ERR_INVALID_RESPONSE);
    968     case ERROR_CLASS_OK:
    969       if (!ExtractPortFromEPSVResponse( response, &data_connection_port_))
    970         return Stop(ERR_INVALID_RESPONSE);
    971       if (data_connection_port_ < 1024 ||
    972           !IsPortAllowedByFtp(data_connection_port_))
    973         return Stop(ERR_UNSAFE_PORT);
    974       next_state_ = STATE_DATA_CONNECT;
    975       break;
    976     case ERROR_CLASS_INFO_NEEDED:
    977       return Stop(ERR_INVALID_RESPONSE);
    978     case ERROR_CLASS_TRANSIENT_ERROR:
    979     case ERROR_CLASS_PERMANENT_ERROR:
    980       use_epsv_ = false;
    981       next_state_ = STATE_CTRL_WRITE_PASV;
    982       return OK;
    983     default:
    984       NOTREACHED();
    985       return Stop(ERR_UNEXPECTED);
    986   }
    987   return OK;
    988 }
    989 
    990 // PASV command
    991 int FtpNetworkTransaction::DoCtrlWritePASV() {
    992   std::string command = "PASV";
    993   next_state_ = STATE_CTRL_READ;
    994   return SendFtpCommand(command, command, COMMAND_PASV);
    995 }
    996 
    997 int FtpNetworkTransaction::ProcessResponsePASV(
    998     const FtpCtrlResponse& response) {
    999   switch (GetErrorClass(response.status_code)) {
   1000     case ERROR_CLASS_INITIATED:
   1001       return Stop(ERR_INVALID_RESPONSE);
   1002     case ERROR_CLASS_OK:
   1003       if (!ExtractPortFromPASVResponse(response, &data_connection_port_))
   1004         return Stop(ERR_INVALID_RESPONSE);
   1005       if (data_connection_port_ < 1024 ||
   1006           !IsPortAllowedByFtp(data_connection_port_))
   1007         return Stop(ERR_UNSAFE_PORT);
   1008       next_state_ = STATE_DATA_CONNECT;
   1009       break;
   1010     case ERROR_CLASS_INFO_NEEDED:
   1011       return Stop(ERR_INVALID_RESPONSE);
   1012     case ERROR_CLASS_TRANSIENT_ERROR:
   1013       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1014     case ERROR_CLASS_PERMANENT_ERROR:
   1015       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1016     default:
   1017       NOTREACHED();
   1018       return Stop(ERR_UNEXPECTED);
   1019   }
   1020   return OK;
   1021 }
   1022 
   1023 // RETR command
   1024 int FtpNetworkTransaction::DoCtrlWriteRETR() {
   1025   std::string command = "RETR " + GetRequestPathForFtpCommand(false);
   1026   next_state_ = STATE_CTRL_READ;
   1027   return SendFtpCommand(command, command, COMMAND_RETR);
   1028 }
   1029 
   1030 int FtpNetworkTransaction::ProcessResponseRETR(
   1031     const FtpCtrlResponse& response) {
   1032   switch (GetErrorClass(response.status_code)) {
   1033     case ERROR_CLASS_INITIATED:
   1034       // We want the client to start reading the response at this point.
   1035       // It got here either through Start or RestartWithAuth. We want that
   1036       // method to complete. Not setting next state here will make DoLoop exit
   1037       // and in turn make Start/RestartWithAuth complete.
   1038       resource_type_ = RESOURCE_TYPE_FILE;
   1039       break;
   1040     case ERROR_CLASS_OK:
   1041       resource_type_ = RESOURCE_TYPE_FILE;
   1042       next_state_ = STATE_CTRL_WRITE_QUIT;
   1043       break;
   1044     case ERROR_CLASS_INFO_NEEDED:
   1045       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1046     case ERROR_CLASS_TRANSIENT_ERROR:
   1047       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1048     case ERROR_CLASS_PERMANENT_ERROR:
   1049       // Code 550 means "Failed to open file". Other codes are unrelated,
   1050       // like "Not logged in" etc.
   1051       if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE)
   1052         return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1053 
   1054       // It's possible that RETR failed because the path is a directory.
   1055       resource_type_ = RESOURCE_TYPE_DIRECTORY;
   1056 
   1057       // We're going to try CWD next, but first send a PASV one more time,
   1058       // because some FTP servers, including FileZilla, require that.
   1059       // See http://crbug.com/25316.
   1060       next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
   1061       break;
   1062     default:
   1063       NOTREACHED();
   1064       return Stop(ERR_UNEXPECTED);
   1065   }
   1066 
   1067   // We should be sure about our resource type now. Otherwise we risk
   1068   // an infinite loop (RETR can later send CWD, and CWD can later send RETR).
   1069   DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_);
   1070 
   1071   return OK;
   1072 }
   1073 
   1074 // SIZE command
   1075 int FtpNetworkTransaction::DoCtrlWriteSIZE() {
   1076   std::string command = "SIZE " + GetRequestPathForFtpCommand(false);
   1077   next_state_ = STATE_CTRL_READ;
   1078   return SendFtpCommand(command, command, COMMAND_SIZE);
   1079 }
   1080 
   1081 int FtpNetworkTransaction::ProcessResponseSIZE(
   1082     const FtpCtrlResponse& response) {
   1083   State state_after_size;
   1084   if (resource_type_ == RESOURCE_TYPE_FILE)
   1085     state_after_size = STATE_CTRL_WRITE_RETR;
   1086   else
   1087     state_after_size = STATE_CTRL_WRITE_CWD;
   1088 
   1089   switch (GetErrorClass(response.status_code)) {
   1090     case ERROR_CLASS_INITIATED:
   1091       next_state_ = state_after_size;
   1092       break;
   1093     case ERROR_CLASS_OK:
   1094       if (response.lines.size() != 1)
   1095         return Stop(ERR_INVALID_RESPONSE);
   1096       int64 size;
   1097       if (!base::StringToInt64(response.lines[0], &size))
   1098         return Stop(ERR_INVALID_RESPONSE);
   1099       if (size < 0)
   1100         return Stop(ERR_INVALID_RESPONSE);
   1101 
   1102       // A successful response to SIZE does not mean the resource is a file.
   1103       // Some FTP servers (for example, the qnx one) send a SIZE even for
   1104       // directories.
   1105       response_.expected_content_size = size;
   1106 
   1107       next_state_ = state_after_size;
   1108       break;
   1109     case ERROR_CLASS_INFO_NEEDED:
   1110       next_state_ = state_after_size;
   1111       break;
   1112     case ERROR_CLASS_TRANSIENT_ERROR:
   1113       ResetDataConnectionAfterError(state_after_size);
   1114       break;
   1115     case ERROR_CLASS_PERMANENT_ERROR:
   1116       // It's possible that SIZE failed because the path is a directory.
   1117       if (resource_type_ == RESOURCE_TYPE_UNKNOWN &&
   1118           response.status_code != 550) {
   1119         return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1120       }
   1121 
   1122       ResetDataConnectionAfterError(state_after_size);
   1123       break;
   1124     default:
   1125       NOTREACHED();
   1126       return Stop(ERR_UNEXPECTED);
   1127   }
   1128 
   1129   return OK;
   1130 }
   1131 
   1132 // CWD command
   1133 int FtpNetworkTransaction::DoCtrlWriteCWD() {
   1134   std::string command = "CWD " + GetRequestPathForFtpCommand(true);
   1135   next_state_ = STATE_CTRL_READ;
   1136   return SendFtpCommand(command, command, COMMAND_CWD);
   1137 }
   1138 
   1139 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) {
   1140   // We should never issue CWD if we know the target resource is a file.
   1141   DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_);
   1142 
   1143   switch (GetErrorClass(response.status_code)) {
   1144     case ERROR_CLASS_INITIATED:
   1145       return Stop(ERR_INVALID_RESPONSE);
   1146     case ERROR_CLASS_OK:
   1147       next_state_ = STATE_CTRL_WRITE_LIST;
   1148       break;
   1149     case ERROR_CLASS_INFO_NEEDED:
   1150       return Stop(ERR_INVALID_RESPONSE);
   1151     case ERROR_CLASS_TRANSIENT_ERROR:
   1152       // Some FTP servers send response 451 (not a valid CWD response according
   1153       // to RFC 959) instead of 550.
   1154       if (response.status_code == 451)
   1155         return ProcessResponseCWDNotADirectory();
   1156 
   1157       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1158     case ERROR_CLASS_PERMANENT_ERROR:
   1159       if (response.status_code == 550)
   1160         return ProcessResponseCWDNotADirectory();
   1161 
   1162       return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
   1163     default:
   1164       NOTREACHED();
   1165       return Stop(ERR_UNEXPECTED);
   1166   }
   1167 
   1168   return OK;
   1169 }
   1170 
   1171 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() {
   1172   if (resource_type_ == RESOURCE_TYPE_DIRECTORY) {
   1173     // We're assuming that the resource is a directory, but the server
   1174     // says it's not true. The most probable interpretation is that it
   1175     // doesn't exist (with FTP we can't be sure).
   1176     return Stop(ERR_FILE_NOT_FOUND);
   1177   }
   1178 
   1179   // We are here because SIZE failed and we are not sure what the resource
   1180   // type is. It could still be file, and SIZE could fail because of
   1181   // an access error (http://crbug.com/56734). Try RETR just to be sure.
   1182   resource_type_ = RESOURCE_TYPE_FILE;
   1183 
   1184   ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR);
   1185   return OK;
   1186 }
   1187 
   1188 // LIST command
   1189 int FtpNetworkTransaction::DoCtrlWriteLIST() {
   1190   // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option
   1191   // forces LIST output instead of NLST (which would be ambiguous for us
   1192   // to parse).
   1193   std::string command("LIST -l");
   1194   if (system_type_ == SYSTEM_TYPE_VMS)
   1195     command = "LIST *.*;0";
   1196 
   1197   next_state_ = STATE_CTRL_READ;
   1198   return SendFtpCommand(command, command, COMMAND_LIST);
   1199 }
   1200 
   1201 int FtpNetworkTransaction::ProcessResponseLIST(
   1202     const FtpCtrlResponse& response) {
   1203   switch (GetErrorClass(response.status_code)) {
   1204     case ERROR_CLASS_INITIATED:
   1205       // We want the client to start reading the response at this point.
   1206       // It got here either through Start or RestartWithAuth. We want that
   1207       // method to complete. Not setting next state here will make DoLoop exit
   1208       // and in turn make Start/RestartWithAuth complete.
   1209       response_.is_directory_listing = true;
   1210       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
   1229 int FtpNetworkTransaction::DoCtrlWriteQUIT() {
   1230   std::string command = "QUIT";
   1231   next_state_ = STATE_CTRL_READ;
   1232   return SendFtpCommand(command, command, COMMAND_QUIT);
   1233 }
   1234 
   1235 int FtpNetworkTransaction::ProcessResponseQUIT(
   1236     const FtpCtrlResponse& response) {
   1237   ctrl_socket_->Disconnect();
   1238   return last_error_;
   1239 }
   1240 
   1241 // Data Connection
   1242 
   1243 int FtpNetworkTransaction::DoDataConnect() {
   1244   next_state_ = STATE_DATA_CONNECT_COMPLETE;
   1245   IPEndPoint ip_endpoint;
   1246   AddressList data_address;
   1247   // Connect to the same host as the control socket to prevent PASV port
   1248   // scanning attacks.
   1249   int rv = ctrl_socket_->GetPeerAddress(&ip_endpoint);
   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 
   1262 int FtpNetworkTransaction::DoDataConnectComplete(int result) {
   1263   if (result != OK && use_epsv_) {
   1264     // It's possible we hit a broken server, sadly. They can break in different
   1265     // ways. Some time out, some reset a connection. Fall back to PASV.
   1266     // TODO(phajdan.jr): remember it for future transactions with this server.
   1267     // TODO(phajdan.jr): write a test for this code path.
   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 
   1284 int 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 
   1310 int 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.
   1322 void FtpNetworkTransaction::RecordDataConnectionError(int result) {
   1323   // Gather data for http://crbug.com/3073. See how many users have trouble
   1324   // establishing FTP data connection in passive FTP mode.
   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