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 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 | 232 |
233 int FtpNetworkTransaction::Stop(int error) { | 233 int FtpNetworkTransaction::Stop(int error) { |
234 if (command_sent_ == COMMAND_QUIT) | 234 if (command_sent_ == COMMAND_QUIT) |
235 return error; | 235 return error; |
236 | 236 |
237 next_state_ = STATE_CTRL_WRITE_QUIT; | 237 next_state_ = STATE_CTRL_WRITE_QUIT; |
238 last_error_ = error; | 238 last_error_ = error; |
239 return OK; | 239 return OK; |
240 } | 240 } |
241 | 241 |
242 int FtpNetworkTransaction::RestartIgnoringLastError( | |
243 const CompletionCallback& callback) { | |
244 return ERR_NOT_IMPLEMENTED; | |
245 } | |
246 | |
247 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, | 242 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, |
248 const CompletionCallback& callback, | 243 const CompletionCallback& callback, |
249 const BoundNetLog& net_log) { | 244 const BoundNetLog& net_log) { |
250 net_log_ = net_log; | 245 net_log_ = net_log; |
251 request_ = request_info; | 246 request_ = request_info; |
252 | 247 |
253 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); | 248 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); |
254 | 249 |
255 if (request_->url.has_username()) { | 250 if (request_->url.has_username()) { |
256 base::string16 username; | 251 base::string16 username; |
(...skipping 769 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 | 1021 |
1027 // RETR command | 1022 // RETR command |
1028 int FtpNetworkTransaction::DoCtrlWriteRETR() { | 1023 int FtpNetworkTransaction::DoCtrlWriteRETR() { |
1029 std::string command = "RETR " + GetRequestPathForFtpCommand(false); | 1024 std::string command = "RETR " + GetRequestPathForFtpCommand(false); |
1030 next_state_ = STATE_CTRL_READ; | 1025 next_state_ = STATE_CTRL_READ; |
1031 return SendFtpCommand(command, command, COMMAND_RETR); | 1026 return SendFtpCommand(command, command, COMMAND_RETR); |
1032 } | 1027 } |
1033 | 1028 |
1034 int FtpNetworkTransaction::ProcessResponseRETR( | 1029 int FtpNetworkTransaction::ProcessResponseRETR( |
1035 const FtpCtrlResponse& response) { | 1030 const FtpCtrlResponse& response) { |
| 1031 // Resource type should be either filled in by DetectTypecode() or |
| 1032 // detected with CWD. RETR is sent only when the resource is a file. |
| 1033 DCHECK_EQ(RESOURCE_TYPE_FILE, resource_type_); |
| 1034 |
1036 switch (GetErrorClass(response.status_code)) { | 1035 switch (GetErrorClass(response.status_code)) { |
1037 case ERROR_CLASS_INITIATED: | 1036 case ERROR_CLASS_INITIATED: |
1038 // We want the client to start reading the response at this point. | 1037 // We want the client to start reading the response at this point. |
1039 // It got here either through Start or RestartWithAuth. We want that | 1038 // It got here either through Start or RestartWithAuth. We want that |
1040 // method to complete. Not setting next state here will make DoLoop exit | 1039 // method to complete. Not setting next state here will make DoLoop exit |
1041 // and in turn make Start/RestartWithAuth complete. | 1040 // and in turn make Start/RestartWithAuth complete. |
1042 resource_type_ = RESOURCE_TYPE_FILE; | |
1043 break; | 1041 break; |
1044 case ERROR_CLASS_OK: | 1042 case ERROR_CLASS_OK: |
1045 resource_type_ = RESOURCE_TYPE_FILE; | |
1046 next_state_ = STATE_CTRL_WRITE_QUIT; | 1043 next_state_ = STATE_CTRL_WRITE_QUIT; |
1047 break; | 1044 break; |
1048 case ERROR_CLASS_INFO_NEEDED: | 1045 case ERROR_CLASS_INFO_NEEDED: |
1049 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1046 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1050 case ERROR_CLASS_TRANSIENT_ERROR: | 1047 case ERROR_CLASS_TRANSIENT_ERROR: |
1051 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1048 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1052 case ERROR_CLASS_PERMANENT_ERROR: | 1049 case ERROR_CLASS_PERMANENT_ERROR: |
1053 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1050 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1054 default: | 1051 default: |
1055 NOTREACHED(); | 1052 NOTREACHED(); |
1056 return Stop(ERR_UNEXPECTED); | 1053 return Stop(ERR_UNEXPECTED); |
1057 } | 1054 } |
1058 | 1055 |
1059 // We should be sure about our resource type now. Otherwise we risk | |
1060 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). | |
1061 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); | |
1062 | |
1063 return OK; | 1056 return OK; |
1064 } | 1057 } |
1065 | 1058 |
1066 // SIZE command | 1059 // SIZE command |
1067 int FtpNetworkTransaction::DoCtrlWriteSIZE() { | 1060 int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
1068 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); | 1061 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); |
1069 next_state_ = STATE_CTRL_READ; | 1062 next_state_ = STATE_CTRL_READ; |
1070 return SendFtpCommand(command, command, COMMAND_SIZE); | 1063 return SendFtpCommand(command, command, COMMAND_SIZE); |
1071 } | 1064 } |
1072 | 1065 |
(...skipping 15 matching lines...) Expand all Loading... |
1088 // Some FTP servers (for example, the qnx one) send a SIZE even for | 1081 // Some FTP servers (for example, the qnx one) send a SIZE even for |
1089 // directories. | 1082 // directories. |
1090 response_.expected_content_size = size; | 1083 response_.expected_content_size = size; |
1091 break; | 1084 break; |
1092 case ERROR_CLASS_INFO_NEEDED: | 1085 case ERROR_CLASS_INFO_NEEDED: |
1093 break; | 1086 break; |
1094 case ERROR_CLASS_TRANSIENT_ERROR: | 1087 case ERROR_CLASS_TRANSIENT_ERROR: |
1095 break; | 1088 break; |
1096 case ERROR_CLASS_PERMANENT_ERROR: | 1089 case ERROR_CLASS_PERMANENT_ERROR: |
1097 // It's possible that SIZE failed because the path is a directory. | 1090 // It's possible that SIZE failed because the path is a directory. |
| 1091 // TODO(xunjieli): Add a test for this case. |
1098 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && | 1092 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && |
1099 response.status_code != 550) { | 1093 response.status_code != 550) { |
1100 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1094 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1101 } | 1095 } |
1102 break; | 1096 break; |
1103 default: | 1097 default: |
1104 NOTREACHED(); | 1098 NOTREACHED(); |
1105 return Stop(ERR_UNEXPECTED); | 1099 return Stop(ERR_UNEXPECTED); |
1106 } | 1100 } |
| 1101 |
| 1102 // If the resource is known beforehand to be a file, RETR should be issued, |
| 1103 // otherwise do CWD which will detect the resource type. |
1107 if (resource_type_ == RESOURCE_TYPE_FILE) | 1104 if (resource_type_ == RESOURCE_TYPE_FILE) |
1108 EstablishDataConnection(STATE_CTRL_WRITE_RETR); | 1105 EstablishDataConnection(STATE_CTRL_WRITE_RETR); |
1109 else | 1106 else |
1110 next_state_ = STATE_CTRL_WRITE_CWD; | 1107 next_state_ = STATE_CTRL_WRITE_CWD; |
1111 return OK; | 1108 return OK; |
1112 } | 1109 } |
1113 | 1110 |
1114 // CWD command | 1111 // CWD command |
1115 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 1112 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
1116 std::string command = "CWD " + GetRequestPathForFtpCommand(true); | 1113 std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
1117 next_state_ = STATE_CTRL_READ; | 1114 next_state_ = STATE_CTRL_READ; |
1118 return SendFtpCommand(command, command, COMMAND_CWD); | 1115 return SendFtpCommand(command, command, COMMAND_CWD); |
1119 } | 1116 } |
1120 | 1117 |
1121 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { | 1118 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
1122 // We should never issue CWD if we know the target resource is a file. | 1119 // CWD should be invoked only when the resource is not a file. |
1123 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); | 1120 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); |
1124 | 1121 |
1125 switch (GetErrorClass(response.status_code)) { | 1122 switch (GetErrorClass(response.status_code)) { |
1126 case ERROR_CLASS_INITIATED: | 1123 case ERROR_CLASS_INITIATED: |
1127 return Stop(ERR_INVALID_RESPONSE); | 1124 return Stop(ERR_INVALID_RESPONSE); |
1128 case ERROR_CLASS_OK: | 1125 case ERROR_CLASS_OK: |
| 1126 resource_type_ = RESOURCE_TYPE_DIRECTORY; |
1129 EstablishDataConnection(STATE_CTRL_WRITE_LIST); | 1127 EstablishDataConnection(STATE_CTRL_WRITE_LIST); |
1130 break; | 1128 break; |
1131 case ERROR_CLASS_INFO_NEEDED: | 1129 case ERROR_CLASS_INFO_NEEDED: |
1132 return Stop(ERR_INVALID_RESPONSE); | 1130 return Stop(ERR_INVALID_RESPONSE); |
1133 case ERROR_CLASS_TRANSIENT_ERROR: | 1131 case ERROR_CLASS_TRANSIENT_ERROR: |
1134 // Some FTP servers send response 451 (not a valid CWD response according | 1132 // Some FTP servers send response 451 (not a valid CWD response according |
1135 // to RFC 959) instead of 550. | 1133 // to RFC 959) instead of 550. |
1136 if (response.status_code == 451) | 1134 if (response.status_code == 451) |
1137 return ProcessResponseCWDNotADirectory(); | 1135 return ProcessResponseCWDNotADirectory(); |
1138 | 1136 |
(...skipping 12 matching lines...) Expand all Loading... |
1151 } | 1149 } |
1152 | 1150 |
1153 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { | 1151 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { |
1154 if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { | 1152 if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { |
1155 // We're assuming that the resource is a directory, but the server | 1153 // We're assuming that the resource is a directory, but the server |
1156 // says it's not true. The most probable interpretation is that it | 1154 // says it's not true. The most probable interpretation is that it |
1157 // doesn't exist (with FTP we can't be sure). | 1155 // doesn't exist (with FTP we can't be sure). |
1158 return Stop(ERR_FILE_NOT_FOUND); | 1156 return Stop(ERR_FILE_NOT_FOUND); |
1159 } | 1157 } |
1160 | 1158 |
1161 // We are here because SIZE failed and we are not sure what the resource | 1159 // If it is not a directory, it is probably a file. |
1162 // type is. It could still be file, and SIZE could fail because of | |
1163 // an access error (http://crbug.com/56734). Try RETR just to be sure. | |
1164 resource_type_ = RESOURCE_TYPE_FILE; | 1160 resource_type_ = RESOURCE_TYPE_FILE; |
1165 | 1161 |
1166 EstablishDataConnection(STATE_CTRL_WRITE_RETR); | 1162 EstablishDataConnection(STATE_CTRL_WRITE_RETR); |
1167 return OK; | 1163 return OK; |
1168 } | 1164 } |
1169 | 1165 |
1170 // LIST command | 1166 // LIST command |
1171 int FtpNetworkTransaction::DoCtrlWriteLIST() { | 1167 int FtpNetworkTransaction::DoCtrlWriteLIST() { |
1172 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option | 1168 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option |
1173 // forces LIST output instead of NLST (which would be ambiguous for us | 1169 // forces LIST output instead of NLST (which would be ambiguous for us |
1174 // to parse). | 1170 // to parse). |
1175 std::string command("LIST -l"); | 1171 std::string command("LIST -l"); |
1176 if (system_type_ == SYSTEM_TYPE_VMS) | 1172 if (system_type_ == SYSTEM_TYPE_VMS) |
1177 command = "LIST *.*;0"; | 1173 command = "LIST *.*;0"; |
1178 | 1174 |
1179 next_state_ = STATE_CTRL_READ; | 1175 next_state_ = STATE_CTRL_READ; |
1180 return SendFtpCommand(command, command, COMMAND_LIST); | 1176 return SendFtpCommand(command, command, COMMAND_LIST); |
1181 } | 1177 } |
1182 | 1178 |
1183 int FtpNetworkTransaction::ProcessResponseLIST( | 1179 int FtpNetworkTransaction::ProcessResponseLIST( |
1184 const FtpCtrlResponse& response) { | 1180 const FtpCtrlResponse& response) { |
| 1181 // Resource type should be either filled in by DetectTypecode() or |
| 1182 // detected with CWD. LIST is sent only when the resource is a directory. |
| 1183 DCHECK_EQ(RESOURCE_TYPE_DIRECTORY, resource_type_); |
| 1184 |
1185 switch (GetErrorClass(response.status_code)) { | 1185 switch (GetErrorClass(response.status_code)) { |
1186 case ERROR_CLASS_INITIATED: | 1186 case ERROR_CLASS_INITIATED: |
1187 // We want the client to start reading the response at this point. | 1187 // We want the client to start reading the response at this point. |
1188 // It got here either through Start or RestartWithAuth. We want that | 1188 // It got here either through Start or RestartWithAuth. We want that |
1189 // method to complete. Not setting next state here will make DoLoop exit | 1189 // method to complete. Not setting next state here will make DoLoop exit |
1190 // and in turn make Start/RestartWithAuth complete. | 1190 // and in turn make Start/RestartWithAuth complete. |
1191 response_.is_directory_listing = true; | 1191 response_.is_directory_listing = true; |
1192 break; | 1192 break; |
1193 case ERROR_CLASS_OK: | 1193 case ERROR_CLASS_OK: |
1194 response_.is_directory_listing = true; | 1194 response_.is_directory_listing = true; |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1375 if (!had_error_type[type]) { | 1375 if (!had_error_type[type]) { |
1376 had_error_type[type] = true; | 1376 had_error_type[type] = true; |
1377 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", | 1377 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", |
1378 type, NUM_OF_NET_ERROR_TYPES); | 1378 type, NUM_OF_NET_ERROR_TYPES); |
1379 } | 1379 } |
1380 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", | 1380 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", |
1381 type, NUM_OF_NET_ERROR_TYPES); | 1381 type, NUM_OF_NET_ERROR_TYPES); |
1382 } | 1382 } |
1383 | 1383 |
1384 } // namespace net | 1384 } // namespace net |
OLD | NEW |