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 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_NONE) { |
| 228 } |
228 | 229 |
229 FtpNetworkTransaction::~FtpNetworkTransaction() { | 230 FtpNetworkTransaction::~FtpNetworkTransaction() { |
230 } | 231 } |
231 | 232 |
232 int FtpNetworkTransaction::Stop(int error) { | 233 int FtpNetworkTransaction::Stop(int error) { |
233 if (command_sent_ == COMMAND_QUIT) | 234 if (command_sent_ == COMMAND_QUIT) |
234 return error; | 235 return error; |
235 | 236 |
236 next_state_ = STATE_CTRL_WRITE_QUIT; | 237 next_state_ = STATE_CTRL_WRITE_QUIT; |
237 last_error_ = error; | 238 last_error_ = error; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); | 339 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); |
339 read_data_buf_ = NULL; | 340 read_data_buf_ = NULL; |
340 read_data_buf_len_ = 0; | 341 read_data_buf_len_ = 0; |
341 if (write_buf_.get()) | 342 if (write_buf_.get()) |
342 write_buf_->SetOffset(0); | 343 write_buf_->SetOffset(0); |
343 last_error_ = OK; | 344 last_error_ = OK; |
344 data_connection_port_ = 0; | 345 data_connection_port_ = 0; |
345 ctrl_socket_.reset(); | 346 ctrl_socket_.reset(); |
346 data_socket_.reset(); | 347 data_socket_.reset(); |
347 next_state_ = STATE_NONE; | 348 next_state_ = STATE_NONE; |
348 state_after_data_connect_complete_ = STATE_CTRL_WRITE_SIZE; | 349 state_after_data_connect_complete_ = STATE_NONE; |
349 } | 350 } |
350 | 351 |
351 void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) { | 352 void FtpNetworkTransaction::EstablishDataConnection(State state_after_connect) { |
352 // The server _might_ have reset the data connection | 353 DCHECK(state_after_connect == STATE_CTRL_WRITE_RETR || |
353 // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS: | 354 state_after_connect == STATE_CTRL_WRITE_LIST); |
354 // "The server MUST close the data connection under the following | 355 state_after_data_connect_complete_ = state_after_connect; |
355 // conditions: | |
356 // ... | |
357 // 5. An irrecoverable error condition occurs.") | |
358 // | |
359 // It is ambiguous what an irrecoverable error condition is, | |
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; | 356 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; |
363 } | 357 } |
364 | 358 |
365 void FtpNetworkTransaction::DoCallback(int rv) { | 359 void FtpNetworkTransaction::DoCallback(int rv) { |
366 DCHECK(rv != ERR_IO_PENDING); | 360 DCHECK(rv != ERR_IO_PENDING); |
367 DCHECK(!user_callback_.is_null()); | 361 DCHECK(!user_callback_.is_null()); |
368 | 362 |
369 // Since Run may result in Read being called, clear callback_ up front. | 363 // Since Run may result in Read being called, clear callback_ up front. |
370 CompletionCallback c = user_callback_; | 364 CompletionCallback c = user_callback_; |
371 user_callback_.Reset(); | 365 user_callback_.Reset(); |
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
937 next_state_ = STATE_CTRL_READ; | 931 next_state_ = STATE_CTRL_READ; |
938 return SendFtpCommand(command, command, COMMAND_TYPE); | 932 return SendFtpCommand(command, command, COMMAND_TYPE); |
939 } | 933 } |
940 | 934 |
941 int FtpNetworkTransaction::ProcessResponseTYPE( | 935 int FtpNetworkTransaction::ProcessResponseTYPE( |
942 const FtpCtrlResponse& response) { | 936 const FtpCtrlResponse& response) { |
943 switch (GetErrorClass(response.status_code)) { | 937 switch (GetErrorClass(response.status_code)) { |
944 case ERROR_CLASS_INITIATED: | 938 case ERROR_CLASS_INITIATED: |
945 return Stop(ERR_INVALID_RESPONSE); | 939 return Stop(ERR_INVALID_RESPONSE); |
946 case ERROR_CLASS_OK: | 940 case ERROR_CLASS_OK: |
947 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; | 941 next_state_ = STATE_CTRL_WRITE_SIZE; |
948 break; | 942 break; |
949 case ERROR_CLASS_INFO_NEEDED: | 943 case ERROR_CLASS_INFO_NEEDED: |
950 return Stop(ERR_INVALID_RESPONSE); | 944 return Stop(ERR_INVALID_RESPONSE); |
951 case ERROR_CLASS_TRANSIENT_ERROR: | 945 case ERROR_CLASS_TRANSIENT_ERROR: |
952 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 946 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
953 case ERROR_CLASS_PERMANENT_ERROR: | 947 case ERROR_CLASS_PERMANENT_ERROR: |
954 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 948 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
955 default: | 949 default: |
956 NOTREACHED(); | 950 NOTREACHED(); |
957 return Stop(ERR_UNEXPECTED); | 951 return Stop(ERR_UNEXPECTED); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1049 break; | 1043 break; |
1050 case ERROR_CLASS_OK: | 1044 case ERROR_CLASS_OK: |
1051 resource_type_ = RESOURCE_TYPE_FILE; | 1045 resource_type_ = RESOURCE_TYPE_FILE; |
1052 next_state_ = STATE_CTRL_WRITE_QUIT; | 1046 next_state_ = STATE_CTRL_WRITE_QUIT; |
1053 break; | 1047 break; |
1054 case ERROR_CLASS_INFO_NEEDED: | 1048 case ERROR_CLASS_INFO_NEEDED: |
1055 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1049 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1056 case ERROR_CLASS_TRANSIENT_ERROR: | 1050 case ERROR_CLASS_TRANSIENT_ERROR: |
1057 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1051 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1058 case ERROR_CLASS_PERMANENT_ERROR: | 1052 case ERROR_CLASS_PERMANENT_ERROR: |
1059 // Code 550 means "Failed to open file". Other codes are unrelated, | 1053 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1060 // like "Not logged in" etc. | |
1061 if (response.status_code != 550 || resource_type_ == RESOURCE_TYPE_FILE) | |
1062 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | |
1063 | |
1064 // It's possible that RETR failed because the path is a directory. | |
1065 resource_type_ = RESOURCE_TYPE_DIRECTORY; | |
1066 | |
1067 // We're going to try CWD next, but first send a PASV one more time, | |
1068 // because some FTP servers, including FileZilla, require that. | |
1069 // See http://crbug.com/25316. | |
1070 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; | |
1071 break; | |
1072 default: | 1054 default: |
1073 NOTREACHED(); | 1055 NOTREACHED(); |
1074 return Stop(ERR_UNEXPECTED); | 1056 return Stop(ERR_UNEXPECTED); |
1075 } | 1057 } |
1076 | 1058 |
1077 // We should be sure about our resource type now. Otherwise we risk | 1059 // 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). | 1060 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). |
1079 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); | 1061 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); |
1080 | 1062 |
1081 return OK; | 1063 return OK; |
1082 } | 1064 } |
1083 | 1065 |
1084 // SIZE command | 1066 // SIZE command |
1085 int FtpNetworkTransaction::DoCtrlWriteSIZE() { | 1067 int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
1086 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); | 1068 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); |
1087 next_state_ = STATE_CTRL_READ; | 1069 next_state_ = STATE_CTRL_READ; |
1088 return SendFtpCommand(command, command, COMMAND_SIZE); | 1070 return SendFtpCommand(command, command, COMMAND_SIZE); |
1089 } | 1071 } |
1090 | 1072 |
1091 int FtpNetworkTransaction::ProcessResponseSIZE( | 1073 int FtpNetworkTransaction::ProcessResponseSIZE( |
1092 const FtpCtrlResponse& response) { | 1074 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)) { | 1075 switch (GetErrorClass(response.status_code)) { |
1100 case ERROR_CLASS_INITIATED: | 1076 case ERROR_CLASS_INITIATED: |
1101 next_state_ = state_after_size; | |
1102 break; | 1077 break; |
1103 case ERROR_CLASS_OK: | 1078 case ERROR_CLASS_OK: |
1104 if (response.lines.size() != 1) | 1079 if (response.lines.size() != 1) |
1105 return Stop(ERR_INVALID_RESPONSE); | 1080 return Stop(ERR_INVALID_RESPONSE); |
1106 int64 size; | 1081 int64 size; |
1107 if (!base::StringToInt64(response.lines[0], &size)) | 1082 if (!base::StringToInt64(response.lines[0], &size)) |
1108 return Stop(ERR_INVALID_RESPONSE); | 1083 return Stop(ERR_INVALID_RESPONSE); |
1109 if (size < 0) | 1084 if (size < 0) |
1110 return Stop(ERR_INVALID_RESPONSE); | 1085 return Stop(ERR_INVALID_RESPONSE); |
1111 | 1086 |
1112 // A successful response to SIZE does not mean the resource is a file. | 1087 // 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 | 1088 // Some FTP servers (for example, the qnx one) send a SIZE even for |
1114 // directories. | 1089 // directories. |
1115 response_.expected_content_size = size; | 1090 response_.expected_content_size = size; |
1116 | |
1117 next_state_ = state_after_size; | |
1118 break; | 1091 break; |
1119 case ERROR_CLASS_INFO_NEEDED: | 1092 case ERROR_CLASS_INFO_NEEDED: |
1120 next_state_ = state_after_size; | |
1121 break; | 1093 break; |
1122 case ERROR_CLASS_TRANSIENT_ERROR: | 1094 case ERROR_CLASS_TRANSIENT_ERROR: |
1123 ResetDataConnectionAfterError(state_after_size); | |
1124 break; | 1095 break; |
1125 case ERROR_CLASS_PERMANENT_ERROR: | 1096 case ERROR_CLASS_PERMANENT_ERROR: |
1126 // It's possible that SIZE failed because the path is a directory. | 1097 // It's possible that SIZE failed because the path is a directory. |
1127 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && | 1098 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && |
1128 response.status_code != 550) { | 1099 response.status_code != 550) { |
1129 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1100 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1130 } | 1101 } |
1131 | |
1132 ResetDataConnectionAfterError(state_after_size); | |
1133 break; | 1102 break; |
1134 default: | 1103 default: |
1135 NOTREACHED(); | 1104 NOTREACHED(); |
1136 return Stop(ERR_UNEXPECTED); | 1105 return Stop(ERR_UNEXPECTED); |
1137 } | 1106 } |
1138 | 1107 if (resource_type_ == RESOURCE_TYPE_FILE) |
| 1108 EstablishDataConnection(STATE_CTRL_WRITE_RETR); |
| 1109 else |
| 1110 next_state_ = STATE_CTRL_WRITE_CWD; |
1139 return OK; | 1111 return OK; |
1140 } | 1112 } |
1141 | 1113 |
1142 // CWD command | 1114 // CWD command |
1143 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 1115 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
1144 std::string command = "CWD " + GetRequestPathForFtpCommand(true); | 1116 std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
1145 next_state_ = STATE_CTRL_READ; | 1117 next_state_ = STATE_CTRL_READ; |
1146 return SendFtpCommand(command, command, COMMAND_CWD); | 1118 return SendFtpCommand(command, command, COMMAND_CWD); |
1147 } | 1119 } |
1148 | 1120 |
1149 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { | 1121 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
1150 // We should never issue CWD if we know the target resource is a file. | 1122 // We should never issue CWD if we know the target resource is a file. |
1151 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); | 1123 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); |
1152 | 1124 |
1153 switch (GetErrorClass(response.status_code)) { | 1125 switch (GetErrorClass(response.status_code)) { |
1154 case ERROR_CLASS_INITIATED: | 1126 case ERROR_CLASS_INITIATED: |
1155 return Stop(ERR_INVALID_RESPONSE); | 1127 return Stop(ERR_INVALID_RESPONSE); |
1156 case ERROR_CLASS_OK: | 1128 case ERROR_CLASS_OK: |
1157 next_state_ = STATE_CTRL_WRITE_LIST; | 1129 EstablishDataConnection(STATE_CTRL_WRITE_LIST); |
1158 break; | 1130 break; |
1159 case ERROR_CLASS_INFO_NEEDED: | 1131 case ERROR_CLASS_INFO_NEEDED: |
1160 return Stop(ERR_INVALID_RESPONSE); | 1132 return Stop(ERR_INVALID_RESPONSE); |
1161 case ERROR_CLASS_TRANSIENT_ERROR: | 1133 case ERROR_CLASS_TRANSIENT_ERROR: |
1162 // Some FTP servers send response 451 (not a valid CWD response according | 1134 // Some FTP servers send response 451 (not a valid CWD response according |
1163 // to RFC 959) instead of 550. | 1135 // to RFC 959) instead of 550. |
1164 if (response.status_code == 451) | 1136 if (response.status_code == 451) |
1165 return ProcessResponseCWDNotADirectory(); | 1137 return ProcessResponseCWDNotADirectory(); |
1166 | 1138 |
1167 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1139 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
(...skipping 16 matching lines...) Expand all Loading... |
1184 // says it's not true. The most probable interpretation is that it | 1156 // says it's not true. The most probable interpretation is that it |
1185 // doesn't exist (with FTP we can't be sure). | 1157 // doesn't exist (with FTP we can't be sure). |
1186 return Stop(ERR_FILE_NOT_FOUND); | 1158 return Stop(ERR_FILE_NOT_FOUND); |
1187 } | 1159 } |
1188 | 1160 |
1189 // We are here because SIZE failed and we are not sure what the resource | 1161 // 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 | 1162 // 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. | 1163 // an access error (http://crbug.com/56734). Try RETR just to be sure. |
1192 resource_type_ = RESOURCE_TYPE_FILE; | 1164 resource_type_ = RESOURCE_TYPE_FILE; |
1193 | 1165 |
1194 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); | 1166 EstablishDataConnection(STATE_CTRL_WRITE_RETR); |
1195 return OK; | 1167 return OK; |
1196 } | 1168 } |
1197 | 1169 |
1198 // LIST command | 1170 // LIST command |
1199 int FtpNetworkTransaction::DoCtrlWriteLIST() { | 1171 int FtpNetworkTransaction::DoCtrlWriteLIST() { |
1200 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option | 1172 // 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 | 1173 // forces LIST output instead of NLST (which would be ambiguous for us |
1202 // to parse). | 1174 // to parse). |
1203 std::string command("LIST -l"); | 1175 std::string command("LIST -l"); |
1204 if (system_type_ == SYSTEM_TYPE_VMS) | 1176 if (system_type_ == SYSTEM_TYPE_VMS) |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1403 if (!had_error_type[type]) { | 1375 if (!had_error_type[type]) { |
1404 had_error_type[type] = true; | 1376 had_error_type[type] = true; |
1405 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", | 1377 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", |
1406 type, NUM_OF_NET_ERROR_TYPES); | 1378 type, NUM_OF_NET_ERROR_TYPES); |
1407 } | 1379 } |
1408 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", | 1380 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", |
1409 type, NUM_OF_NET_ERROR_TYPES); | 1381 type, NUM_OF_NET_ERROR_TYPES); |
1410 } | 1382 } |
1411 | 1383 |
1412 } // namespace net | 1384 } // namespace net |
OLD | NEW |