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