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