Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: net/ftp/ftp_network_transaction.cc

Issue 861193007: Do not send PASV until RETR or LIST (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/ftp/ftp_network_transaction.h" 5 #include "net/ftp/ftp_network_transaction.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 last_error_(OK), 217 last_error_(OK),
218 system_type_(SYSTEM_TYPE_UNKNOWN), 218 system_type_(SYSTEM_TYPE_UNKNOWN),
219 // Use image (binary) transfer by default. It should always work, 219 // Use image (binary) transfer by default. It should always work,
220 // whereas the ascii transfer may damage binary data. 220 // whereas the ascii transfer may damage binary data.
221 data_type_(DATA_TYPE_IMAGE), 221 data_type_(DATA_TYPE_IMAGE),
222 resource_type_(RESOURCE_TYPE_UNKNOWN), 222 resource_type_(RESOURCE_TYPE_UNKNOWN),
223 use_epsv_(true), 223 use_epsv_(true),
224 data_connection_port_(0), 224 data_connection_port_(0),
225 socket_factory_(socket_factory), 225 socket_factory_(socket_factory),
226 next_state_(STATE_NONE), 226 next_state_(STATE_NONE),
227 state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE) {} 227 state_after_data_connect_complete_(STATE_CTRL_WRITE_SIZE) {}
davidben 2015/01/27 19:58:59 This should probably be initialized to STATE_NONE
xunjieli 2015/01/27 20:55:27 Done.
228 228
229 FtpNetworkTransaction::~FtpNetworkTransaction() { 229 FtpNetworkTransaction::~FtpNetworkTransaction() {
230 } 230 }
231 231
232 int FtpNetworkTransaction::Stop(int error) { 232 int FtpNetworkTransaction::Stop(int error) {
233 if (command_sent_ == COMMAND_QUIT) 233 if (command_sent_ == COMMAND_QUIT)
234 return error; 234 return error;
235 235
236 next_state_ = STATE_CTRL_WRITE_QUIT; 236 next_state_ = STATE_CTRL_WRITE_QUIT;
237 last_error_ = error; 237 last_error_ = error;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 338 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_));
339 read_data_buf_ = NULL; 339 read_data_buf_ = NULL;
340 read_data_buf_len_ = 0; 340 read_data_buf_len_ = 0;
341 if (write_buf_.get()) 341 if (write_buf_.get())
342 write_buf_->SetOffset(0); 342 write_buf_->SetOffset(0);
343 last_error_ = OK; 343 last_error_ = OK;
344 data_connection_port_ = 0; 344 data_connection_port_ = 0;
345 ctrl_socket_.reset(); 345 ctrl_socket_.reset();
346 data_socket_.reset(); 346 data_socket_.reset();
347 next_state_ = STATE_NONE; 347 next_state_ = STATE_NONE;
348 state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE; 348 state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE;
davidben 2015/01/27 19:58:59 This should be STATE_NONE now.
xunjieli 2015/01/27 20:55:28 Done.
349 } 349 }
350 350
351 void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) { 351 void FtpNetworkTransaction::EstablishDataConnection(State state_after_connect) {
352 // The server _might_ have reset the data connection 352 // Do data connect if the state that follows data connect is RETR or LIST.
353 // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS: 353 if (state_after_connect == STATE_CTRL_WRITE_RETR ||
354 // "The server MUST close the data connection under the following 354 state_after_connect == STATE_CTRL_WRITE_LIST) {
355 // conditions: 355 state_after_data_connect_complete_ = state_after_connect;
356 // ... 356 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
davidben 2015/01/27 19:58:59 Nit: I'd probably just do rather than check + NOTR
xunjieli 2015/01/27 20:55:28 Done. Good idea. thanks
357 // 5. An irrecoverable error condition occurs.") 357 } else {
358 // 358 NOTREACHED();
359 // It is ambiguous what an irrecoverable error condition is, 359 }
360 // so we take no chances.
361 state_after_data_connect_complete_ = next_state;
362 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
363 } 360 }
364 361
365 void FtpNetworkTransaction::DoCallback(int rv) { 362 void FtpNetworkTransaction::DoCallback(int rv) {
366 DCHECK(rv != ERR_IO_PENDING); 363 DCHECK(rv != ERR_IO_PENDING);
367 DCHECK(!user_callback_.is_null()); 364 DCHECK(!user_callback_.is_null());
368 365
369 // Since Run may result in Read being called, clear callback_ up front. 366 // Since Run may result in Read being called, clear callback_ up front.
370 CompletionCallback c = user_callback_; 367 CompletionCallback c = user_callback_;
371 user_callback_.Reset(); 368 user_callback_.Reset();
372 c.Run(rv); 369 c.Run(rv);
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 next_state_ = STATE_CTRL_READ; 934 next_state_ = STATE_CTRL_READ;
938 return SendFtpCommand(command, command, COMMAND_TYPE); 935 return SendFtpCommand(command, command, COMMAND_TYPE);
939 } 936 }
940 937
941 int FtpNetworkTransaction::ProcessResponseTYPE( 938 int FtpNetworkTransaction::ProcessResponseTYPE(
942 const FtpCtrlResponse& response) { 939 const FtpCtrlResponse& response) {
943 switch (GetErrorClass(response.status_code)) { 940 switch (GetErrorClass(response.status_code)) {
944 case ERROR_CLASS_INITIATED: 941 case ERROR_CLASS_INITIATED:
945 return Stop(ERR_INVALID_RESPONSE); 942 return Stop(ERR_INVALID_RESPONSE);
946 case ERROR_CLASS_OK: 943 case ERROR_CLASS_OK:
947 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 944 next_state_ = STATE_CTRL_WRITE_SIZE;
948 break; 945 break;
949 case ERROR_CLASS_INFO_NEEDED: 946 case ERROR_CLASS_INFO_NEEDED:
950 return Stop(ERR_INVALID_RESPONSE); 947 return Stop(ERR_INVALID_RESPONSE);
951 case ERROR_CLASS_TRANSIENT_ERROR: 948 case ERROR_CLASS_TRANSIENT_ERROR:
952 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 949 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
953 case ERROR_CLASS_PERMANENT_ERROR: 950 case ERROR_CLASS_PERMANENT_ERROR:
954 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 951 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
955 default: 952 default:
956 NOTREACHED(); 953 NOTREACHED();
957 return Stop(ERR_UNEXPECTED); 954 return Stop(ERR_UNEXPECTED);
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1060 // like "Not logged in" etc. 1057 // like "Not logged in" etc.
1061 if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) 1058 if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE)
1062 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1059 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
1063 1060
1064 // It's possible that RETR failed because the path is a directory. 1061 // It's possible that RETR failed because the path is a directory.
1065 resource_type_ = RESOURCE_TYPE_DIRECTORY; 1062 resource_type_ = RESOURCE_TYPE_DIRECTORY;
1066 1063
1067 // We're going to try CWD next, but first send a PASV one more time, 1064 // We're going to try CWD next, but first send a PASV one more time,
1068 // because some FTP servers, including FileZilla, require that. 1065 // because some FTP servers, including FileZilla, require that.
1069 // See http://crbug.com/25316. 1066 // See http://crbug.com/25316.
1070 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; 1067 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
davidben 2015/01/27 19:58:59 I'm actually confused how this worked before this
xunjieli 2015/01/27 20:55:28 Done. Right, this part doesn't look correct. Thank
1071 break; 1068 break;
1072 default: 1069 default:
1073 NOTREACHED(); 1070 NOTREACHED();
1074 return Stop(ERR_UNEXPECTED); 1071 return Stop(ERR_UNEXPECTED);
1075 } 1072 }
1076 1073
1077 // We should be sure about our resource type now. Otherwise we risk 1074 // We should be sure about our resource type now. Otherwise we risk
1078 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). 1075 // an infinite loop (RETR can later send CWD, and CWD can later send RETR).
1079 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); 1076 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_);
1080 1077
1081 return OK; 1078 return OK;
1082 } 1079 }
1083 1080
1084 // SIZE command 1081 // SIZE command
1085 int FtpNetworkTransaction::DoCtrlWriteSIZE() { 1082 int FtpNetworkTransaction::DoCtrlWriteSIZE() {
1086 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 1083 std::string command = "SIZE " + GetRequestPathForFtpCommand(false);
1087 next_state_ = STATE_CTRL_READ; 1084 next_state_ = STATE_CTRL_READ;
1088 return SendFtpCommand(command, command, COMMAND_SIZE); 1085 return SendFtpCommand(command, command, COMMAND_SIZE);
1089 } 1086 }
1090 1087
1091 int FtpNetworkTransaction::ProcessResponseSIZE( 1088 int FtpNetworkTransaction::ProcessResponseSIZE(
1092 const FtpCtrlResponse& response) { 1089 const FtpCtrlResponse& response) {
1093 State state_after_size;
1094 if (resource_type_ == RESOURCE_TYPE_FILE)
1095 state_after_size = STATE_CTRL_WRITE_RETR;
1096 else
1097 state_after_size = STATE_CTRL_WRITE_CWD;
1098
1099 switch (GetErrorClass(response.status_code)) { 1090 switch (GetErrorClass(response.status_code)) {
1100 case ERROR_CLASS_INITIATED: 1091 case ERROR_CLASS_INITIATED:
1101 next_state_ = state_after_size;
1102 break; 1092 break;
1103 case ERROR_CLASS_OK: 1093 case ERROR_CLASS_OK:
1104 if (response.lines.size() != 1) 1094 if (response.lines.size() != 1)
1105 return Stop(ERR_INVALID_RESPONSE); 1095 return Stop(ERR_INVALID_RESPONSE);
1106 int64 size; 1096 int64 size;
1107 if (!base::StringToInt64(response.lines[0], &size)) 1097 if (!base::StringToInt64(response.lines[0], &size))
1108 return Stop(ERR_INVALID_RESPONSE); 1098 return Stop(ERR_INVALID_RESPONSE);
1109 if (size < 0) 1099 if (size < 0)
1110 return Stop(ERR_INVALID_RESPONSE); 1100 return Stop(ERR_INVALID_RESPONSE);
1111 1101
1112 // A successful response to SIZE does not mean the resource is a file. 1102 // A successful response to SIZE does not mean the resource is a file.
1113 // Some FTP servers (for example, the qnx one) send a SIZE even for 1103 // Some FTP servers (for example, the qnx one) send a SIZE even for
1114 // directories. 1104 // directories.
1115 response_.expected_content_size = size; 1105 response_.expected_content_size = size;
1116
1117 next_state_ = state_after_size;
1118 break; 1106 break;
1119 case ERROR_CLASS_INFO_NEEDED: 1107 case ERROR_CLASS_INFO_NEEDED:
1120 next_state_ = state_after_size;
1121 break; 1108 break;
1122 case ERROR_CLASS_TRANSIENT_ERROR: 1109 case ERROR_CLASS_TRANSIENT_ERROR:
1123 ResetDataConnectionAfterError(state_after_size);
1124 break; 1110 break;
1125 case ERROR_CLASS_PERMANENT_ERROR: 1111 case ERROR_CLASS_PERMANENT_ERROR:
1126 // It's possible that SIZE failed because the path is a directory. 1112 // It's possible that SIZE failed because the path is a directory.
1127 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 1113 if (resource_type_ == RESOURCE_TYPE_UNKNOWN &&
1128 response.status_code != 550) { 1114 response.status_code != 550) {
1129 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1115 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
1130 } 1116 }
1131
1132 ResetDataConnectionAfterError(state_after_size);
1133 break; 1117 break;
1134 default: 1118 default:
1135 NOTREACHED(); 1119 NOTREACHED();
1136 return Stop(ERR_UNEXPECTED); 1120 return Stop(ERR_UNEXPECTED);
1137 } 1121 }
1138 1122 if (resource_type_ == RESOURCE_TYPE_FILE)
1123 EstablishDataConnection(STATE_CTRL_WRITE_RETR);
1124 else
1125 next_state_ = STATE_CTRL_WRITE_CWD;
1139 return OK; 1126 return OK;
1140 } 1127 }
1141 1128
1142 // CWD command 1129 // CWD command
1143 int FtpNetworkTransaction::DoCtrlWriteCWD() { 1130 int FtpNetworkTransaction::DoCtrlWriteCWD() {
1144 std::string command = "CWD " + GetRequestPathForFtpCommand(true); 1131 std::string command = "CWD " + GetRequestPathForFtpCommand(true);
1145 next_state_ = STATE_CTRL_READ; 1132 next_state_ = STATE_CTRL_READ;
1146 return SendFtpCommand(command, command, COMMAND_CWD); 1133 return SendFtpCommand(command, command, COMMAND_CWD);
1147 } 1134 }
1148 1135
1149 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 1136 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) {
1150 // We should never issue CWD if we know the target resource is a file. 1137 // We should never issue CWD if we know the target resource is a file.
1151 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); 1138 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_);
1152 1139
1153 switch (GetErrorClass(response.status_code)) { 1140 switch (GetErrorClass(response.status_code)) {
1154 case ERROR_CLASS_INITIATED: 1141 case ERROR_CLASS_INITIATED:
1155 return Stop(ERR_INVALID_RESPONSE); 1142 return Stop(ERR_INVALID_RESPONSE);
1156 case ERROR_CLASS_OK: 1143 case ERROR_CLASS_OK:
1157 next_state_ = STATE_CTRL_WRITE_LIST; 1144 EstablishDataConnection(STATE_CTRL_WRITE_LIST);
1158 break; 1145 break;
1159 case ERROR_CLASS_INFO_NEEDED: 1146 case ERROR_CLASS_INFO_NEEDED:
1160 return Stop(ERR_INVALID_RESPONSE); 1147 return Stop(ERR_INVALID_RESPONSE);
1161 case ERROR_CLASS_TRANSIENT_ERROR: 1148 case ERROR_CLASS_TRANSIENT_ERROR:
1162 // Some FTP servers send response 451 (not a valid CWD response according 1149 // Some FTP servers send response 451 (not a valid CWD response according
1163 // to RFC 959) instead of 550. 1150 // to RFC 959) instead of 550.
1164 if (response.status_code == 451) 1151 if (response.status_code == 451)
1165 return ProcessResponseCWDNotADirectory(); 1152 return ProcessResponseCWDNotADirectory();
1166 1153
1167 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1154 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
(...skipping 16 matching lines...) Expand all
1184 // says it's not true. The most probable interpretation is that it 1171 // says it's not true. The most probable interpretation is that it
1185 // doesn't exist (with FTP we can't be sure). 1172 // doesn't exist (with FTP we can't be sure).
1186 return Stop(ERR_FILE_NOT_FOUND); 1173 return Stop(ERR_FILE_NOT_FOUND);
1187 } 1174 }
1188 1175
1189 // We are here because SIZE failed and we are not sure what the resource 1176 // We are here because SIZE failed and we are not sure what the resource
1190 // type is. It could still be file, and SIZE could fail because of 1177 // type is. It could still be file, and SIZE could fail because of
1191 // an access error (http://crbug.com/56734). Try RETR just to be sure. 1178 // an access error (http://crbug.com/56734). Try RETR just to be sure.
1192 resource_type_ = RESOURCE_TYPE_FILE; 1179 resource_type_ = RESOURCE_TYPE_FILE;
1193 1180
1194 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); 1181 EstablishDataConnection(STATE_CTRL_WRITE_RETR);
1195 return OK; 1182 return OK;
1196 } 1183 }
1197 1184
1198 // LIST command 1185 // LIST command
1199 int FtpNetworkTransaction::DoCtrlWriteLIST() { 1186 int FtpNetworkTransaction::DoCtrlWriteLIST() {
1200 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option 1187 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option
1201 // forces LIST output instead of NLST (which would be ambiguous for us 1188 // forces LIST output instead of NLST (which would be ambiguous for us
1202 // to parse). 1189 // to parse).
1203 std::string command("LIST -l"); 1190 std::string command("LIST -l");
1204 if (system_type_ == SYSTEM_TYPE_VMS) 1191 if (system_type_ == SYSTEM_TYPE_VMS)
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
1403 if (!had_error_type[type]) { 1390 if (!had_error_type[type]) {
1404 had_error_type[type] = true; 1391 had_error_type[type] = true;
1405 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", 1392 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened",
1406 type, NUM_OF_NET_ERROR_TYPES); 1393 type, NUM_OF_NET_ERROR_TYPES);
1407 } 1394 }
1408 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 1395 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount",
1409 type, NUM_OF_NET_ERROR_TYPES); 1396 type, NUM_OF_NET_ERROR_TYPES);
1410 } 1397 }
1411 1398
1412 } // namespace net 1399 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698