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