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