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