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 |