OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 resource_type_(RESOURCE_TYPE_UNKNOWN), | 197 resource_type_(RESOURCE_TYPE_UNKNOWN), |
198 use_epsv_(true), | 198 use_epsv_(true), |
199 data_connection_port_(0), | 199 data_connection_port_(0), |
200 socket_factory_(socket_factory), | 200 socket_factory_(socket_factory), |
201 next_state_(STATE_NONE) { | 201 next_state_(STATE_NONE) { |
202 } | 202 } |
203 | 203 |
204 FtpNetworkTransaction::~FtpNetworkTransaction() { | 204 FtpNetworkTransaction::~FtpNetworkTransaction() { |
205 } | 205 } |
206 | 206 |
| 207 int FtpNetworkTransaction::Stop(int error) { |
| 208 if (command_sent_ == COMMAND_QUIT) |
| 209 return error; |
| 210 |
| 211 next_state_ = STATE_CTRL_WRITE_QUIT; |
| 212 last_error_ = error; |
| 213 return OK; |
| 214 } |
| 215 |
| 216 int FtpNetworkTransaction::RestartIgnoringLastError( |
| 217 CompletionCallback* callback) { |
| 218 return ERR_NOT_IMPLEMENTED; |
| 219 } |
| 220 |
207 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, | 221 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, |
208 CompletionCallback* callback, | 222 CompletionCallback* callback, |
209 const BoundNetLog& net_log) { | 223 const BoundNetLog& net_log) { |
210 net_log_ = net_log; | 224 net_log_ = net_log; |
211 request_ = request_info; | 225 request_ = request_info; |
212 | 226 |
213 if (request_->url.has_username()) { | 227 if (request_->url.has_username()) { |
214 GetIdentityFromURL(request_->url, &username_, &password_); | 228 GetIdentityFromURL(request_->url, &username_, &password_); |
215 } else { | 229 } else { |
216 username_ = ASCIIToUTF16("anonymous"); | 230 username_ = ASCIIToUTF16("anonymous"); |
217 password_ = ASCIIToUTF16("chrome@example.com"); | 231 password_ = ASCIIToUTF16("chrome@example.com"); |
218 } | 232 } |
219 | 233 |
220 DetectTypecode(); | 234 DetectTypecode(); |
221 | 235 |
222 next_state_ = STATE_CTRL_RESOLVE_HOST; | 236 next_state_ = STATE_CTRL_RESOLVE_HOST; |
223 int rv = DoLoop(OK); | 237 int rv = DoLoop(OK); |
224 if (rv == ERR_IO_PENDING) | 238 if (rv == ERR_IO_PENDING) |
225 user_callback_ = callback; | 239 user_callback_ = callback; |
226 return rv; | 240 return rv; |
227 } | 241 } |
228 | 242 |
229 int FtpNetworkTransaction::Stop(int error) { | |
230 if (command_sent_ == COMMAND_QUIT) | |
231 return error; | |
232 | |
233 next_state_ = STATE_CTRL_WRITE_QUIT; | |
234 last_error_ = error; | |
235 return OK; | |
236 } | |
237 | |
238 int FtpNetworkTransaction::RestartWithAuth(const string16& username, | 243 int FtpNetworkTransaction::RestartWithAuth(const string16& username, |
239 const string16& password, | 244 const string16& password, |
240 CompletionCallback* callback) { | 245 CompletionCallback* callback) { |
241 ResetStateForRestart(); | 246 ResetStateForRestart(); |
242 | 247 |
243 username_ = username; | 248 username_ = username; |
244 password_ = password; | 249 password_ = password; |
245 | 250 |
246 next_state_ = STATE_CTRL_RESOLVE_HOST; | 251 next_state_ = STATE_CTRL_RESOLVE_HOST; |
247 int rv = DoLoop(OK); | 252 int rv = DoLoop(OK); |
248 if (rv == ERR_IO_PENDING) | 253 if (rv == ERR_IO_PENDING) |
249 user_callback_ = callback; | 254 user_callback_ = callback; |
250 return rv; | 255 return rv; |
251 } | 256 } |
252 | 257 |
253 int FtpNetworkTransaction::RestartIgnoringLastError( | |
254 CompletionCallback* callback) { | |
255 return ERR_NOT_IMPLEMENTED; | |
256 } | |
257 | |
258 int FtpNetworkTransaction::Read(IOBuffer* buf, | 258 int FtpNetworkTransaction::Read(IOBuffer* buf, |
259 int buf_len, | 259 int buf_len, |
260 CompletionCallback* callback) { | 260 CompletionCallback* callback) { |
261 DCHECK(buf); | 261 DCHECK(buf); |
262 DCHECK_GT(buf_len, 0); | 262 DCHECK_GT(buf_len, 0); |
263 | 263 |
264 read_data_buf_ = buf; | 264 read_data_buf_ = buf; |
265 read_data_buf_len_ = buf_len; | 265 read_data_buf_len_ = buf_len; |
266 | 266 |
267 next_state_ = STATE_DATA_READ; | 267 next_state_ = STATE_DATA_READ; |
(...skipping 27 matching lines...) Expand all Loading... |
295 if (command_sent_ != COMMAND_NONE) | 295 if (command_sent_ != COMMAND_NONE) |
296 return LOAD_STATE_SENDING_REQUEST; | 296 return LOAD_STATE_SENDING_REQUEST; |
297 | 297 |
298 return LOAD_STATE_IDLE; | 298 return LOAD_STATE_IDLE; |
299 } | 299 } |
300 | 300 |
301 uint64 FtpNetworkTransaction::GetUploadProgress() const { | 301 uint64 FtpNetworkTransaction::GetUploadProgress() const { |
302 return 0; | 302 return 0; |
303 } | 303 } |
304 | 304 |
305 // Used to prepare and send FTP command. | 305 void FtpNetworkTransaction::ResetStateForRestart() { |
306 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, | 306 command_sent_ = COMMAND_NONE; |
307 Command cmd) { | 307 user_callback_ = NULL; |
308 // If we send a new command when we still have unprocessed responses | 308 response_ = FtpResponseInfo(); |
309 // for previous commands, the response receiving code will have no way to know | 309 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); |
310 // which responses are for which command. | 310 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer()); |
311 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); | 311 read_data_buf_ = NULL; |
| 312 read_data_buf_len_ = 0; |
| 313 if (write_buf_) |
| 314 write_buf_->SetOffset(0); |
| 315 last_error_ = OK; |
| 316 data_connection_port_ = 0; |
| 317 ctrl_socket_.reset(); |
| 318 data_socket_.reset(); |
| 319 next_state_ = STATE_NONE; |
| 320 } |
312 | 321 |
313 DCHECK(!write_command_buf_); | 322 void FtpNetworkTransaction::DoCallback(int rv) { |
314 DCHECK(!write_buf_); | 323 DCHECK(rv != ERR_IO_PENDING); |
| 324 DCHECK(user_callback_); |
315 | 325 |
316 if (!IsValidFTPCommandString(command)) { | 326 // Since Run may result in Read being called, clear callback_ up front. |
317 // Callers should validate the command themselves and return a more specific | 327 CompletionCallback* c = user_callback_; |
318 // error code. | 328 user_callback_ = NULL; |
319 NOTREACHED(); | 329 c->Run(rv); |
320 return Stop(ERR_UNEXPECTED); | 330 } |
321 } | |
322 | 331 |
323 command_sent_ = cmd; | 332 void FtpNetworkTransaction::OnIOComplete(int result) { |
324 | 333 int rv = DoLoop(result); |
325 write_command_buf_ = new IOBufferWithSize(command.length() + 2); | 334 if (rv != ERR_IO_PENDING) |
326 write_buf_ = new DrainableIOBuffer(write_command_buf_, | 335 DoCallback(rv); |
327 write_command_buf_->size()); | |
328 memcpy(write_command_buf_->data(), command.data(), command.length()); | |
329 memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); | |
330 | |
331 next_state_ = STATE_CTRL_WRITE; | |
332 return OK; | |
333 } | 336 } |
334 | 337 |
335 int FtpNetworkTransaction::ProcessCtrlResponse() { | 338 int FtpNetworkTransaction::ProcessCtrlResponse() { |
336 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); | 339 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); |
337 | 340 |
338 int rv = OK; | 341 int rv = OK; |
339 switch (command_sent_) { | 342 switch (command_sent_) { |
340 case COMMAND_NONE: | 343 case COMMAND_NONE: |
341 // TODO(phajdan.jr): Check for errors in the welcome message. | 344 // TODO(phajdan.jr): Check for errors in the welcome message. |
342 next_state_ = STATE_CTRL_WRITE_USER; | 345 next_state_ = STATE_CTRL_WRITE_USER; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 break; | 399 break; |
397 default: | 400 default: |
398 // Multiple responses for other commands are invalid. | 401 // Multiple responses for other commands are invalid. |
399 return Stop(ERR_INVALID_RESPONSE); | 402 return Stop(ERR_INVALID_RESPONSE); |
400 } | 403 } |
401 } | 404 } |
402 | 405 |
403 return rv; | 406 return rv; |
404 } | 407 } |
405 | 408 |
406 void FtpNetworkTransaction::ResetStateForRestart() { | 409 // Used to prepare and send FTP command. |
407 command_sent_ = COMMAND_NONE; | 410 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, |
408 user_callback_ = NULL; | 411 Command cmd) { |
409 response_ = FtpResponseInfo(); | 412 // If we send a new command when we still have unprocessed responses |
410 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); | 413 // for previous commands, the response receiving code will have no way to know |
411 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer()); | 414 // which responses are for which command. |
412 read_data_buf_ = NULL; | 415 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); |
413 read_data_buf_len_ = 0; | |
414 if (write_buf_) | |
415 write_buf_->SetOffset(0); | |
416 last_error_ = OK; | |
417 data_connection_port_ = 0; | |
418 ctrl_socket_.reset(); | |
419 data_socket_.reset(); | |
420 next_state_ = STATE_NONE; | |
421 } | |
422 | 416 |
423 void FtpNetworkTransaction::DoCallback(int rv) { | 417 DCHECK(!write_command_buf_); |
424 DCHECK(rv != ERR_IO_PENDING); | 418 DCHECK(!write_buf_); |
425 DCHECK(user_callback_); | |
426 | 419 |
427 // Since Run may result in Read being called, clear callback_ up front. | 420 if (!IsValidFTPCommandString(command)) { |
428 CompletionCallback* c = user_callback_; | 421 // Callers should validate the command themselves and return a more specific |
429 user_callback_ = NULL; | 422 // error code. |
430 c->Run(rv); | 423 NOTREACHED(); |
431 } | 424 return Stop(ERR_UNEXPECTED); |
| 425 } |
432 | 426 |
433 void FtpNetworkTransaction::OnIOComplete(int result) { | 427 command_sent_ = cmd; |
434 int rv = DoLoop(result); | 428 |
435 if (rv != ERR_IO_PENDING) | 429 write_command_buf_ = new IOBufferWithSize(command.length() + 2); |
436 DoCallback(rv); | 430 write_buf_ = new DrainableIOBuffer(write_command_buf_, |
| 431 write_command_buf_->size()); |
| 432 memcpy(write_command_buf_->data(), command.data(), command.length()); |
| 433 memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); |
| 434 |
| 435 next_state_ = STATE_CTRL_WRITE; |
| 436 return OK; |
437 } | 437 } |
438 | 438 |
439 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( | 439 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( |
440 bool is_directory) const { | 440 bool is_directory) const { |
441 std::string path(current_remote_directory_); | 441 std::string path(current_remote_directory_); |
442 if (request_->url.has_path()) { | 442 if (request_->url.has_path()) { |
443 std::string gurl_path(request_->url.path()); | 443 std::string gurl_path(request_->url.path()); |
444 | 444 |
445 // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. | 445 // Get rid of the typecode, see RFC 1738 section 3.2.2. FTP url-path. |
446 std::string::size_type pos = gurl_path.rfind(';'); | 446 std::string::size_type pos = gurl_path.rfind(';'); |
(...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 940 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
941 case ERROR_CLASS_PERMANENT_ERROR: | 941 case ERROR_CLASS_PERMANENT_ERROR: |
942 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | 942 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
943 default: | 943 default: |
944 NOTREACHED(); | 944 NOTREACHED(); |
945 return Stop(ERR_UNEXPECTED); | 945 return Stop(ERR_UNEXPECTED); |
946 } | 946 } |
947 return OK; | 947 return OK; |
948 } | 948 } |
949 | 949 |
950 // SIZE command | |
951 int FtpNetworkTransaction::DoCtrlWriteSIZE() { | |
952 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); | |
953 next_state_ = STATE_CTRL_READ; | |
954 return SendFtpCommand(command, COMMAND_SIZE); | |
955 } | |
956 | |
957 int FtpNetworkTransaction::ProcessResponseSIZE( | |
958 const FtpCtrlResponse& response) { | |
959 switch (GetErrorClass(response.status_code)) { | |
960 case ERROR_CLASS_INITIATED: | |
961 break; | |
962 case ERROR_CLASS_OK: | |
963 if (response.lines.size() != 1) | |
964 return Stop(ERR_INVALID_RESPONSE); | |
965 int64 size; | |
966 if (!base::StringToInt64(response.lines[0], &size)) | |
967 return Stop(ERR_INVALID_RESPONSE); | |
968 if (size < 0) | |
969 return Stop(ERR_INVALID_RESPONSE); | |
970 | |
971 // A successful response to SIZE does not mean the resource is a file. | |
972 // Some FTP servers (for example, the qnx one) send a SIZE even for | |
973 // directories. | |
974 response_.expected_content_size = size; | |
975 break; | |
976 case ERROR_CLASS_INFO_NEEDED: | |
977 break; | |
978 case ERROR_CLASS_TRANSIENT_ERROR: | |
979 break; | |
980 case ERROR_CLASS_PERMANENT_ERROR: | |
981 // It's possible that SIZE failed because the path is a directory. | |
982 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && | |
983 response.status_code != 550) { | |
984 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); | |
985 } | |
986 break; | |
987 default: | |
988 NOTREACHED(); | |
989 return Stop(ERR_UNEXPECTED); | |
990 } | |
991 | |
992 if (resource_type_ == RESOURCE_TYPE_FILE) | |
993 next_state_ = STATE_CTRL_WRITE_RETR; | |
994 else | |
995 next_state_ = STATE_CTRL_WRITE_CWD; | |
996 | |
997 return OK; | |
998 } | |
999 | |
1000 // RETR command | 950 // RETR command |
1001 int FtpNetworkTransaction::DoCtrlWriteRETR() { | 951 int FtpNetworkTransaction::DoCtrlWriteRETR() { |
1002 std::string command = "RETR " + GetRequestPathForFtpCommand(false); | 952 std::string command = "RETR " + GetRequestPathForFtpCommand(false); |
1003 next_state_ = STATE_CTRL_READ; | 953 next_state_ = STATE_CTRL_READ; |
1004 return SendFtpCommand(command, COMMAND_RETR); | 954 return SendFtpCommand(command, COMMAND_RETR); |
1005 } | 955 } |
1006 | 956 |
1007 int FtpNetworkTransaction::ProcessResponseRETR( | 957 int FtpNetworkTransaction::ProcessResponseRETR( |
1008 const FtpCtrlResponse& response) { | 958 const FtpCtrlResponse& response) { |
1009 switch (GetErrorClass(response.status_code)) { | 959 switch (GetErrorClass(response.status_code)) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1041 return Stop(ERR_UNEXPECTED); | 991 return Stop(ERR_UNEXPECTED); |
1042 } | 992 } |
1043 | 993 |
1044 // We should be sure about our resource type now. Otherwise we risk | 994 // We should be sure about our resource type now. Otherwise we risk |
1045 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). | 995 // an infinite loop (RETR can later send CWD, and CWD can later send RETR). |
1046 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); | 996 DCHECK_NE(RESOURCE_TYPE_UNKNOWN, resource_type_); |
1047 | 997 |
1048 return OK; | 998 return OK; |
1049 } | 999 } |
1050 | 1000 |
| 1001 // SIZE command |
| 1002 int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
| 1003 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); |
| 1004 next_state_ = STATE_CTRL_READ; |
| 1005 return SendFtpCommand(command, COMMAND_SIZE); |
| 1006 } |
| 1007 |
| 1008 int FtpNetworkTransaction::ProcessResponseSIZE( |
| 1009 const FtpCtrlResponse& response) { |
| 1010 switch (GetErrorClass(response.status_code)) { |
| 1011 case ERROR_CLASS_INITIATED: |
| 1012 break; |
| 1013 case ERROR_CLASS_OK: |
| 1014 if (response.lines.size() != 1) |
| 1015 return Stop(ERR_INVALID_RESPONSE); |
| 1016 int64 size; |
| 1017 if (!base::StringToInt64(response.lines[0], &size)) |
| 1018 return Stop(ERR_INVALID_RESPONSE); |
| 1019 if (size < 0) |
| 1020 return Stop(ERR_INVALID_RESPONSE); |
| 1021 |
| 1022 // A successful response to SIZE does not mean the resource is a file. |
| 1023 // Some FTP servers (for example, the qnx one) send a SIZE even for |
| 1024 // directories. |
| 1025 response_.expected_content_size = size; |
| 1026 break; |
| 1027 case ERROR_CLASS_INFO_NEEDED: |
| 1028 break; |
| 1029 case ERROR_CLASS_TRANSIENT_ERROR: |
| 1030 break; |
| 1031 case ERROR_CLASS_PERMANENT_ERROR: |
| 1032 // It's possible that SIZE failed because the path is a directory. |
| 1033 if (resource_type_ == RESOURCE_TYPE_UNKNOWN && |
| 1034 response.status_code != 550) { |
| 1035 return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code)); |
| 1036 } |
| 1037 break; |
| 1038 default: |
| 1039 NOTREACHED(); |
| 1040 return Stop(ERR_UNEXPECTED); |
| 1041 } |
| 1042 |
| 1043 if (resource_type_ == RESOURCE_TYPE_FILE) |
| 1044 next_state_ = STATE_CTRL_WRITE_RETR; |
| 1045 else |
| 1046 next_state_ = STATE_CTRL_WRITE_CWD; |
| 1047 |
| 1048 return OK; |
| 1049 } |
| 1050 |
1051 // CWD command | 1051 // CWD command |
1052 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 1052 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
1053 std::string command = "CWD " + GetRequestPathForFtpCommand(true); | 1053 std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
1054 next_state_ = STATE_CTRL_READ; | 1054 next_state_ = STATE_CTRL_READ; |
1055 return SendFtpCommand(command, COMMAND_CWD); | 1055 return SendFtpCommand(command, COMMAND_CWD); |
1056 } | 1056 } |
1057 | 1057 |
1058 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { | 1058 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
1059 // We should never issue CWD if we know the target resource is a file. | 1059 // We should never issue CWD if we know the target resource is a file. |
1060 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); | 1060 DCHECK_NE(RESOURCE_TYPE_FILE, resource_type_); |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1291 if (!had_error_type[type]) { | 1291 if (!had_error_type[type]) { |
1292 had_error_type[type] = true; | 1292 had_error_type[type] = true; |
1293 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", | 1293 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", |
1294 type, NUM_OF_NET_ERROR_TYPES); | 1294 type, NUM_OF_NET_ERROR_TYPES); |
1295 } | 1295 } |
1296 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", | 1296 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", |
1297 type, NUM_OF_NET_ERROR_TYPES); | 1297 type, NUM_OF_NET_ERROR_TYPES); |
1298 } | 1298 } |
1299 | 1299 |
1300 } // namespace net | 1300 } // namespace net |
OLD | NEW |