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 |