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

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

Issue 11364224: FTP: Open a fresh data connection after a command error. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 1 month 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 | Annotate | Revision Log
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 read_data_buf_len_(0), 217 read_data_buf_len_(0),
218 last_error_(OK), 218 last_error_(OK),
219 system_type_(SYSTEM_TYPE_UNKNOWN), 219 system_type_(SYSTEM_TYPE_UNKNOWN),
220 // Use image (binary) transfer by default. It should always work, 220 // Use image (binary) transfer by default. It should always work,
221 // whereas the ascii transfer may damage binary data. 221 // whereas the ascii transfer may damage binary data.
222 data_type_(DATA_TYPE_IMAGE), 222 data_type_(DATA_TYPE_IMAGE),
223 resource_type_(RESOURCE_TYPE_UNKNOWN), 223 resource_type_(RESOURCE_TYPE_UNKNOWN),
224 use_epsv_(true), 224 use_epsv_(true),
225 data_connection_port_(0), 225 data_connection_port_(0),
226 socket_factory_(socket_factory), 226 socket_factory_(socket_factory),
227 next_state_(STATE_NONE) { 227 next_state_(STATE_NONE),
228 state_after_data_connection_(STATE_CTRL_WRITE_SIZE) {
228 } 229 }
229 230
230 FtpNetworkTransaction::~FtpNetworkTransaction() { 231 FtpNetworkTransaction::~FtpNetworkTransaction() {
231 } 232 }
232 233
233 int FtpNetworkTransaction::Stop(int error) { 234 int FtpNetworkTransaction::Stop(int error) {
234 if (command_sent_ == COMMAND_QUIT) 235 if (command_sent_ == COMMAND_QUIT)
235 return error; 236 return error;
236 237
237 next_state_ = STATE_CTRL_WRITE_QUIT; 238 next_state_ = STATE_CTRL_WRITE_QUIT;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); 340 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_));
340 read_data_buf_ = NULL; 341 read_data_buf_ = NULL;
341 read_data_buf_len_ = 0; 342 read_data_buf_len_ = 0;
342 if (write_buf_) 343 if (write_buf_)
343 write_buf_->SetOffset(0); 344 write_buf_->SetOffset(0);
344 last_error_ = OK; 345 last_error_ = OK;
345 data_connection_port_ = 0; 346 data_connection_port_ = 0;
346 ctrl_socket_.reset(); 347 ctrl_socket_.reset();
347 data_socket_.reset(); 348 data_socket_.reset();
348 next_state_ = STATE_NONE; 349 next_state_ = STATE_NONE;
350 state_after_data_connection_ = STATE_CTRL_WRITE_SIZE;
351 }
352
353 void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) {
354 // The server _might_ have reset the data connection
355 // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS:
356 // "The server MUST close the data connection under the following
357 // conditions:
358 // ...
359 // 5. An irrecoverable error condition occurs.")
360 //
361 // It is ambiguous whan an irrecoverable error condition is,
eroman 2012/11/13 20:36:21 typo: "whan" --> "what" or "when" ?
Paweł Hajdan Jr. 2012/11/14 17:30:18 Done.
362 // so we take no chances.
363 state_after_data_connection_ = next_state;
364 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
349 } 365 }
350 366
351 void FtpNetworkTransaction::DoCallback(int rv) { 367 void FtpNetworkTransaction::DoCallback(int rv) {
352 DCHECK(rv != ERR_IO_PENDING); 368 DCHECK(rv != ERR_IO_PENDING);
353 DCHECK(!user_callback_.is_null()); 369 DCHECK(!user_callback_.is_null());
354 370
355 // Since Run may result in Read being called, clear callback_ up front. 371 // Since Run may result in Read being called, clear callback_ up front.
356 CompletionCallback c = user_callback_; 372 CompletionCallback c = user_callback_;
357 user_callback_.Reset(); 373 user_callback_.Reset();
358 c.Run(rv); 374 c.Run(rv);
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after
1043 1059
1044 // SIZE command 1060 // SIZE command
1045 int FtpNetworkTransaction::DoCtrlWriteSIZE() { 1061 int FtpNetworkTransaction::DoCtrlWriteSIZE() {
1046 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 1062 std::string command = "SIZE " + GetRequestPathForFtpCommand(false);
1047 next_state_ = STATE_CTRL_READ; 1063 next_state_ = STATE_CTRL_READ;
1048 return SendFtpCommand(command, command, COMMAND_SIZE); 1064 return SendFtpCommand(command, command, COMMAND_SIZE);
1049 } 1065 }
1050 1066
1051 int FtpNetworkTransaction::ProcessResponseSIZE( 1067 int FtpNetworkTransaction::ProcessResponseSIZE(
1052 const FtpCtrlResponse& response) { 1068 const FtpCtrlResponse& response) {
1069 State state_after_size;
1070 if (resource_type_ == RESOURCE_TYPE_FILE)
1071 state_after_size = STATE_CTRL_WRITE_RETR;
1072 else
1073 state_after_size = STATE_CTRL_WRITE_CWD;
1074
1053 switch (GetErrorClass(response.status_code)) { 1075 switch (GetErrorClass(response.status_code)) {
1054 case ERROR_CLASS_INITIATED: 1076 case ERROR_CLASS_INITIATED:
1077 next_state_ = state_after_size;
1055 break; 1078 break;
1056 case ERROR_CLASS_OK: 1079 case ERROR_CLASS_OK:
1057 if (response.lines.size() != 1) 1080 if (response.lines.size() != 1)
1058 return Stop(ERR_INVALID_RESPONSE); 1081 return Stop(ERR_INVALID_RESPONSE);
1059 int64 size; 1082 int64 size;
1060 if (!base::StringToInt64(response.lines[0], &size)) 1083 if (!base::StringToInt64(response.lines[0], &size))
1061 return Stop(ERR_INVALID_RESPONSE); 1084 return Stop(ERR_INVALID_RESPONSE);
1062 if (size < 0) 1085 if (size < 0)
1063 return Stop(ERR_INVALID_RESPONSE); 1086 return Stop(ERR_INVALID_RESPONSE);
1064 1087
1065 // A successful response to SIZE does not mean the resource is a file. 1088 // A successful response to SIZE does not mean the resource is a file.
1066 // Some FTP servers (for example, the qnx one) send a SIZE even for 1089 // Some FTP servers (for example, the qnx one) send a SIZE even for
1067 // directories. 1090 // directories.
1068 response_.expected_content_size = size; 1091 response_.expected_content_size = size;
1092
1093 next_state_ = state_after_size;
1069 break; 1094 break;
1070 case ERROR_CLASS_INFO_NEEDED: 1095 case ERROR_CLASS_INFO_NEEDED:
1096 next_state_ = state_after_size;
1071 break; 1097 break;
1072 case ERROR_CLASS_TRANSIENT_ERROR: 1098 case ERROR_CLASS_TRANSIENT_ERROR:
1099 ResetDataConnectionAfterError(state_after_size);
1073 break; 1100 break;
1074 case ERROR_CLASS_PERMANENT_ERROR: 1101 case ERROR_CLASS_PERMANENT_ERROR:
1075 // It's possible that SIZE failed because the path is a directory. 1102 // It's possible that SIZE failed because the path is a directory.
1076 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && 1103 if (resource_type_ == RESOURCE_TYPE_UNKNOWN &&
1077 response.status_code != 550) { 1104 response.status_code != 550) {
1078 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); 1105 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
1079 } 1106 }
1107
1108 ResetDataConnectionAfterError(state_after_size);
1080 break; 1109 break;
1081 default: 1110 default:
1082 NOTREACHED(); 1111 NOTREACHED();
1083 return Stop(ERR_UNEXPECTED); 1112 return Stop(ERR_UNEXPECTED);
1084 } 1113 }
1085 1114
1086 if (resource_type_ == RESOURCE_TYPE_FILE)
1087 next_state_ = STATE_CTRL_WRITE_RETR;
1088 else
1089 next_state_ = STATE_CTRL_WRITE_CWD;
1090
1091 return OK; 1115 return OK;
1092 } 1116 }
1093 1117
1094 // CWD command 1118 // CWD command
1095 int FtpNetworkTransaction::DoCtrlWriteCWD() { 1119 int FtpNetworkTransaction::DoCtrlWriteCWD() {
1096 std::string command = "CWD " + GetRequestPathForFtpCommand(true); 1120 std::string command = "CWD " + GetRequestPathForFtpCommand(true);
1097 next_state_ = STATE_CTRL_READ; 1121 next_state_ = STATE_CTRL_READ;
1098 return SendFtpCommand(command, command, COMMAND_CWD); 1122 return SendFtpCommand(command, command, COMMAND_CWD);
1099 } 1123 }
1100 1124
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1135 // We're assuming that the resource is a directory, but the server 1159 // We're assuming that the resource is a directory, but the server
1136 // says it's not true. The most probable interpretation is that it 1160 // says it's not true. The most probable interpretation is that it
1137 // doesn't exist (with FTP we can't be sure). 1161 // doesn't exist (with FTP we can't be sure).
1138 return Stop(ERR_FILE_NOT_FOUND); 1162 return Stop(ERR_FILE_NOT_FOUND);
1139 } 1163 }
1140 1164
1141 // We are here because SIZE failed and we are not sure what the resource 1165 // We are here because SIZE failed and we are not sure what the resource
1142 // type is. It could still be file, and SIZE could fail because of 1166 // type is. It could still be file, and SIZE could fail because of
1143 // an access error (http://crbug.com/56734). Try RETR just to be sure. 1167 // an access error (http://crbug.com/56734). Try RETR just to be sure.
1144 resource_type_ = RESOURCE_TYPE_FILE; 1168 resource_type_ = RESOURCE_TYPE_FILE;
1145 next_state_ = STATE_CTRL_WRITE_RETR;
1146 1169
1170 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR);
1147 return OK; 1171 return OK;
1148 } 1172 }
1149 1173
1150 // LIST command 1174 // LIST command
1151 int FtpNetworkTransaction::DoCtrlWriteLIST() { 1175 int FtpNetworkTransaction::DoCtrlWriteLIST() {
1152 std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST"); 1176 std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST");
1153 next_state_ = STATE_CTRL_READ; 1177 next_state_ = STATE_CTRL_READ;
1154 return SendFtpCommand(command, command, COMMAND_LIST); 1178 return SendFtpCommand(command, command, COMMAND_LIST);
1155 } 1179 }
1156 1180
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1226 return OK; 1250 return OK;
1227 } 1251 }
1228 1252
1229 // Only record the connection error after we've applied all our fallbacks. 1253 // Only record the connection error after we've applied all our fallbacks.
1230 // We want to capture the final error, one we're not going to recover from. 1254 // We want to capture the final error, one we're not going to recover from.
1231 RecordDataConnectionError(result); 1255 RecordDataConnectionError(result);
1232 1256
1233 if (result != OK) 1257 if (result != OK)
1234 return Stop(result); 1258 return Stop(result);
1235 1259
1236 next_state_ = STATE_CTRL_WRITE_SIZE; 1260 next_state_ = state_after_data_connection_;
1237 return OK; 1261 return OK;
1238 } 1262 }
1239 1263
1240 int FtpNetworkTransaction::DoDataRead() { 1264 int FtpNetworkTransaction::DoDataRead() {
1241 DCHECK(read_data_buf_); 1265 DCHECK(read_data_buf_);
1242 DCHECK_GT(read_data_buf_len_, 0); 1266 DCHECK_GT(read_data_buf_len_, 0);
1243 1267
1244 if (data_socket_ == NULL || !data_socket_->IsConnected()) { 1268 if (data_socket_ == NULL || !data_socket_->IsConnected()) {
1245 // If we don't destroy the data socket completely, some servers will wait 1269 // If we don't destroy the data socket completely, some servers will wait
1246 // for us (http://crbug.com/21127). The half-closed TCP connection needs 1270 // for us (http://crbug.com/21127). The half-closed TCP connection needs
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1348 if (!had_error_type[type]) { 1372 if (!had_error_type[type]) {
1349 had_error_type[type] = true; 1373 had_error_type[type] = true;
1350 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", 1374 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened",
1351 type, NUM_OF_NET_ERROR_TYPES); 1375 type, NUM_OF_NET_ERROR_TYPES);
1352 } 1376 }
1353 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 1377 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount",
1354 type, NUM_OF_NET_ERROR_TYPES); 1378 type, NUM_OF_NET_ERROR_TYPES);
1355 } 1379 }
1356 1380
1357 } // namespace net 1381 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698