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