ftp_network_transaction.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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" 115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 125e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/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]); 155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!base::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), 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) io_callback_(base::Bind(&FtpNetworkTransaction::OnIOComplete, 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::Unretained(this))), 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) session_(session), 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_(NULL), 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resolver_(session->host_resolver()), 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_len_(0), 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_(OK), 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_(SYSTEM_TYPE_UNKNOWN), 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use image (binary) transfer by default. It should always work, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whereas the ascii transfer may damage binary data. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_type_(DATA_TYPE_IMAGE), 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_(RESOURCE_TYPE_UNKNOWN), 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_epsv_(true), 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_connection_port_(0), 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) socket_factory_(socket_factory), 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) next_state_(STATE_NONE), 2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE) {} 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FtpNetworkTransaction::~FtpNetworkTransaction() { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::Stop(int error) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_QUIT) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_QUIT; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = error; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::RestartIgnoringLastError( 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_NOT_IMPLEMENTED; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback, 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BoundNetLog& net_log) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_ = net_log; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_ = request_info; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request_->url.has_username()) { 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 username; 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 password; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetIdentityFromURL(request_->url, &username, &password); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials_.Set(username, password); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) credentials_.Set(base::ASCIIToUTF16("anonymous"), 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ASCIIToUTF16("chrome@example.com")); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DetectTypecode(); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_RESOLVE_HOST; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(OK); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_ = callback; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials, 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetStateForRestart(); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) credentials_ = credentials; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_RESOLVE_HOST; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(OK); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_ = callback; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::Read(IOBuffer* buf, 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int buf_len, 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(buf); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(buf_len, 0); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_ = buf; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_len_ = buf_len; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_READ; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(OK); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv == ERR_IO_PENDING) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_ = callback; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return &response_; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LoadState FtpNetworkTransaction::GetLoadState() const { 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_CTRL_RESOLVE_HOST_COMPLETE) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_RESOLVING_HOST; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_CTRL_CONNECT_COMPLETE || 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ == STATE_DATA_CONNECT_COMPLETE) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_CONNECTING; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_state_ == STATE_DATA_READ_COMPLETE) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_READING_RESPONSE; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_RETR && read_data_buf_.get()) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_READING_RESPONSE; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_QUIT) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_IDLE; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ != COMMAND_NONE) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_SENDING_REQUEST; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_IDLE; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint64 FtpNetworkTransaction::GetUploadProgress() const { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::ResetStateForRestart() { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_sent_ = COMMAND_NONE; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_.Reset(); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_ = FtpResponseInfo(); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_ = NULL; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_len_ = 0; 340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (write_buf_.get()) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_->SetOffset(0); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = OK; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_connection_port_ = 0; 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_socket_.reset(); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_socket_.reset(); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_NONE; 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE; 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) { 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The server _might_ have reset the data connection 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS: 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // "The server MUST close the data connection under the following 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // conditions: 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // ... 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 5. An irrecoverable error condition occurs.") 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It is ambiguous what an irrecoverable error condition is, 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // so we take no chances. 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_after_data_connect_complete_ = next_state; 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::DoCallback(int rv) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv != ERR_IO_PENDING); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!user_callback_.is_null()); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since Run may result in Read being called, clear callback_ up front. 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback c = user_callback_; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_callback_.Reset(); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c.Run(rv); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::OnIOComplete(int result) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = DoLoop(result); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != ERR_IO_PENDING) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoCallback(rv); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessCtrlResponse() { 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = OK; 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (command_sent_) { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_NONE: 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(phajdan.jr): Check for errors in the welcome message. 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_USER; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_USER: 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseUSER(response); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_PASS: 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponsePASS(response); 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_SYST: 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseSYST(response); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_PWD: 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponsePWD(response); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_TYPE: 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseTYPE(response); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_EPSV: 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseEPSV(response); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_PASV: 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponsePASV(response); 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_SIZE: 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseSIZE(response); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_RETR: 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseRETR(response); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_CWD: 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseCWD(response); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_LIST: 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseLIST(response); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_QUIT: 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseQUIT(response); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_UNEXPECTED; 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We may get multiple responses for some commands, 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // see http://crbug.com/18036. 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) { 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = ctrl_response_buffer_->PopResponse(); 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (command_sent_) { 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_RETR: 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseRETR(response); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case COMMAND_LIST: 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ProcessResponseLIST(response); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Multiple responses for other commands are invalid. 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used to prepare and send FTP command. 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::SendFtpCommand(const std::string& command, 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_for_log, 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Command cmd) { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we send a new command when we still have unprocessed responses 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for previous commands, the response receiving code will have no way to know 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which responses are for which command. 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!ctrl_response_buffer_->ResponseAvailable()); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 460868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!write_command_buf_.get()); 461868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!write_buf_.get()); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsValidFTPCommandString(command)) { 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callers should validate the command themselves and return a more specific 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // error code. 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_sent_ = cmd; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_command_buf_ = new IOBufferWithSize(command.length() + 2); 473868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) write_buf_ = new DrainableIOBuffer(write_command_buf_.get(), 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_command_buf_->size()); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(write_command_buf_->data(), command.data(), command.length()); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT, 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::StringCallback("command", &command_for_log)); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE; 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_directory) const { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string path(current_remote_directory_); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request_->url.has_path()) { 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string gurl_path(request_->url.path()); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::size_type pos = gurl_path.rfind(';'); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pos != std::string::npos) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gurl_path.resize(pos); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.append(gurl_path); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure that if the path is expected to be a file, it won't end 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with a trailing slash. 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/') 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.erase(path.length() - 1); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnescapeRule::URL_SPECIAL_CHARS; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This may unescape to non-ASCII characters, but we allow that. See the 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comment for IsValidFTPCommandString. 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = net::UnescapeURLComponent(path, unescape_rules); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (system_type_ == SYSTEM_TYPE_VMS) { 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_directory) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = FtpUtil::UnixDirectoryPathToVMS(path); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = FtpUtil::UnixFilePathToVMS(path); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsValidFTPCommandString(path)); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return path; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::DetectTypecode() { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!request_->url.has_path()) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string gurl_path(request_->url.path()); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extract the typecode, see RFC 1738 section 3.2.2. FTP url-path. 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::size_type pos = gurl_path.rfind(';'); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pos == std::string::npos) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string typecode_string(gurl_path.substr(pos)); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typecode_string == ";type=a") { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_type_ = DATA_TYPE_ASCII; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (typecode_string == ";type=i") { 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_type_ = DATA_TYPE_IMAGE; 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (typecode_string == ";type=d") { 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_DIRECTORY; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoLoop(int result) { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(next_state_ != STATE_NONE); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = result; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) State state = next_state_; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_NONE; 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (state) { 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_RESOLVE_HOST: 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlResolveHost(); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_RESOLVE_HOST_COMPLETE: 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlResolveHostComplete(rv); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_CONNECT: 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlConnect(); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_CONNECT_COMPLETE: 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlConnectComplete(rv); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_READ: 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlRead(); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_READ_COMPLETE: 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlReadComplete(rv); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE: 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWrite(); 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_COMPLETE: 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteComplete(rv); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_USER: 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteUSER(); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_PASS: 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWritePASS(); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_SYST: 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteSYST(); 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_PWD: 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWritePWD(); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_TYPE: 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteTYPE(); 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_EPSV: 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteEPSV(); 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_PASV: 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWritePASV(); 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_RETR: 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteRETR(); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_SIZE: 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteSIZE(); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_CWD: 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteCWD(); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_LIST: 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteLIST(); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_CTRL_WRITE_QUIT: 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoCtrlWriteQUIT(); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_CONNECT: 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataConnect(); 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_CONNECT_COMPLETE: 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataConnectComplete(rv); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_READ: 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(rv == OK); 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataRead(); 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STATE_DATA_READ_COMPLETE: 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = DoDataReadComplete(rv); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "bad state"; 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rv = ERR_UNEXPECTED; 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rv; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlResolveHost() { 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE; 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url)); 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No known referrer. 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return resolver_.Resolve( 6533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) info, 6543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DEFAULT_PRIORITY, 6553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) &addresses_, 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)), 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_); 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == OK) 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_CONNECT; 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlConnect() { 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_CONNECT_COMPLETE; 6683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) ctrl_socket_ = socket_factory_->CreateTransportClientSocket( 6693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) addresses_, net_log_.net_log(), net_log_.source()); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent( 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_FTP_CONTROL_CONNECTION, 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_socket_->NetLog().source().ToEventParametersCallback()); 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ctrl_socket_->Connect(io_callback_); 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlConnectComplete(int result) { 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == OK) { 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Put the peer's IP address and port into the response. 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPEndPoint ip_endpoint; 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = ctrl_socket_->GetPeerAddress(&ip_endpoint); 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == OK) { 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.socket_address = HostPortPair::FromIPEndPoint(ip_endpoint); 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ip_endpoint.GetFamily() == ADDRESS_FAMILY_IPV4) { 6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Do not use EPSV for IPv4 connections. Some servers become confused 6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // and we time out while waiting to connect. PASV is perfectly fine for 6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // IPv4. Note that this blacklists IPv4 not to use EPSV instead of 6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // whitelisting IPv6 to use it, to make the code more future-proof: 6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // all future protocols should just use EPSV. 6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) use_epsv_ = false; 6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlRead() { 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ_COMPLETE; 700868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return ctrl_socket_->Read(read_ctrl_buf_.get(), kCtrlBufLen, io_callback_); 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlReadComplete(int result) { 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == 0) { 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some servers (for example Pure-FTPd) apparently close the control 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // connection when anonymous login is not permitted. For more details 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // see http://crbug.com/25023. 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_sent_ == COMMAND_USER && 7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) credentials_.username() == base::ASCIIToUTF16("anonymous")) { 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.needs_auth = true; 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_EMPTY_RESPONSE); 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result < 0) 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(result); 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result); 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ctrl_response_buffer_->ResponseAvailable()) { 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Read more data from the control socket. 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProcessCtrlResponse(); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWrite() { 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_COMPLETE; 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 731868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return ctrl_socket_->Write( 732868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) write_buf_.get(), write_buf_->BytesRemaining(), io_callback_); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteComplete(int result) { 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result < 0) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_->DidConsume(result); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_buf_->BytesRemaining() == 0) { 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear the write buffer. 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_buf_ = NULL; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_command_buf_ = NULL; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE; 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FTP Commands and responses 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// USER Command. 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteUSER() { 7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string command = "USER " + base::UTF16ToUTF8(credentials_.username()); 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsValidFTPCommandString(command)) 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_MALFORMED_IDENTITY); 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, "USER ***", COMMAND_USER); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseUSER( 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_SYST; 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PASS; 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.needs_auth = true; 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PASS command. 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWritePASS() { 7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string command = "PASS " + base::UTF16ToUTF8(credentials_.password()); 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsValidFTPCommandString(command)) 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_MALFORMED_IDENTITY); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, "PASS ***", COMMAND_PASS); 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponsePASS( 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_SYST; 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.needs_auth = true; 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SYST command. 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteSYST() { 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "SYST"; 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_SYST); 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseSYST( 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: { 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All important info should be on the first line. 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string line = response.lines[0]; 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The response should be ASCII, which allows us to do case-insensitive 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comparisons easily. If it is not ASCII, we leave the system type 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as unknown. 833010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (base::IsStringASCII(line)) { 8346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) line = base::StringToLowerASCII(line); 8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Remove all whitespace, to correctly handle cases like fancy "V M S" 8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // response instead of "VMS". 838a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::RemoveChars(line, base::kWhitespaceASCII, &line); 8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The "magic" strings we test for below have been gathered by an 8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // empirical study. VMS needs to come first because some VMS systems 8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // also respond with "UNIX emulation", which is not perfect. It is much 8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // more reliable to talk to these servers in their native language. 8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (line.find("vms") != std::string::npos) { 8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) system_type_ = SYSTEM_TYPE_VMS; 8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (line.find("l8") != std::string::npos || 8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) line.find("unix") != std::string::npos || 8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) line.find("bsd") != std::string::npos) { 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_ = SYSTEM_TYPE_UNIX; 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (line.find("win32") != std::string::npos || 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line.find("windows") != std::string::npos) { 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_ = SYSTEM_TYPE_WINDOWS; 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (line.find("os/2") != std::string::npos) { 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) system_type_ = SYSTEM_TYPE_OS2; 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PWD; 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Server does not recognize the SYST command so proceed. 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PWD; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PWD command. 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWritePWD() { 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "PWD"; 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_PWD); 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: { 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The info we look for should be on the first line. 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string line = response.lines[0]; 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line.empty()) 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::size_type quote_pos = line.find('"'); 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (quote_pos != std::string::npos) { 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.substr(quote_pos + 1); 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) quote_pos = line.find('"'); 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (quote_pos == std::string::npos) 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.substr(0, quote_pos); 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (system_type_ == SYSTEM_TYPE_VMS) 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = FtpUtil::VMSPathToUnix(line); 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line.length() && line[line.length() - 1] == '/') 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line.erase(line.length() - 1); 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_remote_directory_ = line; 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_TYPE; 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TYPE command. 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteTYPE() { 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "TYPE "; 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_type_ == DATA_TYPE_ASCII) { 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command += "A"; 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (data_type_ == DATA_TYPE_IMAGE) { 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command += "I"; 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_TYPE); 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseTYPE( 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EPSV command 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteEPSV() { 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string command = "EPSV"; 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_EPSV); 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseEPSV( 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ExtractPortFromEPSVResponse( response, &data_connection_port_)) 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_connection_port_ < 1024 || 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !IsPortAllowedByFtp(data_connection_port_)) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNSAFE_PORT); 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_CONNECT; 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_epsv_ = false; 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PASV; 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PASV command 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWritePASV() { 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "PASV"; 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_PASV); 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponsePASV( 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ExtractPortFromPASVResponse(response, &data_connection_port_)) 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_connection_port_ < 1024 || 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !IsPortAllowedByFtp(data_connection_port_)) 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNSAFE_PORT); 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_CONNECT; 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RETR command 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteRETR() { 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "RETR " + GetRequestPathForFtpCommand(false); 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_RETR); 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseRETR( 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want the client to start reading the response at this point. 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It got here either through Start or RestartWithAuth. We want that 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // method to complete. Not setting next state here will make DoLoop exit 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and in turn make Start/RestartWithAuth complete. 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_QUIT; 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Code 550 means "Failed to open file". Other codes are unrelated, 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // like "Not logged in" etc. 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible that RETR failed because the path is a directory. 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_DIRECTORY; 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're going to try CWD next, but first send a PASV one more time, 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because some FTP servers, including FileZilla, require that. 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See http://crbug.com/25316. 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should be sure about our resource type now. Otherwise we risk 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an infinite loop (RETR can later send CWD, and CWD can later send RETR). 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SIZE command 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteSIZE() { 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_SIZE); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseSIZE( 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 10832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) State state_after_size; 10842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (resource_type_ == RESOURCE_TYPE_FILE) 10852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_after_size = STATE_CTRL_WRITE_RETR; 10862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else 10872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_after_size = STATE_CTRL_WRITE_CWD; 10882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 10912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) next_state_ = state_after_size; 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.lines.size() != 1) 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 size; 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt64(response.lines[0], &size)) 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size < 0) 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A successful response to SIZE does not mean the resource is a file. 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some FTP servers (for example, the qnx one) send a SIZE even for 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // directories. 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.expected_content_size = size; 11062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) next_state_ = state_after_size; 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 11102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) next_state_ = state_after_size; 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 11132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ResetDataConnectionAfterError(state_after_size); 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible that SIZE failed because the path is a directory. 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response.status_code != 550) { 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ResetDataConnectionAfterError(state_after_size); 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CWD command 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteCWD() { 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "CWD " + GetRequestPathForFtpCommand(true); 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_CWD); 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should never issue CWD if we know the target resource is a file. 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_LIST; 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Some FTP servers send response 451 (not a valid CWD response according 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to RFC 959) instead of 550. 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.status_code == 451) 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProcessResponseCWDNotADirectory(); 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (response.status_code == 550) 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProcessResponseCWDNotADirectory(); 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're assuming that the resource is a directory, but the server 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // says it's not true. The most probable interpretation is that it 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // doesn't exist (with FTP we can't be sure). 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_FILE_NOT_FOUND); 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are here because SIZE failed and we are not sure what the resource 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // type is. It could still be file, and SIZE could fail because of 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an access error (http://crbug.com/56734). Try RETR just to be sure. 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_type_ = RESOURCE_TYPE_FILE; 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIST command 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteLIST() { 11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option 11912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // forces LIST output instead of NLST (which would be ambiguous for us 11922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to parse). 11932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string command("LIST -l"); 11942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (system_type_ == SYSTEM_TYPE_VMS) 11952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command = "LIST *.*;0"; 11962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_LIST); 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseLIST( 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (GetErrorClass(response.status_code)) { 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INITIATED: 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want the client to start reading the response at this point. 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It got here either through Start or RestartWithAuth. We want that 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // method to complete. Not setting next state here will make DoLoop exit 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and in turn make Start/RestartWithAuth complete. 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.is_directory_listing = true; 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_OK: 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response_.is_directory_listing = true; 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_QUIT; 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_INFO_NEEDED: 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_INVALID_RESPONSE); 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_TRANSIENT_ERROR: 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERROR_CLASS_PERMANENT_ERROR: 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(ERR_UNEXPECTED); 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// QUIT command 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoCtrlWriteQUIT() { 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string command = "QUIT"; 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SendFtpCommand(command, command, COMMAND_QUIT); 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::ProcessResponseQUIT( 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FtpCtrlResponse& response) { 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_socket_->Disconnect(); 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return last_error_; 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Data Connection 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataConnect() { 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_CONNECT_COMPLETE; 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPEndPoint ip_endpoint; 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddressList data_address; 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connect to the same host as the control socket to prevent PASV port 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // scanning attacks. 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = ctrl_socket_->GetPeerAddress(&ip_endpoint); 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv != OK) 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(rv); 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_address = AddressList::CreateFromIPAddress( 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ip_endpoint.address(), data_connection_port_); 12543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) data_socket_ = socket_factory_->CreateTransportClientSocket( 12553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) data_address, net_log_.net_log(), net_log_.source()); 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent( 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_FTP_DATA_CONNECTION, 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_socket_->NetLog().source().ToEventParametersCallback()); 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data_socket_->Connect(io_callback_); 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataConnectComplete(int result) { 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != OK && use_epsv_) { 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's possible we hit a broken server, sadly. They can break in different 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ways. Some time out, some reset a connection. Fall back to PASV. 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(phajdan.jr): remember it for future transactions with this server. 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(phajdan.jr): write a test for this code path. 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_epsv_ = false; 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_WRITE_PASV; 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only record the connection error after we've applied all our fallbacks. 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to capture the final error, one we're not going to recover from. 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordDataConnectionError(result); 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != OK) 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(result); 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) next_state_ = state_after_data_connect_complete_; 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataRead() { 1285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(read_data_buf_.get()); 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(read_data_buf_len_, 0); 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (data_socket_ == NULL || !data_socket_->IsConnected()) { 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we don't destroy the data socket completely, some servers will wait 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for us (http://crbug.com/21127). The half-closed TCP connection needs 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be closed on our side too. 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_socket_.reset(); 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ctrl_socket_->IsConnected()) { 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait for the server's response, we should get it before sending QUIT. 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_CTRL_READ; 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are no longer connected to the server, so just finish the transaction. 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Stop(OK); 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_state_ = STATE_DATA_READ_COMPLETE; 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_data_buf_->data()[0] = 0; 1306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return data_socket_->Read( 1307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) read_data_buf_.get(), read_data_buf_len_, io_callback_); 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int FtpNetworkTransaction::DoDataReadComplete(int result) { 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We're using a histogram as a group of counters, with one bucket for each 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// enumeration value. We're only interested in the values of the counters. 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Ignore the shape, average, and standard deviation of the histograms because 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// they are meaningless. 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We use two histograms. In the first histogram we tally whether the user has 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// seen an error of that type during the session. In the second histogram we 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// tally the total number of times the users sees each errer. 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FtpNetworkTransaction::RecordDataConnectionError(int result) { 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gather data for http://crbug.com/3073. See how many users have trouble 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // establishing FTP data connection in passive FTP mode. 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Data connection successful. 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_OK = 0, 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Local firewall blocked the connection. 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_ACCESS_DENIED = 1, 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connection timed out. 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_TIMED_OUT = 2, 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connection has been estabilished, but then got broken (either reset 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or aborted). 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_CONNECTION_BROKEN = 3, 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Connection has been refused. 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_CONNECTION_REFUSED = 4, 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No connection to the internet. 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_INTERNET_DISCONNECTED = 5, 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Could not reach the destination address. 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_ADDRESS_UNREACHABLE = 6, 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A programming error in our network stack. 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_UNEXPECTED = 7, 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Other kind of error. 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NET_ERROR_OTHER = 20, 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NUM_OF_NET_ERROR_TYPES 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } type; 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (result) { 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case OK: 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_OK; 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_ACCESS_DENIED: 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_NETWORK_ACCESS_DENIED: 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_ACCESS_DENIED; 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_TIMED_OUT: 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_TIMED_OUT; 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_ABORTED: 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_RESET: 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_CLOSED: 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_CONNECTION_BROKEN; 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_FAILED: 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_CONNECTION_REFUSED: 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_CONNECTION_REFUSED; 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_INTERNET_DISCONNECTED: 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_INTERNET_DISCONNECTED; 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_ADDRESS_INVALID: 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_ADDRESS_UNREACHABLE: 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_ADDRESS_UNREACHABLE; 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ERR_UNEXPECTED: 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_UNEXPECTED; 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type = NET_ERROR_OTHER; 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool had_error_type[NUM_OF_NET_ERROR_TYPES]; 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type >= 0 && type < NUM_OF_NET_ERROR_TYPES); 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!had_error_type[type]) { 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) had_error_type[type] = true; 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type, NUM_OF_NET_ERROR_TYPES); 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type, NUM_OF_NET_ERROR_TYPES); 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 1403