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 read_data_buf_len_(0), | 217 read_data_buf_len_(0), |
| 218 last_error_(OK), | 218 last_error_(OK), |
| 219 system_type_(SYSTEM_TYPE_UNKNOWN), | 219 system_type_(SYSTEM_TYPE_UNKNOWN), |
| 220 // Use image (binary) transfer by default. It should always work, | 220 // Use image (binary) transfer by default. It should always work, |
| 221 // whereas the ascii transfer may damage binary data. | 221 // whereas the ascii transfer may damage binary data. |
| 222 data_type_(DATA_TYPE_IMAGE), | 222 data_type_(DATA_TYPE_IMAGE), |
| 223 resource_type_(RESOURCE_TYPE_UNKNOWN), | 223 resource_type_(RESOURCE_TYPE_UNKNOWN), |
| 224 use_epsv_(true), | 224 use_epsv_(true), |
| 225 data_connection_port_(0), | 225 data_connection_port_(0), |
| 226 socket_factory_(socket_factory), | 226 socket_factory_(socket_factory), |
| 227 next_state_(STATE_NONE) { | 227 next_state_(STATE_NONE), |
| 228 state_after_data_connection_(STATE_CTRL_WRITE_SIZE) { | |
| 228 } | 229 } |
| 229 | 230 |
| 230 FtpNetworkTransaction::~FtpNetworkTransaction() { | 231 FtpNetworkTransaction::~FtpNetworkTransaction() { |
| 231 } | 232 } |
| 232 | 233 |
| 233 int FtpNetworkTransaction::Stop(int error) { | 234 int FtpNetworkTransaction::Stop(int error) { |
| 234 if (command_sent_ == COMMAND_QUIT) | 235 if (command_sent_ == COMMAND_QUIT) |
| 235 return error; | 236 return error; |
| 236 | 237 |
| 237 next_state_ = STATE_CTRL_WRITE_QUIT; | 238 next_state_ = STATE_CTRL_WRITE_QUIT; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); | 340 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer(net_log_)); |
| 340 read_data_buf_ = NULL; | 341 read_data_buf_ = NULL; |
| 341 read_data_buf_len_ = 0; | 342 read_data_buf_len_ = 0; |
| 342 if (write_buf_) | 343 if (write_buf_) |
| 343 write_buf_->SetOffset(0); | 344 write_buf_->SetOffset(0); |
| 344 last_error_ = OK; | 345 last_error_ = OK; |
| 345 data_connection_port_ = 0; | 346 data_connection_port_ = 0; |
| 346 ctrl_socket_.reset(); | 347 ctrl_socket_.reset(); |
| 347 data_socket_.reset(); | 348 data_socket_.reset(); |
| 348 next_state_ = STATE_NONE; | 349 next_state_ = STATE_NONE; |
| 350 state_after_data_connection_ = STATE_CTRL_WRITE_SIZE; | |
| 351 } | |
| 352 | |
| 353 void FtpNetworkTransaction::ResetDataConnectionAfterError(State next_state) { | |
| 354 // The server _might_ have reset the data connection | |
| 355 // (see RFC 959 3.2. ESTABLISHING DATA CONNECTIONS: | |
| 356 // "The server MUST close the data connection under the following | |
| 357 // conditions: | |
| 358 // ... | |
| 359 // 5. An irrecoverable error condition occurs.") | |
| 360 // | |
| 361 // It is ambiguous whan an irrecoverable error condition is, | |
|
eroman
2012/11/13 20:36:21
typo: "whan" --> "what" or "when" ?
Paweł Hajdan Jr.
2012/11/14 17:30:18
Done.
| |
| 362 // so we take no chances. | |
| 363 state_after_data_connection_ = next_state; | |
| 364 next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV; | |
| 349 } | 365 } |
| 350 | 366 |
| 351 void FtpNetworkTransaction::DoCallback(int rv) { | 367 void FtpNetworkTransaction::DoCallback(int rv) { |
| 352 DCHECK(rv != ERR_IO_PENDING); | 368 DCHECK(rv != ERR_IO_PENDING); |
| 353 DCHECK(!user_callback_.is_null()); | 369 DCHECK(!user_callback_.is_null()); |
| 354 | 370 |
| 355 // Since Run may result in Read being called, clear callback_ up front. | 371 // Since Run may result in Read being called, clear callback_ up front. |
| 356 CompletionCallback c = user_callback_; | 372 CompletionCallback c = user_callback_; |
| 357 user_callback_.Reset(); | 373 user_callback_.Reset(); |
| 358 c.Run(rv); | 374 c.Run(rv); |
| (...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1043 | 1059 |
| 1044 // SIZE command | 1060 // SIZE command |
| 1045 int FtpNetworkTransaction::DoCtrlWriteSIZE() { | 1061 int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
| 1046 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); | 1062 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); |
| 1047 next_state_ = STATE_CTRL_READ; | 1063 next_state_ = STATE_CTRL_READ; |
| 1048 return SendFtpCommand(command, command, COMMAND_SIZE); | 1064 return SendFtpCommand(command, command, COMMAND_SIZE); |
| 1049 } | 1065 } |
| 1050 | 1066 |
| 1051 int FtpNetworkTransaction::ProcessResponseSIZE( | 1067 int FtpNetworkTransaction::ProcessResponseSIZE( |
| 1052 const FtpCtrlResponse& response) { | 1068 const FtpCtrlResponse& response) { |
| 1069 State state_after_size; | |
| 1070 if (resource_type_ == RESOURCE_TYPE_FILE) | |
| 1071 state_after_size = STATE_CTRL_WRITE_RETR; | |
| 1072 else | |
| 1073 state_after_size = STATE_CTRL_WRITE_CWD; | |
| 1074 | |
| 1053 switch (GetErrorClass(response.status_code)) { | 1075 switch (GetErrorClass(response.status_code)) { |
| 1054 case ERROR_CLASS_INITIATED: | 1076 case ERROR_CLASS_INITIATED: |
| 1077 next_state_ = state_after_size; | |
| 1055 break; | 1078 break; |
| 1056 case ERROR_CLASS_OK: | 1079 case ERROR_CLASS_OK: |
| 1057 if (response.lines.size() != 1) | 1080 if (response.lines.size() != 1) |
| 1058 return Stop(ERR_INVALID_RESPONSE); | 1081 return Stop(ERR_INVALID_RESPONSE); |
| 1059 int64 size; | 1082 int64 size; |
| 1060 if (!base::StringToInt64(response.lines[0], &size)) | 1083 if (!base::StringToInt64(response.lines[0], &size)) |
| 1061 return Stop(ERR_INVALID_RESPONSE); | 1084 return Stop(ERR_INVALID_RESPONSE); |
| 1062 if (size < 0) | 1085 if (size < 0) |
| 1063 return Stop(ERR_INVALID_RESPONSE); | 1086 return Stop(ERR_INVALID_RESPONSE); |
| 1064 | 1087 |
| 1065 // A successful response to SIZE does not mean the resource is a file. | 1088 // A successful response to SIZE does not mean the resource is a file. |
| 1066 // Some FTP servers (for example, the qnx one) send a SIZE even for | 1089 // Some FTP servers (for example, the qnx one) send a SIZE even for |
| 1067 // directories. | 1090 // directories. |
| 1068 response_.expected_content_size = size; | 1091 response_.expected_content_size = size; |
| 1092 | |
| 1093 next_state_ = state_after_size; | |
| 1069 break; | 1094 break; |
| 1070 case ERROR_CLASS_INFO_NEEDED: | 1095 case ERROR_CLASS_INFO_NEEDED: |
| 1096 next_state_ = state_after_size; | |
| 1071 break; | 1097 break; |
| 1072 case ERROR_CLASS_TRANSIENT_ERROR: | 1098 case ERROR_CLASS_TRANSIENT_ERROR: |
| 1099 ResetDataConnectionAfterError(state_after_size); | |
| 1073 break; | 1100 break; |
| 1074 case ERROR_CLASS_PERMANENT_ERROR: | 1101 case ERROR_CLASS_PERMANENT_ERROR: |
| 1075 // It's possible that SIZE failed because the path is a directory. | 1102 // It's possible that SIZE failed because the path is a directory. |
| 1076 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && | 1103 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && |
| 1077 response.status_code != 550) { | 1104 response.status_code != 550) { |
| 1078 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 1105 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
| 1079 } | 1106 } |
| 1107 | |
| 1108 ResetDataConnectionAfterError(state_after_size); | |
| 1080 break; | 1109 break; |
| 1081 default: | 1110 default: |
| 1082 NOTREACHED(); | 1111 NOTREACHED(); |
| 1083 return Stop(ERR_UNEXPECTED); | 1112 return Stop(ERR_UNEXPECTED); |
| 1084 } | 1113 } |
| 1085 | 1114 |
| 1086 if (resource_type_ == RESOURCE_TYPE_FILE) | |
| 1087 next_state_ = STATE_CTRL_WRITE_RETR; | |
| 1088 else | |
| 1089 next_state_ = STATE_CTRL_WRITE_CWD; | |
| 1090 | |
| 1091 return OK; | 1115 return OK; |
| 1092 } | 1116 } |
| 1093 | 1117 |
| 1094 // CWD command | 1118 // CWD command |
| 1095 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 1119 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
| 1096 std::string command = "CWD " + GetRequestPathForFtpCommand(true); | 1120 std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
| 1097 next_state_ = STATE_CTRL_READ; | 1121 next_state_ = STATE_CTRL_READ; |
| 1098 return SendFtpCommand(command, command, COMMAND_CWD); | 1122 return SendFtpCommand(command, command, COMMAND_CWD); |
| 1099 } | 1123 } |
| 1100 | 1124 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1135 // We're assuming that the resource is a directory, but the server | 1159 // We're assuming that the resource is a directory, but the server |
| 1136 // says it's not true. The most probable interpretation is that it | 1160 // says it's not true. The most probable interpretation is that it |
| 1137 // doesn't exist (with FTP we can't be sure). | 1161 // doesn't exist (with FTP we can't be sure). |
| 1138 return Stop(ERR_FILE_NOT_FOUND); | 1162 return Stop(ERR_FILE_NOT_FOUND); |
| 1139 } | 1163 } |
| 1140 | 1164 |
| 1141 // We are here because SIZE failed and we are not sure what the resource | 1165 // We are here because SIZE failed and we are not sure what the resource |
| 1142 // type is. It could still be file, and SIZE could fail because of | 1166 // type is. It could still be file, and SIZE could fail because of |
| 1143 // an access error (http://crbug.com/56734). Try RETR just to be sure. | 1167 // an access error (http://crbug.com/56734). Try RETR just to be sure. |
| 1144 resource_type_ = RESOURCE_TYPE_FILE; | 1168 resource_type_ = RESOURCE_TYPE_FILE; |
| 1145 next_state_ = STATE_CTRL_WRITE_RETR; | |
| 1146 | 1169 |
| 1170 ResetDataConnectionAfterError(STATE_CTRL_WRITE_RETR); | |
| 1147 return OK; | 1171 return OK; |
| 1148 } | 1172 } |
| 1149 | 1173 |
| 1150 // LIST command | 1174 // LIST command |
| 1151 int FtpNetworkTransaction::DoCtrlWriteLIST() { | 1175 int FtpNetworkTransaction::DoCtrlWriteLIST() { |
| 1152 std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST"); | 1176 std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST"); |
| 1153 next_state_ = STATE_CTRL_READ; | 1177 next_state_ = STATE_CTRL_READ; |
| 1154 return SendFtpCommand(command, command, COMMAND_LIST); | 1178 return SendFtpCommand(command, command, COMMAND_LIST); |
| 1155 } | 1179 } |
| 1156 | 1180 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1226 return OK; | 1250 return OK; |
| 1227 } | 1251 } |
| 1228 | 1252 |
| 1229 // Only record the connection error after we've applied all our fallbacks. | 1253 // Only record the connection error after we've applied all our fallbacks. |
| 1230 // We want to capture the final error, one we're not going to recover from. | 1254 // We want to capture the final error, one we're not going to recover from. |
| 1231 RecordDataConnectionError(result); | 1255 RecordDataConnectionError(result); |
| 1232 | 1256 |
| 1233 if (result != OK) | 1257 if (result != OK) |
| 1234 return Stop(result); | 1258 return Stop(result); |
| 1235 | 1259 |
| 1236 next_state_ = STATE_CTRL_WRITE_SIZE; | 1260 next_state_ = state_after_data_connection_; |
| 1237 return OK; | 1261 return OK; |
| 1238 } | 1262 } |
| 1239 | 1263 |
| 1240 int FtpNetworkTransaction::DoDataRead() { | 1264 int FtpNetworkTransaction::DoDataRead() { |
| 1241 DCHECK(read_data_buf_); | 1265 DCHECK(read_data_buf_); |
| 1242 DCHECK_GT(read_data_buf_len_, 0); | 1266 DCHECK_GT(read_data_buf_len_, 0); |
| 1243 | 1267 |
| 1244 if (data_socket_ == NULL || !data_socket_->IsConnected()) { | 1268 if (data_socket_ == NULL || !data_socket_->IsConnected()) { |
| 1245 // If we don't destroy the data socket completely, some servers will wait | 1269 // If we don't destroy the data socket completely, some servers will wait |
| 1246 // for us (http://crbug.com/21127). The half-closed TCP connection needs | 1270 // for us (http://crbug.com/21127). The half-closed TCP connection needs |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1348 if (!had_error_type[type]) { | 1372 if (!had_error_type[type]) { |
| 1349 had_error_type[type] = true; | 1373 had_error_type[type] = true; |
| 1350 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", | 1374 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", |
| 1351 type, NUM_OF_NET_ERROR_TYPES); | 1375 type, NUM_OF_NET_ERROR_TYPES); |
| 1352 } | 1376 } |
| 1353 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", | 1377 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", |
| 1354 type, NUM_OF_NET_ERROR_TYPES); | 1378 type, NUM_OF_NET_ERROR_TYPES); |
| 1355 } | 1379 } |
| 1356 | 1380 |
| 1357 } // namespace net | 1381 } // namespace net |
| OLD | NEW |