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( | |
xunjieli
2015/01/30 21:50:44
This is never used anywhere. Is it okay to remove
davidben
2015/02/04 18:51:18
Sounds good. :-)
| |
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 18 matching lines...) Expand all Loading... | |
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. |
1098 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && | 1091 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && |
1099 response.status_code != 550) { | 1092 response.status_code != 550) { |
1100 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1093 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1101 } | 1094 } |
davidben
2015/02/04 18:51:18
Do you know what this code does? I'm confused what
xunjieli
2015/02/04 20:29:29
The Stop case is not tested in the code. I think i
| |
1102 break; | 1095 break; |
1103 default: | 1096 default: |
1104 NOTREACHED(); | 1097 NOTREACHED(); |
1105 return Stop(ERR_UNEXPECTED); | 1098 return Stop(ERR_UNEXPECTED); |
1106 } | 1099 } |
1107 if (resource_type_ == RESOURCE_TYPE_FILE) | 1100 if (resource_type_ == RESOURCE_TYPE_FILE) |
1108 EstablishDataConnection(STATE_CTRL_WRITE_RETR); | 1101 EstablishDataConnection(STATE_CTRL_WRITE_RETR); |
1109 else | 1102 else |
1110 next_state_ = STATE_CTRL_WRITE_CWD; | 1103 next_state_ = STATE_CTRL_WRITE_CWD; |
1111 return OK; | 1104 return OK; |
1112 } | 1105 } |
1113 | 1106 |
1114 // CWD command | 1107 // CWD command |
1115 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 1108 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
1116 std::string command = "CWD " + GetRequestPathForFtpCommand(true); | 1109 std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
1117 next_state_ = STATE_CTRL_READ; | 1110 next_state_ = STATE_CTRL_READ; |
1118 return SendFtpCommand(command, command, COMMAND_CWD); | 1111 return SendFtpCommand(command, command, COMMAND_CWD); |
1119 } | 1112 } |
1120 | 1113 |
1121 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { | 1114 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
1122 // We should never issue CWD if we know the target resource is a file. | 1115 // CWD should be invoked only when the resource is not a file. |
1123 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); | 1116 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); |
1124 | 1117 |
1125 switch (GetErrorClass(response.status_code)) { | 1118 switch (GetErrorClass(response.status_code)) { |
1126 case ERROR_CLASS_INITIATED: | 1119 case ERROR_CLASS_INITIATED: |
1127 return Stop(ERR_INVALID_RESPONSE); | 1120 return Stop(ERR_INVALID_RESPONSE); |
1128 case ERROR_CLASS_OK: | 1121 case ERROR_CLASS_OK: |
1122 resource_type_ = RESOURCE_TYPE_DIRECTORY; | |
1129 EstablishDataConnection(STATE_CTRL_WRITE_LIST); | 1123 EstablishDataConnection(STATE_CTRL_WRITE_LIST); |
1130 break; | 1124 break; |
1131 case ERROR_CLASS_INFO_NEEDED: | 1125 case ERROR_CLASS_INFO_NEEDED: |
1132 return Stop(ERR_INVALID_RESPONSE); | 1126 return Stop(ERR_INVALID_RESPONSE); |
1133 case ERROR_CLASS_TRANSIENT_ERROR: | 1127 case ERROR_CLASS_TRANSIENT_ERROR: |
1134 // Some FTP servers send response 451 (not a valid CWD response according | 1128 // Some FTP servers send response 451 (not a valid CWD response according |
1135 // to RFC 959) instead of 550. | 1129 // to RFC 959) instead of 550. |
1136 if (response.status_code == 451) | 1130 if (response.status_code == 451) |
1137 return ProcessResponseCWDNotADirectory(); | 1131 return ProcessResponseCWDNotADirectory(); |
1138 | 1132 |
1139 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1133 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1140 case ERROR_CLASS_PERMANENT_ERROR: | 1134 case ERROR_CLASS_PERMANENT_ERROR: |
1141 if (response.status_code == 550) | 1135 if (response.status_code == 550) |
1142 return ProcessResponseCWDNotADirectory(); | 1136 return ProcessResponseCWDNotADirectory(); |
1143 | 1137 |
1144 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1138 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
1145 default: | 1139 default: |
1146 NOTREACHED(); | 1140 NOTREACHED(); |
1147 return Stop(ERR_UNEXPECTED); | 1141 return Stop(ERR_UNEXPECTED); |
1148 } | 1142 } |
1149 | 1143 |
1150 return OK; | 1144 return OK; |
1151 } | 1145 } |
1152 | 1146 |
1153 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { | 1147 int FtpNetworkTransaction::ProcessResponseCWDNotADirectory() { |
1154 if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { | 1148 if (resource_type_ == RESOURCE_TYPE_DIRECTORY) { |
davidben
2015/02/05 19:42:57
Oof, I'm sorry! I was wrong that RESOURCE_TYPE_UNK
xunjieli
2015/02/05 20:21:57
Done. Hmm yep, saving a RETR is probably better th
| |
1155 // We're assuming that the resource is a directory, but the server | 1149 // 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 | 1150 // says it's not true. The most probable interpretation is that it |
1157 // doesn't exist (with FTP we can't be sure). | 1151 // doesn't exist (with FTP we can't be sure). |
1158 return Stop(ERR_FILE_NOT_FOUND); | 1152 return Stop(ERR_FILE_NOT_FOUND); |
1159 } | 1153 } |
1160 | 1154 |
1161 // We are here because SIZE failed and we are not sure what the resource | 1155 // 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; | 1156 resource_type_ = RESOURCE_TYPE_FILE; |
1165 | 1157 |
1166 EstablishDataConnection(STATE_CTRL_WRITE_RETR); | 1158 EstablishDataConnection(STATE_CTRL_WRITE_RETR); |
1167 return OK; | 1159 return OK; |
1168 } | 1160 } |
1169 | 1161 |
1170 // LIST command | 1162 // LIST command |
1171 int FtpNetworkTransaction::DoCtrlWriteLIST() { | 1163 int FtpNetworkTransaction::DoCtrlWriteLIST() { |
1172 // Use the -l option for mod_ftp configured in LISTIsNLST mode: the option | 1164 // 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 | 1165 // forces LIST output instead of NLST (which would be ambiguous for us |
1174 // to parse). | 1166 // to parse). |
1175 std::string command("LIST -l"); | 1167 std::string command("LIST -l"); |
xunjieli
2015/01/30 21:50:44
I wonder if we should remove "-l". This is not a p
davidben
2015/02/04 18:51:18
Hrm. Apparently it was added in https://chromiumco
xunjieli
2015/02/04 20:29:29
Sounds good to me. no easy way around this I gues
| |
1176 if (system_type_ == SYSTEM_TYPE_VMS) | 1168 if (system_type_ == SYSTEM_TYPE_VMS) |
1177 command = "LIST *.*;0"; | 1169 command = "LIST *.*;0"; |
1178 | 1170 |
1179 next_state_ = STATE_CTRL_READ; | 1171 next_state_ = STATE_CTRL_READ; |
1180 return SendFtpCommand(command, command, COMMAND_LIST); | 1172 return SendFtpCommand(command, command, COMMAND_LIST); |
1181 } | 1173 } |
1182 | 1174 |
1183 int FtpNetworkTransaction::ProcessResponseLIST( | 1175 int FtpNetworkTransaction::ProcessResponseLIST( |
1184 const FtpCtrlResponse& response) { | 1176 const FtpCtrlResponse& response) { |
1177 // Resource type should be either filled in by DetectTypecode() or | |
1178 // detected with CWD. LIST is sent only when the resource is a directory. | |
1179 DCHECK_EQ(RESOURCE_TYPE_DIRECTORY, resource_type_); | |
1180 | |
1185 switch (GetErrorClass(response.status_code)) { | 1181 switch (GetErrorClass(response.status_code)) { |
1186 case ERROR_CLASS_INITIATED: | 1182 case ERROR_CLASS_INITIATED: |
1187 // We want the client to start reading the response at this point. | 1183 // We want the client to start reading the response at this point. |
1188 // It got here either through Start or RestartWithAuth. We want that | 1184 // It got here either through Start or RestartWithAuth. We want that |
1189 // method to complete. Not setting next state here will make DoLoop exit | 1185 // method to complete. Not setting next state here will make DoLoop exit |
1190 // and in turn make Start/RestartWithAuth complete. | 1186 // and in turn make Start/RestartWithAuth complete. |
1191 response_.is_directory_listing = true; | 1187 response_.is_directory_listing = true; |
1192 break; | 1188 break; |
1193 case ERROR_CLASS_OK: | 1189 case ERROR_CLASS_OK: |
1194 response_.is_directory_listing = true; | 1190 response_.is_directory_listing = true; |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1375 if (!had_error_type[type]) { | 1371 if (!had_error_type[type]) { |
1376 had_error_type[type] = true; | 1372 had_error_type[type] = true; |
1377 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", | 1373 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", |
1378 type, NUM_OF_NET_ERROR_TYPES); | 1374 type, NUM_OF_NET_ERROR_TYPES); |
1379 } | 1375 } |
1380 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", | 1376 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", |
1381 type, NUM_OF_NET_ERROR_TYPES); | 1377 type, NUM_OF_NET_ERROR_TYPES); |
1382 } | 1378 } |
1383 | 1379 |
1384 } // namespace net | 1380 } // namespace net |
OLD | NEW |