ftp_network_transaction.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/ftp/ftp_network_transaction.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_number_conversions.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_split.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/address_list.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/connection_type_histograms.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/ftp/ftp_network_session.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/ftp/ftp_request_info.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/ftp/ftp_util.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/socket/client_socket_factory.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/socket/stream_socket.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kCRLF[] = "\r\n"; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCtrlBufLen = 1024; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |input| can be safely used as a part of FTP command. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidFTPCommandString(const std::string& input) { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RFC 959 only allows ASCII strings, but at least Firefox can send non-ASCII 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // characters in the command if the request path contains them. To be 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // compatible, we do the same and allow non-ASCII characters in a command. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Protect agains newline injection attack. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (input.find_first_of("\r\n") != std::string::npos) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum ErrorClass { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The requested action was initiated. The client should expect another 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reply before issuing the next command. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ERROR_CLASS_INITIATED, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The requested action has been successfully completed. 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ERROR_CLASS_OK, 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The command has been accepted, but to complete the operation, more 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // information must be sent by the client. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ERROR_CLASS_INFO_NEEDED, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The command was not accepted and the requested action did not take place. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This condition is temporary, and the client is encouraged to restart the 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // command sequence. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ERROR_CLASS_TRANSIENT_ERROR, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The command was not accepted and the requested action did not take place. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This condition is rather permanent, and the client is discouraged from 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // repeating the exact request. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ERROR_CLASS_PERMANENT_ERROR, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the error class for given response code. Caller should ensure 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that |response_code| is in range 100-599. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ErrorClass GetErrorClass(int response_code) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_code >= 100 && response_code <= 199) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERROR_CLASS_INITIATED; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_code >= 200 && response_code <= 299) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERROR_CLASS_OK; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_code >= 300 && response_code <= 399) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERROR_CLASS_INFO_NEEDED; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_code >= 400 && response_code <= 499) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERROR_CLASS_TRANSIENT_ERROR; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response_code >= 500 && response_code <= 599) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERROR_CLASS_PERMANENT_ERROR; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should not be called on invalid error codes. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << response_code; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERROR_CLASS_PERMANENT_ERROR; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns network error code for received FTP |response_code|. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetNetErrorCodeForFtpResponseCode(int response_code) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (response_code) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 421: 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net::ERR_FTP_SERVICE_UNAVAILABLE; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 426: 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net::ERR_FTP_TRANSFER_ABORTED; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 450: 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net::ERR_FTP_FILE_BUSY; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 500: 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 501: 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net::ERR_FTP_SYNTAX_ERROR; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 502: 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 504: 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net::ERR_FTP_COMMAND_NOT_SUPPORTED; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 503: 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net::ERR_FTP_BAD_COMMAND_SEQUENCE; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return net::ERR_FTP_FAILED; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// From RFC 2428 Section 3: 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The text returned in response to the EPSV command MUST be: 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <some text> (<d><d><d><tcp-port><d>) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <d> is a delimiter character, ideally to be | 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtractPortFromEPSVResponse(const net::FtpCtrlResponse& response, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* port) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.lines.size() != 1) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* ptr = response.lines[0].c_str(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*ptr && *ptr != '(') 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++ptr; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*ptr) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char sep = *(++ptr); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!sep || isdigit(sep) || *(++ptr) != sep || *(++ptr) != sep) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!isdigit(*(++ptr))) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *port = *ptr - '0'; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (isdigit(*(++ptr))) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *port *= 10; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *port += *ptr - '0'; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*ptr != sep) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There are two way we can receive IP address and port. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (127,0,0,1,23,21) IP address and port encapsulated in (). 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 127,0,0,1,23,21 IP address and port without (). 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See RFC 959, Section 4.1.2 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtractPortFromPASVResponse(const net::FtpCtrlResponse& response, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* port) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.lines.size() != 1) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string line(response.lines[0]); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsStringASCII(line)) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line.length() < 2) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t paren_pos = line.find('('); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (paren_pos == std::string::npos) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Find the first comma and use it to locate the beginning 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of the response data. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t comma_pos = line.find(','); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (comma_pos == std::string::npos) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t space_pos = line.rfind(' ', comma_pos); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (space_pos != std::string::npos) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.substr(space_pos + 1); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the parentheses and use the text inside them. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t closing_paren_pos = line.rfind(')'); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (closing_paren_pos == std::string::npos) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (closing_paren_pos <= paren_pos) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.substr(paren_pos + 1, closing_paren_pos - paren_pos - 1); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Split the line into comma-separated pieces and extract 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the last two. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> pieces; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(line, ',', &pieces); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pieces.size() != 6) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore the IP address supplied in the response. We are always going 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to connect back to the same server to prevent FTP PASV port scanning. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int p0, p1; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt(pieces[4], &p0)) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt(pieces[5], &p1)) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *port = (p0 << 8) + p1; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FtpNetworkTransaction::FtpNetworkTransaction( 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FtpNetworkSession* session, 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClientSocketFactory* socket_factory) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : command_sent_(COMMAND_NONE), 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ALLOW_THIS_IN_INITIALIZER_LIST( 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_callback_(base::Bind(&FtpNetworkTransaction::OnIOComplete, 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this)))), 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_(session), 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_(NULL), 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resolver_(session->host_resolver()), 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_response_buffer_(NULL), 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_len_(0), 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_(OK), 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_(SYSTEM_TYPE_UNKNOWN), 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use image (binary) transfer by default. It should always work, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whereas the ascii transfer may damage binary data. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_type_(DATA_TYPE_IMAGE), 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_(RESOURCE_TYPE_UNKNOWN), 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_epsv_(true), 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_connection_port_(0), 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) socket_factory_(socket_factory), 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_(STATE_NONE) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FtpNetworkTransaction::~FtpNetworkTransaction() { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::Stop(int error) { 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_QUIT) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_QUIT; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = error; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::RestartIgnoringLastError( 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_NOT_IMPLEMENTED; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BoundNetLog& net_log) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_ = net_log; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_ = request_info; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request_->url.has_username()) { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 username; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 password; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetIdentityFromURL(request_->url, &username, &password); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials_.Set(username, password); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials_.Set(ASCIIToUTF16("anonymous"), 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASCIIToUTF16("chrome@example.com")); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DetectTypecode(); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_RESOLVE_HOST; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(OK); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_ = callback; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetStateForRestart(); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials_ = credentials; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_RESOLVE_HOST; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(OK); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_ = callback; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::Read(IOBuffer* buf, 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int buf_len, 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(buf); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(buf_len, 0); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_ = buf; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_len_ = buf_len; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_READ; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(OK); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_ = callback; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &response_; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LoadState FtpNetworkTransaction::GetLoadState() const { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_CTRL_RESOLVE_HOST_COMPLETE) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_RESOLVING_HOST; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_CTRL_CONNECT_COMPLETE || 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ == STATE_DATA_CONNECT_COMPLETE) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_CONNECTING; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_DATA_READ_COMPLETE) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_READING_RESPONSE; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_RETR && read_data_buf_.get()) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_READING_RESPONSE; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_QUIT) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_IDLE; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ != COMMAND_NONE) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_SENDING_REQUEST; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_IDLE; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint64 FtpNetworkTransaction::GetUploadProgress() const { 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::ResetStateForRestart() { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_sent_ = COMMAND_NONE; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_.Reset(); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_ = FtpResponseInfo(); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_ = NULL; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_len_ = 0; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_buf_) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_->SetOffset(0); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = OK; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_connection_port_ = 0; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_socket_.reset(); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_socket_.reset(); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_NONE; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::DoCallback(int rv) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv != ERR_IO_PENDING); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!user_callback_.is_null()); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since Run may result in Read being called, clear callback_ up front. 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback c = user_callback_; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_.Reset(); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c.Run(rv); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::OnIOComplete(int result) { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(result); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != ERR_IO_PENDING) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoCallback(rv); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessCtrlResponse() { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = OK; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (command_sent_) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_NONE: 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(phajdan.jr): Check for errors in the welcome message. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_USER; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_USER: 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseUSER(response); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_PASS: 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponsePASS(response); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_SYST: 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseSYST(response); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_PWD: 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponsePWD(response); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_TYPE: 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseTYPE(response); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_EPSV: 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseEPSV(response); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_PASV: 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponsePASV(response); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_SIZE: 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseSIZE(response); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_RETR: 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseRETR(response); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_CWD: 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseCWD(response); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_LIST: 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseLIST(response); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_QUIT: 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseQUIT(response); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_UNEXPECTED; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We may get multiple responses for some commands, 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // see http://crbug.com/18036. 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) { 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = ctrl_response_buffer_->PopResponse(); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (command_sent_) { 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_RETR: 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseRETR(response); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_LIST: 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseLIST(response); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Multiple responses for other commands are invalid. 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used to prepare and send FTP command. 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::SendFtpCommand(const std::string& command, 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_for_log, 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Command cmd) { 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we send a new command when we still have unprocessed responses 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for previous commands, the response receiving code will have no way to know 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which responses are for which command. 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!ctrl_response_buffer_->ResponseAvailable()); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!write_command_buf_); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!write_buf_); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsValidFTPCommandString(command)) { 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callers should validate the command themselves and return a more specific 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // error code. 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_sent_ = cmd; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_command_buf_ = new IOBufferWithSize(command.length() + 2); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_ = new DrainableIOBuffer(write_command_buf_, 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_command_buf_->size()); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(write_command_buf_->data(), command.data(), command.length()); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT, 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::StringCallback("command", &command_for_log)); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_directory) const { 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string path(current_remote_directory_); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request_->url.has_path()) { 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string gurl_path(request_->url.path()); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::size_type pos = gurl_path.rfind(';'); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pos != std::string::npos) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gurl_path.resize(pos); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.append(gurl_path); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure that if the path is expected to be a file, it won't end 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with a trailing slash. 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/') 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.erase(path.length() - 1); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnescapeRule::URL_SPECIAL_CHARS; 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This may unescape to non-ASCII characters, but we allow that. See the 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comment for IsValidFTPCommandString. 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = net::UnescapeURLComponent(path, unescape_rules); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (system_type_ == SYSTEM_TYPE_VMS) { 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_directory) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = FtpUtil::UnixDirectoryPathToVMS(path); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = FtpUtil::UnixFilePathToVMS(path); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsValidFTPCommandString(path)); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return path; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::DetectTypecode() { 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!request_->url.has_path()) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string gurl_path(request_->url.path()); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path. 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::size_type pos = gurl_path.rfind(';'); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pos == std::string::npos) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string typecode_string(gurl_path.substr(pos)); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typecode_string == ";type=a") { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_type_ = DATA_TYPE_ASCII; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (typecode_string == ";type=i") { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_type_ = DATA_TYPE_IMAGE; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (typecode_string == ";type=d") { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_DIRECTORY; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoLoop(int result) { 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(next_state_ != STATE_NONE); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = result; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) State state = next_state_; 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_NONE; 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (state) { 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_RESOLVE_HOST: 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlResolveHost(); 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_RESOLVE_HOST_COMPLETE: 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlResolveHostComplete(rv); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_CONNECT: 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlConnect(); 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_CONNECT_COMPLETE: 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlConnectComplete(rv); 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_READ: 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlRead(); 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_READ_COMPLETE: 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlReadComplete(rv); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE: 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWrite(); 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_COMPLETE: 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteComplete(rv); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_USER: 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteUSER(); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_PASS: 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWritePASS(); 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_SYST: 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteSYST(); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_PWD: 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWritePWD(); 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_TYPE: 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteTYPE(); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_EPSV: 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteEPSV(); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_PASV: 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWritePASV(); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_RETR: 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteRETR(); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_SIZE: 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteSIZE(); 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_CWD: 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteCWD(); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_LIST: 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteLIST(); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_QUIT: 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteQUIT(); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_CONNECT: 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataConnect(); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_CONNECT_COMPLETE: 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataConnectComplete(rv); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_READ: 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataRead(); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_READ_COMPLETE: 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataReadComplete(rv); 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "bad state"; 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ERR_UNEXPECTED; 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlResolveHost() { 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE; 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url)); 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No known referrer. 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return resolver_.Resolve( 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info, &addresses_, 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)), 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_); 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == OK) 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_CONNECT; 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlConnect() { 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_CONNECT_COMPLETE; 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_socket_.reset(socket_factory_->CreateTransportClientSocket( 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addresses_, net_log_.net_log(), net_log_.source())); 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent( 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_FTP_CONTROL_CONNECTION, 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_socket_->NetLog().source().ToEventParametersCallback()); 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ctrl_socket_->Connect(io_callback_); 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlConnectComplete(int result) { 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == OK) { 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put the peer's IP address and port into the response. 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPEndPoint ip_endpoint; 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = ctrl_socket_->GetPeerAddress(&ip_endpoint); 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == OK) { 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.socket_address = HostPortPair::FromIPEndPoint(ip_endpoint); 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlRead() { 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ_COMPLETE; 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ctrl_socket_->Read(read_ctrl_buf_, kCtrlBufLen, io_callback_); 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlReadComplete(int result) { 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == 0) { 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some servers (for example Pure-FTPd) apparently close the control 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // connection when anonymous login is not permitted. For more details 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // see http://crbug.com/25023. 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_USER && 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials_.username() == ASCIIToUTF16("anonymous")) { 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.needs_auth = true; 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_EMPTY_RESPONSE); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result < 0) 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(result); 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result); 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ctrl_response_buffer_->ResponseAvailable()) { 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read more data from the control socket. 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProcessCtrlResponse(); 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWrite() { 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_COMPLETE; 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ctrl_socket_->Write(write_buf_, 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_->BytesRemaining(), 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_callback_); 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteComplete(int result) { 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result < 0) 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_->DidConsume(result); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_buf_->BytesRemaining() == 0) { 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear the write buffer. 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_ = NULL; 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_command_buf_ = NULL; 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE; 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FTP Commands and responses 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// USER Command. 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteUSER() { 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "USER " + UTF16ToUTF8(credentials_.username()); 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsValidFTPCommandString(command)) 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_MALFORMED_IDENTITY); 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, "USER ***", COMMAND_USER); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseUSER( 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_SYST; 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PASS; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.needs_auth = true; 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PASS command. 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWritePASS() { 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "PASS " + UTF16ToUTF8(credentials_.password()); 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsValidFTPCommandString(command)) 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_MALFORMED_IDENTITY); 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, "PASS ***", COMMAND_PASS); 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponsePASS( 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_SYST; 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.needs_auth = true; 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SYST command. 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteSYST() { 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "SYST"; 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_SYST); 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseSYST( 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: { 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All important info should be on the first line. 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string line = response.lines[0]; 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The response should be ASCII, which allows us to do case-insensitive 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comparisons easily. If it is not ASCII, we leave the system type 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as unknown. 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsStringASCII(line)) { 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = StringToLowerASCII(line); 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The "magic" strings we test for below have been gathered by an 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // empirical study. 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line.find("l8") != std::string::npos || 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line.find("unix") != std::string::npos || 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line.find("bsd") != std::string::npos) { 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_ = SYSTEM_TYPE_UNIX; 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (line.find("win32") != std::string::npos || 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line.find("windows") != std::string::npos) { 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_ = SYSTEM_TYPE_WINDOWS; 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (line.find("os/2") != std::string::npos) { 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_ = SYSTEM_TYPE_OS2; 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (line.find("vms") != std::string::npos) { 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_ = SYSTEM_TYPE_VMS; 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PWD; 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Server does not recognize the SYST command so proceed. 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PWD; 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PWD command. 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWritePWD() { 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "PWD"; 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_PWD); 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: { 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The info we look for should be on the first line. 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string line = response.lines[0]; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line.empty()) 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::size_type quote_pos = line.find('"'); 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (quote_pos != std::string::npos) { 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.substr(quote_pos + 1); 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quote_pos = line.find('"'); 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (quote_pos == std::string::npos) 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.substr(0, quote_pos); 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (system_type_ == SYSTEM_TYPE_VMS) 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = FtpUtil::VMSPathToUnix(line); 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line.length() && line[line.length() - 1] == '/') 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line.erase(line.length() - 1); 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_remote_directory_ = line; 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_TYPE; 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TYPE command. 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteTYPE() { 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "TYPE "; 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_type_ == DATA_TYPE_ASCII) { 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command += "A"; 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (data_type_ == DATA_TYPE_IMAGE) { 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command += "I"; 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_TYPE); 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseTYPE( 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EPSV command 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteEPSV() { 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string command = "EPSV"; 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_EPSV); 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseEPSV( 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ExtractPortFromEPSVResponse( response, &data_connection_port_)) 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_connection_port_ < 1024 || 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !IsPortAllowedByFtp(data_connection_port_)) 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNSAFE_PORT); 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_CONNECT; 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_epsv_ = false; 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PASV; 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PASV command 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWritePASV() { 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "PASV"; 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_PASV); 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponsePASV( 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ExtractPortFromPASVResponse(response, &data_connection_port_)) 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_connection_port_ < 1024 || 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !IsPortAllowedByFtp(data_connection_port_)) 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNSAFE_PORT); 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_CONNECT; 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RETR command 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteRETR() { 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "RETR " + GetRequestPathForFtpCommand(false); 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_RETR); 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseRETR( 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want the client to start reading the response at this point. 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It got here either through Start or RestartWithAuth. We want that 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // method to complete. Not setting next state here will make DoLoop exit 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and in turn make Start/RestartWithAuth complete. 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_QUIT; 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Code 550 means "Failed to open file". Other codes are unrelated, 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // like "Not logged in" etc. 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible that RETR failed because the path is a directory. 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_DIRECTORY; 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're going to try CWD next, but first send a PASV one more time, 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because some FTP servers, including FileZilla, require that. 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See http://crbug.com/25316. 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should be sure about our resource type now. Otherwise we risk 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an infinite loop (RETR can later send CWD, and CWD can later send RETR). 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SIZE command 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteSIZE() { 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_SIZE); 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseSIZE( 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.lines.size() != 1) 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 size; 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt64(response.lines[0], &size)) 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size < 0) 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A successful response to SIZE does not mean the resource is a file. 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some FTP servers (for example, the qnx one) send a SIZE even for 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directories. 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.expected_content_size = size; 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible that SIZE failed because the path is a directory. 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response.status_code != 550) { 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resource_type_ == RESOURCE_TYPE_FILE) 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_RETR; 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_CWD; 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CWD command 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteCWD() { 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "CWD " + GetRequestPathForFtpCommand(true); 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_CWD); 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should never issue CWD if we know the target resource is a file. 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_LIST; 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some FTP servers send response 451 (not a valid CWD response according 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to RFC 959) instead of 550. 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.status_code == 451) 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProcessResponseCWDNotADirectory(); 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.status_code == 550) 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProcessResponseCWDNotADirectory(); 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're assuming that the resource is a directory, but the server 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // says it's not true. The most probable interpretation is that it 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // doesn't exist (with FTP we can't be sure). 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_FILE_NOT_FOUND); 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are here because SIZE failed and we are not sure what the resource 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // type is. It could still be file, and SIZE could fail because of 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an access error (http://crbug.com/56734). Try RETR just to be sure. 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_RETR; 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIST command 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteLIST() { 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST"); 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_LIST); 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseLIST( 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want the client to start reading the response at this point. 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It got here either through Start or RestartWithAuth. We want that 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // method to complete. Not setting next state here will make DoLoop exit 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and in turn make Start/RestartWithAuth complete. 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.is_directory_listing = true; 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.is_directory_listing = true; 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_QUIT; 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// QUIT command 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteQUIT() { 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "QUIT"; 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_QUIT); 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseQUIT( 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_socket_->Disconnect(); 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return last_error_; 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Data Connection 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataConnect() { 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_CONNECT_COMPLETE; 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPEndPoint ip_endpoint; 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddressList data_address; 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connect to the same host as the control socket to prevent PASV port 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // scanning attacks. 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = ctrl_socket_->GetPeerAddress(&ip_endpoint); 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != OK) 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(rv); 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_address = AddressList::CreateFromIPAddress( 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ip_endpoint.address(), data_connection_port_); 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_socket_.reset(socket_factory_->CreateTransportClientSocket( 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_address, net_log_.net_log(), net_log_.source())); 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent( 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_FTP_DATA_CONNECTION, 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_socket_->NetLog().source().ToEventParametersCallback()); 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data_socket_->Connect(io_callback_); 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataConnectComplete(int result) { 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != OK && use_epsv_) { 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible we hit a broken server, sadly. They can break in different 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ways. Some time out, some reset a connection. Fall back to PASV. 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(phajdan.jr): remember it for future transactions with this server. 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(phajdan.jr): write a test for this code path. 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_epsv_ = false; 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PASV; 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only record the connection error after we've applied all our fallbacks. 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to capture the final error, one we're not going to recover from. 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordDataConnectionError(result); 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != OK) 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(result); 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_SIZE; 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataRead() { 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(read_data_buf_); 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(read_data_buf_len_, 0); 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_socket_ == NULL || !data_socket_->IsConnected()) { 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't destroy the data socket completely, some servers will wait 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for us (http://crbug.com/21127). The half-closed TCP connection needs 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be closed on our side too. 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_socket_.reset(); 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctrl_socket_->IsConnected()) { 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait for the server's response, we should get it before sending QUIT. 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are no longer connected to the server, so just finish the transaction. 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(OK); 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_READ_COMPLETE; 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_->data()[0] = 0; 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data_socket_->Read(read_data_buf_, read_data_buf_len_, io_callback_); 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataReadComplete(int result) { 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We're using a histogram as a group of counters, with one bucket for each 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// enumeration value. We're only interested in the values of the counters. 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Ignore the shape, average, and standard deviation of the histograms because 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// they are meaningless. 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We use two histograms. In the first histogram we tally whether the user has 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// seen an error of that type during the session. In the second histogram we 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// tally the total number of times the users sees each errer. 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::RecordDataConnectionError(int result) { 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gather data for http://crbug.com/3073. See how many users have trouble 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // establishing FTP data connection in passive FTP mode. 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Data connection successful. 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_OK = 0, 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Local firewall blocked the connection. 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_ACCESS_DENIED = 1, 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connection timed out. 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_TIMED_OUT = 2, 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connection has been estabilished, but then got broken (either reset 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or aborted). 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_CONNECTION_BROKEN = 3, 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connection has been refused. 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_CONNECTION_REFUSED = 4, 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No connection to the internet. 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_INTERNET_DISCONNECTED = 5, 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Could not reach the destination address. 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_ADDRESS_UNREACHABLE = 6, 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A programming error in our network stack. 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_UNEXPECTED = 7, 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Other kind of error. 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_OTHER = 20, 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NUM_OF_NET_ERROR_TYPES 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } type; 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (result) { 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case OK: 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_OK; 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_ACCESS_DENIED: 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_NETWORK_ACCESS_DENIED: 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_ACCESS_DENIED; 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_TIMED_OUT: 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_TIMED_OUT; 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_ABORTED: 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_RESET: 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_CLOSED: 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_CONNECTION_BROKEN; 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_FAILED: 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_REFUSED: 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_CONNECTION_REFUSED; 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_INTERNET_DISCONNECTED: 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_INTERNET_DISCONNECTED; 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_ADDRESS_INVALID: 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_ADDRESS_UNREACHABLE: 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_ADDRESS_UNREACHABLE; 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_UNEXPECTED: 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_UNEXPECTED; 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_OTHER; 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool had_error_type[NUM_OF_NET_ERROR_TYPES]; 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type >= 0 && type < NUM_OF_NET_ERROR_TYPES); 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!had_error_type[type]) { 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) had_error_type[type] = true; 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type, NUM_OF_NET_ERROR_TYPES); 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type, NUM_OF_NET_ERROR_TYPES); 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 1358