OLD | NEW |
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 Loading... |
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_connect_complete_(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 Loading... |
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_connect_complete_ = 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 what an irrecoverable error condition is, |
| 362 // so we take no chances. |
| 363 state_after_data_connect_complete_ = 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 Loading... |
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 Loading... |
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 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option | 1176 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option |
1153 // forces LIST output instead of NLST (which would be ambiguous for us | 1177 // forces LIST output instead of NLST (which would be ambiguous for us |
1154 // to parse). | 1178 // to parse). |
1155 std::string command("LIST -l"); | 1179 std::string command("LIST -l"); |
1156 if (system_type_ == SYSTEM_TYPE_VMS) | 1180 if (system_type_ == SYSTEM_TYPE_VMS) |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1232 return OK; | 1256 return OK; |
1233 } | 1257 } |
1234 | 1258 |
1235 // Only record the connection error after we've applied all our fallbacks. | 1259 // Only record the connection error after we've applied all our fallbacks. |
1236 // We want to capture the final error, one we're not going to recover from. | 1260 // We want to capture the final error, one we're not going to recover from. |
1237 RecordDataConnectionError(result); | 1261 RecordDataConnectionError(result); |
1238 | 1262 |
1239 if (result != OK) | 1263 if (result != OK) |
1240 return Stop(result); | 1264 return Stop(result); |
1241 | 1265 |
1242 next_state_ = STATE_CTRL_WRITE_SIZE; | 1266 next_state_ = state_after_data_connect_complete_; |
1243 return OK; | 1267 return OK; |
1244 } | 1268 } |
1245 | 1269 |
1246 int FtpNetworkTransaction::DoDataRead() { | 1270 int FtpNetworkTransaction::DoDataRead() { |
1247 DCHECK(read_data_buf_); | 1271 DCHECK(read_data_buf_); |
1248 DCHECK_GT(read_data_buf_len_, 0); | 1272 DCHECK_GT(read_data_buf_len_, 0); |
1249 | 1273 |
1250 if (data_socket_ == NULL || !data_socket_->IsConnected()) { | 1274 if (data_socket_ == NULL || !data_socket_->IsConnected()) { |
1251 // If we don't destroy the data socket completely, some servers will wait | 1275 // If we don't destroy the data socket completely, some servers will wait |
1252 // for us (http://crbug.com/21127). The half-closed TCP connection needs | 1276 // for us (http://crbug.com/21127). The half-closed TCP connection needs |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1354 if (!had_error_type[type]) { | 1378 if (!had_error_type[type]) { |
1355 had_error_type[type] = true; | 1379 had_error_type[type] = true; |
1356 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", | 1380 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", |
1357 type, NUM_OF_NET_ERROR_TYPES); | 1381 type, NUM_OF_NET_ERROR_TYPES); |
1358 } | 1382 } |
1359 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", | 1383 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", |
1360 type, NUM_OF_NET_ERROR_TYPES); | 1384 type, NUM_OF_NET_ERROR_TYPES); |
1361 } | 1385 } |
1362 | 1386 |
1363 } // namespace net | 1387 } // namespace net |
OLD | NEW |