1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this 2 // source code is governed by a BSD-style license that can be found in the 3 // LICENSE file. 4 5 #include "net/ftp/ftp_network_transaction.h" 6 7 #include "base/compiler_specific.h" 8 #include "base/histogram.h" 9 #include "base/string_util.h" 10 #include "net/base/connection_type_histograms.h" 11 #include "net/base/escape.h" 12 #include "net/base/load_log.h" 13 #include "net/base/net_errors.h" 14 #include "net/base/net_util.h" 15 #include "net/ftp/ftp_network_session.h" 16 #include "net/ftp/ftp_request_info.h" 17 #include "net/ftp/ftp_util.h" 18 #include "net/socket/client_socket.h" 19 #include "net/socket/client_socket_factory.h" 20 21 // TODO(ibrar): Try to avoid sscanf. 22 #if !defined(COMPILER_MSVC) 23 #define sscanf_s sscanf 24 #endif 25 26 const char kCRLF[] = "\r\n"; 27 28 const int kCtrlBufLen = 1024; 29 30 namespace { 31 32 // Returns true if |input| can be safely used as a part of FTP command. 33 bool IsValidFTPCommandString(const std::string& input) { 34 // RFC 959 only allows ASCII strings, but at least Firefox can send non-ASCII 35 // characters in the command if the request path contains them. To be 36 // compatible, we do the same and allow non-ASCII characters in a command. 37 38 // Protect agains newline injection attack. 39 if (input.find_first_of("\r\n") != std::string::npos) 40 return false; 41 42 return true; 43 } 44 45 } // namespace 46 47 namespace net { 48 49 FtpNetworkTransaction::FtpNetworkTransaction( 50 FtpNetworkSession* session, 51 ClientSocketFactory* socket_factory) 52 : command_sent_(COMMAND_NONE), 53 ALLOW_THIS_IN_INITIALIZER_LIST( 54 io_callback_(this, &FtpNetworkTransaction::OnIOComplete)), 55 user_callback_(NULL), 56 session_(session), 57 request_(NULL), 58 resolver_(session->host_resolver()), 59 read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), 60 ctrl_response_buffer_(new FtpCtrlResponseBuffer()), 61 read_data_buf_len_(0), 62 file_data_len_(0), 63 last_error_(OK), 64 system_type_(SYSTEM_TYPE_UNKNOWN), 65 retr_failed_(false), 66 data_connection_port_(0), 67 socket_factory_(socket_factory), 68 next_state_(STATE_NONE) { 69 } 70 71 FtpNetworkTransaction::~FtpNetworkTransaction() { 72 } 73 74 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, 75 CompletionCallback* callback, 76 LoadLog* load_log) { 77 load_log_ = load_log; 78 request_ = request_info; 79 80 if (request_->url.has_username()) { 81 GetIdentityFromURL(request_->url, &username_, &password_); 82 } else { 83 username_ = L"anonymous"; 84 password_ = L"chrome (at) example.com"; 85 } 86 87 next_state_ = STATE_CTRL_INIT; 88 int rv = DoLoop(OK); 89 if (rv == ERR_IO_PENDING) 90 user_callback_ = callback; 91 return rv; 92 } 93 94 int FtpNetworkTransaction::Stop(int error) { 95 if (command_sent_ == COMMAND_QUIT) 96 return error; 97 98 next_state_ = STATE_CTRL_WRITE_QUIT; 99 last_error_ = error; 100 return OK; 101 } 102 103 int FtpNetworkTransaction::RestartWithAuth(const std::wstring& username, 104 const std::wstring& password, 105 CompletionCallback* callback) { 106 ResetStateForRestart(); 107 108 username_ = username; 109 password_ = password; 110 111 next_state_ = STATE_CTRL_INIT; 112 int rv = DoLoop(OK); 113 if (rv == ERR_IO_PENDING) 114 user_callback_ = callback; 115 return rv; 116 } 117 118 int FtpNetworkTransaction::RestartIgnoringLastError( 119 CompletionCallback* callback) { 120 return ERR_FAILED; 121 } 122 123 int FtpNetworkTransaction::Read(IOBuffer* buf, 124 int buf_len, 125 CompletionCallback* callback) { 126 DCHECK(buf); 127 DCHECK_GT(buf_len, 0); 128 129 read_data_buf_ = buf; 130 read_data_buf_len_ = buf_len; 131 132 next_state_ = STATE_DATA_READ; 133 int rv = DoLoop(OK); 134 if (rv == ERR_IO_PENDING) 135 user_callback_ = callback; 136 return rv; 137 } 138 139 const FtpResponseInfo* FtpNetworkTransaction::GetResponseInfo() const { 140 return &response_; 141 } 142 143 LoadState FtpNetworkTransaction::GetLoadState() const { 144 if (next_state_ == STATE_CTRL_RESOLVE_HOST_COMPLETE) 145 return LOAD_STATE_RESOLVING_HOST; 146 147 if (next_state_ == STATE_CTRL_CONNECT_COMPLETE || 148 next_state_ == STATE_DATA_CONNECT_COMPLETE) 149 return LOAD_STATE_CONNECTING; 150 151 if (next_state_ == STATE_DATA_READ_COMPLETE) 152 return LOAD_STATE_READING_RESPONSE; 153 154 if (command_sent_ == COMMAND_RETR && read_data_buf_.get()) 155 return LOAD_STATE_READING_RESPONSE; 156 157 if (command_sent_ == COMMAND_QUIT) 158 return LOAD_STATE_IDLE; 159 160 if (command_sent_ != COMMAND_NONE) 161 return LOAD_STATE_SENDING_REQUEST; 162 163 return LOAD_STATE_IDLE; 164 } 165 166 uint64 FtpNetworkTransaction::GetUploadProgress() const { 167 return 0; 168 } 169 170 // Used to prepare and send FTP command. 171 int FtpNetworkTransaction::SendFtpCommand(const std::string& command, 172 Command cmd) { 173 // If we send a new command when we still have unprocessed responses 174 // for previous commands, the response receiving code will have no way to know 175 // which responses are for which command. 176 DCHECK(!ctrl_response_buffer_->ResponseAvailable()); 177 178 DCHECK(!write_command_buf_); 179 DCHECK(!write_buf_); 180 181 if (!IsValidFTPCommandString(command)) { 182 // Callers should validate the command themselves and return a more specific 183 // error code. 184 NOTREACHED(); 185 return Stop(ERR_UNEXPECTED); 186 } 187 188 command_sent_ = cmd; 189 190 write_command_buf_ = new IOBufferWithSize(command.length() + 2); 191 write_buf_ = new DrainableIOBuffer(write_command_buf_, 192 write_command_buf_->size()); 193 memcpy(write_command_buf_->data(), command.data(), command.length()); 194 memcpy(write_command_buf_->data() + command.length(), kCRLF, 2); 195 196 next_state_ = STATE_CTRL_WRITE; 197 return OK; 198 } 199 200 // static 201 FtpNetworkTransaction::ErrorClass FtpNetworkTransaction::GetErrorClass( 202 int response_code) { 203 if (response_code >= 100 && response_code <= 199) 204 return ERROR_CLASS_INITIATED; 205 206 if (response_code >= 200 && response_code <= 299) 207 return ERROR_CLASS_OK; 208 209 if (response_code >= 300 && response_code <= 399) 210 return ERROR_CLASS_INFO_NEEDED; 211 212 if (response_code >= 400 && response_code <= 499) 213 return ERROR_CLASS_TRANSIENT_ERROR; 214 215 if (response_code >= 500 && response_code <= 599) 216 return ERROR_CLASS_PERMANENT_ERROR; 217 218 // We should not be called on invalid error codes. 219 NOTREACHED(); 220 return ERROR_CLASS_PERMANENT_ERROR; 221 } 222 223 int FtpNetworkTransaction::ProcessCtrlResponse() { 224 FtpCtrlResponse response = ctrl_response_buffer_->PopResponse(); 225 226 int rv = OK; 227 switch (command_sent_) { 228 case COMMAND_NONE: 229 // TODO(phajdan.jr): Check for errors in the welcome message. 230 next_state_ = STATE_CTRL_WRITE_USER; 231 break; 232 case COMMAND_USER: 233 rv = ProcessResponseUSER(response); 234 break; 235 case COMMAND_PASS: 236 rv = ProcessResponsePASS(response); 237 break; 238 case COMMAND_ACCT: 239 rv = ProcessResponseACCT(response); 240 break; 241 case COMMAND_SYST: 242 rv = ProcessResponseSYST(response); 243 break; 244 case COMMAND_PWD: 245 rv = ProcessResponsePWD(response); 246 break; 247 case COMMAND_TYPE: 248 rv = ProcessResponseTYPE(response); 249 break; 250 case COMMAND_PASV: 251 rv = ProcessResponsePASV(response); 252 break; 253 case COMMAND_SIZE: 254 rv = ProcessResponseSIZE(response); 255 break; 256 case COMMAND_RETR: 257 rv = ProcessResponseRETR(response); 258 break; 259 case COMMAND_CWD: 260 rv = ProcessResponseCWD(response); 261 break; 262 case COMMAND_MLSD: 263 rv = ProcessResponseMLSD(response); 264 break; 265 case COMMAND_LIST: 266 rv = ProcessResponseLIST(response); 267 break; 268 case COMMAND_MDTM: 269 rv = ProcessResponseMDTM(response); 270 break; 271 case COMMAND_QUIT: 272 rv = ProcessResponseQUIT(response); 273 break; 274 default: 275 LOG(DFATAL) << "Unexpected value of command_sent_: " << command_sent_; 276 return ERR_UNEXPECTED; 277 } 278 279 // We may get multiple responses for some commands, 280 // see http://crbug.com/18036. 281 while (ctrl_response_buffer_->ResponseAvailable() && rv == OK) { 282 response = ctrl_response_buffer_->PopResponse(); 283 284 switch (command_sent_) { 285 case COMMAND_RETR: 286 rv = ProcessResponseRETR(response); 287 break; 288 case COMMAND_MLSD: 289 rv = ProcessResponseMLSD(response); 290 break; 291 case COMMAND_LIST: 292 rv = ProcessResponseLIST(response); 293 break; 294 default: 295 // Multiple responses for other commands are invalid. 296 return Stop(ERR_INVALID_RESPONSE); 297 } 298 } 299 300 return rv; 301 } 302 303 void FtpNetworkTransaction::ResetStateForRestart() { 304 command_sent_ = COMMAND_NONE; 305 user_callback_ = NULL; 306 response_ = FtpResponseInfo(); 307 read_ctrl_buf_ = new IOBuffer(kCtrlBufLen); 308 ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer()); 309 read_data_buf_ = NULL; 310 read_data_buf_len_ = 0; 311 file_data_len_ = 0; 312 if (write_buf_) 313 write_buf_->SetOffset(0); 314 last_error_ = OK; 315 retr_failed_ = false; 316 data_connection_port_ = 0; 317 ctrl_socket_.reset(); 318 data_socket_.reset(); 319 next_state_ = STATE_NONE; 320 } 321 322 void FtpNetworkTransaction::DoCallback(int rv) { 323 DCHECK(rv != ERR_IO_PENDING); 324 DCHECK(user_callback_); 325 326 // Since Run may result in Read being called, clear callback_ up front. 327 CompletionCallback* c = user_callback_; 328 user_callback_ = NULL; 329 c->Run(rv); 330 } 331 332 void FtpNetworkTransaction::OnIOComplete(int result) { 333 int rv = DoLoop(result); 334 if (rv != ERR_IO_PENDING) 335 DoCallback(rv); 336 } 337 338 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( 339 bool is_directory) const { 340 std::string path(current_remote_directory_); 341 if (request_->url.has_path()) 342 path.append(request_->url.path()); 343 // Make sure that if the path is expected to be a file, it won't end 344 // with a trailing slash. 345 if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/') 346 path.erase(path.length() - 1); 347 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | 348 UnescapeRule::URL_SPECIAL_CHARS; 349 // This may unescape to non-ASCII characters, but we allow that. See the 350 // comment for IsValidFTPCommandString. 351 path = UnescapeURLComponent(path, unescape_rules); 352 353 if (system_type_ == SYSTEM_TYPE_VMS) { 354 if (is_directory) 355 path = FtpUtil::UnixDirectoryPathToVMS(path); 356 else 357 path = FtpUtil::UnixFilePathToVMS(path); 358 } 359 360 DCHECK(IsValidFTPCommandString(path)); 361 return path; 362 } 363 364 int FtpNetworkTransaction::DoLoop(int result) { 365 DCHECK(next_state_ != STATE_NONE); 366 367 int rv = result; 368 do { 369 State state = next_state_; 370 next_state_ = STATE_NONE; 371 switch (state) { 372 case STATE_CTRL_INIT: 373 DCHECK(rv == OK); 374 rv = DoCtrlInit(); 375 break; 376 case STATE_CTRL_INIT_COMPLETE: 377 rv = DoCtrlInitComplete(rv); 378 break; 379 case STATE_CTRL_RESOLVE_HOST: 380 DCHECK(rv == OK); 381 rv = DoCtrlResolveHost(); 382 break; 383 case STATE_CTRL_RESOLVE_HOST_COMPLETE: 384 rv = DoCtrlResolveHostComplete(rv); 385 break; 386 case STATE_CTRL_CONNECT: 387 DCHECK(rv == OK); 388 rv = DoCtrlConnect(); 389 break; 390 case STATE_CTRL_CONNECT_COMPLETE: 391 rv = DoCtrlConnectComplete(rv); 392 break; 393 case STATE_CTRL_READ: 394 DCHECK(rv == OK); 395 rv = DoCtrlRead(); 396 break; 397 case STATE_CTRL_READ_COMPLETE: 398 rv = DoCtrlReadComplete(rv); 399 break; 400 case STATE_CTRL_WRITE: 401 DCHECK(rv == OK); 402 rv = DoCtrlWrite(); 403 break; 404 case STATE_CTRL_WRITE_COMPLETE: 405 rv = DoCtrlWriteComplete(rv); 406 break; 407 case STATE_CTRL_WRITE_USER: 408 DCHECK(rv == OK); 409 rv = DoCtrlWriteUSER(); 410 break; 411 case STATE_CTRL_WRITE_PASS: 412 DCHECK(rv == OK); 413 rv = DoCtrlWritePASS(); 414 break; 415 case STATE_CTRL_WRITE_SYST: 416 DCHECK(rv == OK); 417 rv = DoCtrlWriteSYST(); 418 break; 419 case STATE_CTRL_WRITE_ACCT: 420 DCHECK(rv == OK); 421 rv = DoCtrlWriteACCT(); 422 break; 423 case STATE_CTRL_WRITE_PWD: 424 DCHECK(rv == OK); 425 rv = DoCtrlWritePWD(); 426 break; 427 case STATE_CTRL_WRITE_TYPE: 428 DCHECK(rv == OK); 429 rv = DoCtrlWriteTYPE(); 430 break; 431 case STATE_CTRL_WRITE_PASV: 432 DCHECK(rv == OK); 433 rv = DoCtrlWritePASV(); 434 break; 435 case STATE_CTRL_WRITE_RETR: 436 DCHECK(rv == OK); 437 rv = DoCtrlWriteRETR(); 438 break; 439 case STATE_CTRL_WRITE_SIZE: 440 DCHECK(rv == OK); 441 rv = DoCtrlWriteSIZE(); 442 break; 443 case STATE_CTRL_WRITE_CWD: 444 DCHECK(rv == OK); 445 rv = DoCtrlWriteCWD(); 446 break; 447 case STATE_CTRL_WRITE_MLSD: 448 DCHECK(rv == 0); 449 rv = DoCtrlWriteMLSD(); 450 break; 451 case STATE_CTRL_WRITE_LIST: 452 DCHECK(rv == OK); 453 rv = DoCtrlWriteLIST(); 454 break; 455 case STATE_CTRL_WRITE_MDTM: 456 DCHECK(rv == OK); 457 rv = DoCtrlWriteMDTM(); 458 break; 459 case STATE_CTRL_WRITE_QUIT: 460 DCHECK(rv == OK); 461 rv = DoCtrlWriteQUIT(); 462 break; 463 464 case STATE_DATA_CONNECT: 465 DCHECK(rv == OK); 466 rv = DoDataConnect(); 467 break; 468 case STATE_DATA_CONNECT_COMPLETE: 469 rv = DoDataConnectComplete(rv); 470 break; 471 case STATE_DATA_READ: 472 DCHECK(rv == OK); 473 rv = DoDataRead(); 474 break; 475 case STATE_DATA_READ_COMPLETE: 476 rv = DoDataReadComplete(rv); 477 break; 478 default: 479 NOTREACHED() << "bad state"; 480 rv = ERR_UNEXPECTED; 481 break; 482 } 483 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 484 return rv; 485 } 486 487 // TODO(ibrar): Yet to see if we need any intialization 488 int FtpNetworkTransaction::DoCtrlInit() { 489 next_state_ = STATE_CTRL_INIT_COMPLETE; 490 return OK; 491 } 492 493 int FtpNetworkTransaction::DoCtrlInitComplete(int result) { 494 next_state_ = STATE_CTRL_RESOLVE_HOST; 495 return OK; 496 } 497 498 int FtpNetworkTransaction::DoCtrlResolveHost() { 499 next_state_ = STATE_CTRL_RESOLVE_HOST_COMPLETE; 500 501 std::string host; 502 int port; 503 504 host = request_->url.host(); 505 port = request_->url.EffectiveIntPort(); 506 507 HostResolver::RequestInfo info(host, port); 508 // No known referrer. 509 return resolver_.Resolve(info, &addresses_, &io_callback_, load_log_); 510 } 511 512 int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { 513 if (result == OK) 514 next_state_ = STATE_CTRL_CONNECT; 515 return result; 516 } 517 518 int FtpNetworkTransaction::DoCtrlConnect() { 519 next_state_ = STATE_CTRL_CONNECT_COMPLETE; 520 ctrl_socket_.reset(socket_factory_->CreateTCPClientSocket(addresses_)); 521 return ctrl_socket_->Connect(&io_callback_, load_log_); 522 } 523 524 int FtpNetworkTransaction::DoCtrlConnectComplete(int result) { 525 if (result == OK) 526 next_state_ = STATE_CTRL_READ; 527 return result; 528 } 529 530 int FtpNetworkTransaction::DoCtrlRead() { 531 next_state_ = STATE_CTRL_READ_COMPLETE; 532 return ctrl_socket_->Read( 533 read_ctrl_buf_, 534 kCtrlBufLen, 535 &io_callback_); 536 } 537 538 int FtpNetworkTransaction::DoCtrlReadComplete(int result) { 539 if (result == 0) { 540 // Some servers (for example Pure-FTPd) apparently close the control 541 // connection when anonymous login is not permitted. For more details 542 // see http://crbug.com/25023. 543 if (command_sent_ == COMMAND_USER && username_ == L"anonymous") 544 response_.needs_auth = true; 545 return Stop(ERR_EMPTY_RESPONSE); 546 } 547 if (result < 0) 548 return Stop(result); 549 550 ctrl_response_buffer_->ConsumeData(read_ctrl_buf_->data(), result); 551 552 if (!ctrl_response_buffer_->ResponseAvailable()) { 553 // Read more data from the control socket. 554 next_state_ = STATE_CTRL_READ; 555 return OK; 556 } 557 558 return ProcessCtrlResponse(); 559 } 560 561 int FtpNetworkTransaction::DoCtrlWrite() { 562 next_state_ = STATE_CTRL_WRITE_COMPLETE; 563 564 return ctrl_socket_->Write(write_buf_, 565 write_buf_->BytesRemaining(), 566 &io_callback_); 567 } 568 569 int FtpNetworkTransaction::DoCtrlWriteComplete(int result) { 570 if (result < 0) 571 return result; 572 573 write_buf_->DidConsume(result); 574 if (write_buf_->BytesRemaining() == 0) { 575 // Clear the write buffer. 576 write_buf_ = NULL; 577 write_command_buf_ = NULL; 578 579 next_state_ = STATE_CTRL_READ; 580 } else { 581 next_state_ = STATE_CTRL_WRITE; 582 } 583 return OK; 584 } 585 586 // FTP Commands and responses 587 588 // USER Command. 589 int FtpNetworkTransaction::DoCtrlWriteUSER() { 590 std::string command = "USER " + WideToUTF8(username_); 591 592 if (!IsValidFTPCommandString(command)) 593 return Stop(ERR_MALFORMED_IDENTITY); 594 595 next_state_ = STATE_CTRL_READ; 596 return SendFtpCommand(command, COMMAND_USER); 597 } 598 599 int FtpNetworkTransaction::ProcessResponseUSER( 600 const FtpCtrlResponse& response) { 601 switch (GetErrorClass(response.status_code)) { 602 case ERROR_CLASS_OK: 603 next_state_ = STATE_CTRL_WRITE_SYST; 604 break; 605 case ERROR_CLASS_INFO_NEEDED: 606 next_state_ = STATE_CTRL_WRITE_PASS; 607 break; 608 case ERROR_CLASS_TRANSIENT_ERROR: 609 if (response.status_code == 421) 610 return Stop(ERR_FAILED); 611 break; 612 case ERROR_CLASS_PERMANENT_ERROR: 613 return Stop(ERR_FAILED); 614 default: 615 NOTREACHED(); 616 return Stop(ERR_UNEXPECTED); 617 } 618 return OK; 619 } 620 621 // PASS command. 622 int FtpNetworkTransaction::DoCtrlWritePASS() { 623 std::string command = "PASS " + WideToUTF8(password_); 624 625 if (!IsValidFTPCommandString(command)) 626 return Stop(ERR_MALFORMED_IDENTITY); 627 628 next_state_ = STATE_CTRL_READ; 629 return SendFtpCommand(command, COMMAND_PASS); 630 } 631 632 int FtpNetworkTransaction::ProcessResponsePASS( 633 const FtpCtrlResponse& response) { 634 switch (GetErrorClass(response.status_code)) { 635 case ERROR_CLASS_OK: 636 next_state_ = STATE_CTRL_WRITE_SYST; 637 break; 638 case ERROR_CLASS_INFO_NEEDED: 639 next_state_ = STATE_CTRL_WRITE_ACCT; 640 break; 641 case ERROR_CLASS_TRANSIENT_ERROR: 642 if (response.status_code == 421) { 643 // TODO(ibrar): Retry here. 644 } 645 return Stop(ERR_FAILED); 646 case ERROR_CLASS_PERMANENT_ERROR: 647 if (response.status_code == 503) { 648 next_state_ = STATE_CTRL_WRITE_USER; 649 } else { 650 response_.needs_auth = true; 651 return Stop(ERR_FAILED); 652 } 653 break; 654 default: 655 NOTREACHED(); 656 return Stop(ERR_UNEXPECTED); 657 } 658 return OK; 659 } 660 661 // SYST command. 662 int FtpNetworkTransaction::DoCtrlWriteSYST() { 663 std::string command = "SYST"; 664 next_state_ = STATE_CTRL_READ; 665 return SendFtpCommand(command, COMMAND_SYST); 666 } 667 668 int FtpNetworkTransaction::ProcessResponseSYST( 669 const FtpCtrlResponse& response) { 670 switch (GetErrorClass(response.status_code)) { 671 case ERROR_CLASS_INITIATED: 672 return Stop(ERR_INVALID_RESPONSE); 673 case ERROR_CLASS_OK: { 674 // All important info should be on the first line. 675 std::string line = response.lines[0]; 676 // The response should be ASCII, which allows us to do case-insensitive 677 // comparisons easily. If it is not ASCII, we leave the system type 678 // as unknown. 679 if (IsStringASCII(line)) { 680 line = StringToLowerASCII(line); 681 // The "magic" strings we test for below have been gathered by an 682 // empirical study. 683 if (line.find("l8") != std::string::npos || 684 line.find("unix") != std::string::npos || 685 line.find("bsd") != std::string::npos) { 686 system_type_ = SYSTEM_TYPE_UNIX; 687 } else if (line.find("win32") != std::string::npos || 688 line.find("windows") != std::string::npos) { 689 system_type_ = SYSTEM_TYPE_WINDOWS; 690 } else if (line.find("os/2") != std::string::npos) { 691 system_type_ = SYSTEM_TYPE_OS2; 692 } else if (line.find("vms") != std::string::npos) { 693 system_type_ = SYSTEM_TYPE_VMS; 694 } 695 } 696 next_state_ = STATE_CTRL_WRITE_PWD; 697 break; 698 } 699 case ERROR_CLASS_INFO_NEEDED: 700 return Stop(ERR_INVALID_RESPONSE); 701 case ERROR_CLASS_TRANSIENT_ERROR: 702 return Stop(ERR_FAILED); 703 case ERROR_CLASS_PERMANENT_ERROR: 704 // Server does not recognize the SYST command so proceed. 705 next_state_ = STATE_CTRL_WRITE_PWD; 706 break; 707 default: 708 NOTREACHED(); 709 return Stop(ERR_UNEXPECTED); 710 } 711 return OK; 712 } 713 714 // PWD command. 715 int FtpNetworkTransaction::DoCtrlWritePWD() { 716 std::string command = "PWD"; 717 next_state_ = STATE_CTRL_READ; 718 return SendFtpCommand(command, COMMAND_PWD); 719 } 720 721 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { 722 switch (GetErrorClass(response.status_code)) { 723 case ERROR_CLASS_INITIATED: 724 return Stop(ERR_INVALID_RESPONSE); 725 case ERROR_CLASS_OK: { 726 // The info we look for should be on the first line. 727 std::string line = response.lines[0]; 728 if (line.empty()) 729 return Stop(ERR_INVALID_RESPONSE); 730 std::string::size_type quote_pos = line.find('"'); 731 if (quote_pos != std::string::npos) { 732 line = line.substr(quote_pos + 1); 733 quote_pos = line.find('"'); 734 if (quote_pos == std::string::npos) 735 return Stop(ERR_INVALID_RESPONSE); 736 line = line.substr(0, quote_pos); 737 } 738 if (system_type_ == SYSTEM_TYPE_VMS) 739 line = FtpUtil::VMSPathToUnix(line); 740 if (line[line.length() - 1] == '/') 741 line.erase(line.length() - 1); 742 current_remote_directory_ = line; 743 next_state_ = STATE_CTRL_WRITE_TYPE; 744 break; 745 } 746 case ERROR_CLASS_INFO_NEEDED: 747 return Stop(ERR_INVALID_RESPONSE); 748 case ERROR_CLASS_TRANSIENT_ERROR: 749 return Stop(ERR_FAILED); 750 case ERROR_CLASS_PERMANENT_ERROR: 751 return Stop(ERR_FAILED); 752 default: 753 NOTREACHED(); 754 return Stop(ERR_UNEXPECTED); 755 } 756 return OK; 757 } 758 759 // TYPE command. 760 int FtpNetworkTransaction::DoCtrlWriteTYPE() { 761 std::string command = "TYPE I"; 762 next_state_ = STATE_CTRL_READ; 763 return SendFtpCommand(command, COMMAND_TYPE); 764 } 765 766 int FtpNetworkTransaction::ProcessResponseTYPE( 767 const FtpCtrlResponse& response) { 768 switch (GetErrorClass(response.status_code)) { 769 case ERROR_CLASS_INITIATED: 770 return Stop(ERR_INVALID_RESPONSE); 771 case ERROR_CLASS_OK: 772 next_state_ = STATE_CTRL_WRITE_PASV; 773 break; 774 case ERROR_CLASS_INFO_NEEDED: 775 return Stop(ERR_INVALID_RESPONSE); 776 case ERROR_CLASS_TRANSIENT_ERROR: 777 return Stop(ERR_FAILED); 778 case ERROR_CLASS_PERMANENT_ERROR: 779 return Stop(ERR_FAILED); 780 default: 781 NOTREACHED(); 782 return Stop(ERR_UNEXPECTED); 783 } 784 return OK; 785 } 786 787 // ACCT command. 788 int FtpNetworkTransaction::DoCtrlWriteACCT() { 789 std::string command = "ACCT noaccount"; 790 next_state_ = STATE_CTRL_READ; 791 return SendFtpCommand(command, COMMAND_ACCT); 792 } 793 794 int FtpNetworkTransaction::ProcessResponseACCT( 795 const FtpCtrlResponse& response) { 796 switch (GetErrorClass(response.status_code)) { 797 case ERROR_CLASS_INITIATED: 798 return Stop(ERR_INVALID_RESPONSE); 799 case ERROR_CLASS_OK: 800 next_state_ = STATE_CTRL_WRITE_SYST; 801 break; 802 case ERROR_CLASS_INFO_NEEDED: 803 return Stop(ERR_INVALID_RESPONSE); 804 case ERROR_CLASS_TRANSIENT_ERROR: 805 return Stop(ERR_FAILED); 806 case ERROR_CLASS_PERMANENT_ERROR: 807 return Stop(ERR_FAILED); 808 default: 809 NOTREACHED(); 810 return Stop(ERR_UNEXPECTED); 811 } 812 return OK; 813 } 814 815 // PASV command 816 int FtpNetworkTransaction::DoCtrlWritePASV() { 817 std::string command = "PASV"; 818 next_state_ = STATE_CTRL_READ; 819 return SendFtpCommand(command, COMMAND_PASV); 820 } 821 822 // There are two way we can receive IP address and port. 823 // TODO(phajdan.jr): Figure out how this should work for IPv6. 824 // (127,0,0,1,23,21) IP address and port encapsulated in (). 825 // 127,0,0,1,23,21 IP address and port without (). 826 int FtpNetworkTransaction::ProcessResponsePASV( 827 const FtpCtrlResponse& response) { 828 switch (GetErrorClass(response.status_code)) { 829 case ERROR_CLASS_INITIATED: 830 return Stop(ERR_INVALID_RESPONSE); 831 case ERROR_CLASS_OK: 832 const char* ptr; 833 int i0, i1, i2, i3, p0, p1; 834 if (response.lines.size() != 1) 835 return Stop(ERR_INVALID_RESPONSE); 836 ptr = response.lines[0].c_str(); // Try with bracket. 837 while (*ptr && *ptr != '(') 838 ++ptr; 839 if (*ptr) { 840 ++ptr; 841 } else { 842 ptr = response.lines[0].c_str(); // Try without bracket. 843 while (*ptr && *ptr != ',') 844 ++ptr; 845 while (*ptr && *ptr != ' ') 846 --ptr; 847 } 848 if (sscanf_s(ptr, "%d,%d,%d,%d,%d,%d", 849 &i0, &i1, &i2, &i3, &p0, &p1) == 6) { 850 // Ignore the IP address supplied in the response. We are always going 851 // to connect back to the same server to prevent FTP PASV port scanning. 852 853 data_connection_port_ = (p0 << 8) + p1; 854 855 if (data_connection_port_ < 1024 || 856 !IsPortAllowedByFtp(data_connection_port_)) 857 return Stop(ERR_UNSAFE_PORT); 858 859 next_state_ = STATE_DATA_CONNECT; 860 } else { 861 return Stop(ERR_INVALID_RESPONSE); 862 } 863 break; 864 case ERROR_CLASS_INFO_NEEDED: 865 return Stop(ERR_INVALID_RESPONSE); 866 case ERROR_CLASS_TRANSIENT_ERROR: 867 return Stop(ERR_FAILED); 868 case ERROR_CLASS_PERMANENT_ERROR: 869 return Stop(ERR_FAILED); 870 default: 871 NOTREACHED(); 872 return Stop(ERR_UNEXPECTED); 873 } 874 return OK; 875 } 876 877 // SIZE command 878 int FtpNetworkTransaction::DoCtrlWriteSIZE() { 879 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); 880 next_state_ = STATE_CTRL_READ; 881 return SendFtpCommand(command, COMMAND_SIZE); 882 } 883 884 int FtpNetworkTransaction::ProcessResponseSIZE( 885 const FtpCtrlResponse& response) { 886 switch (GetErrorClass(response.status_code)) { 887 case ERROR_CLASS_INITIATED: 888 break; 889 case ERROR_CLASS_OK: 890 if (response.lines.size() != 1) 891 return Stop(ERR_INVALID_RESPONSE); 892 if (!StringToInt(response.lines[0], &file_data_len_)) 893 return Stop(ERR_INVALID_RESPONSE); 894 if (file_data_len_ < 0) 895 return Stop(ERR_INVALID_RESPONSE); 896 break; 897 case ERROR_CLASS_INFO_NEEDED: 898 break; 899 case ERROR_CLASS_TRANSIENT_ERROR: 900 break; 901 case ERROR_CLASS_PERMANENT_ERROR: 902 break; 903 default: 904 NOTREACHED(); 905 return Stop(ERR_UNEXPECTED); 906 } 907 next_state_ = STATE_CTRL_WRITE_MDTM; 908 return OK; 909 } 910 911 // RETR command 912 int FtpNetworkTransaction::DoCtrlWriteRETR() { 913 std::string command = "RETR " + GetRequestPathForFtpCommand(false); 914 next_state_ = STATE_CTRL_READ; 915 return SendFtpCommand(command, COMMAND_RETR); 916 } 917 918 int FtpNetworkTransaction::ProcessResponseRETR( 919 const FtpCtrlResponse& response) { 920 switch (GetErrorClass(response.status_code)) { 921 case ERROR_CLASS_INITIATED: 922 // We want the client to start reading the response at this point. 923 // It got here either through Start or RestartWithAuth. We want that 924 // method to complete. Not setting next state here will make DoLoop exit 925 // and in turn make Start/RestartWithAuth complete. 926 break; 927 case ERROR_CLASS_OK: 928 next_state_ = STATE_CTRL_WRITE_QUIT; 929 break; 930 case ERROR_CLASS_INFO_NEEDED: 931 next_state_ = STATE_CTRL_WRITE_PASV; 932 break; 933 case ERROR_CLASS_TRANSIENT_ERROR: 934 if (response.status_code == 421 || response.status_code == 425 || 935 response.status_code == 426) 936 return Stop(ERR_FAILED); 937 return ERR_FAILED; // TODO(ibrar): Retry here. 938 case ERROR_CLASS_PERMANENT_ERROR: 939 // Code 550 means "Failed to open file". Other codes are unrelated, 940 // like "Not logged in" etc. 941 if (response.status_code != 550) 942 return Stop(ERR_FAILED); 943 944 DCHECK(!retr_failed_); // Should not get here twice. 945 retr_failed_ = true; 946 947 // It's possible that RETR failed because the path is a directory. 948 // We're going to try CWD next, but first send a PASV one more time, 949 // because some FTP servers, including FileZilla, require that. 950 // See http://crbug.com/25316. 951 next_state_ = STATE_CTRL_WRITE_PASV; 952 break; 953 default: 954 NOTREACHED(); 955 return Stop(ERR_UNEXPECTED); 956 } 957 return OK; 958 } 959 960 // MDMT command 961 int FtpNetworkTransaction::DoCtrlWriteMDTM() { 962 std::string command = "MDTM " + GetRequestPathForFtpCommand(false); 963 next_state_ = STATE_CTRL_READ; 964 return SendFtpCommand(command, COMMAND_MDTM); 965 } 966 967 int FtpNetworkTransaction::ProcessResponseMDTM( 968 const FtpCtrlResponse& response) { 969 switch (GetErrorClass(response.status_code)) { 970 case ERROR_CLASS_INITIATED: 971 return Stop(ERR_FAILED); 972 case ERROR_CLASS_OK: 973 next_state_ = STATE_CTRL_WRITE_RETR; 974 break; 975 case ERROR_CLASS_INFO_NEEDED: 976 return Stop(ERR_FAILED); 977 case ERROR_CLASS_TRANSIENT_ERROR: 978 return Stop(ERR_FAILED); 979 case ERROR_CLASS_PERMANENT_ERROR: 980 next_state_ = STATE_CTRL_WRITE_RETR; 981 break; 982 default: 983 NOTREACHED(); 984 return Stop(ERR_UNEXPECTED); 985 } 986 return OK; 987 } 988 989 990 // CWD command 991 int FtpNetworkTransaction::DoCtrlWriteCWD() { 992 std::string command = "CWD " + GetRequestPathForFtpCommand(true); 993 next_state_ = STATE_CTRL_READ; 994 return SendFtpCommand(command, COMMAND_CWD); 995 } 996 997 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { 998 switch (GetErrorClass(response.status_code)) { 999 case ERROR_CLASS_INITIATED: 1000 return Stop(ERR_INVALID_RESPONSE); 1001 case ERROR_CLASS_OK: 1002 next_state_ = STATE_CTRL_WRITE_MLSD; 1003 break; 1004 case ERROR_CLASS_INFO_NEEDED: 1005 return Stop(ERR_INVALID_RESPONSE); 1006 case ERROR_CLASS_TRANSIENT_ERROR: 1007 return Stop(ERR_FAILED); 1008 case ERROR_CLASS_PERMANENT_ERROR: 1009 if (retr_failed_ && response.status_code == 550) { 1010 // Both RETR and CWD failed with codes 550. That means that the path 1011 // we're trying to access is not a file, and not a directory. The most 1012 // probable interpretation is that it doesn't exist (with FTP we can't 1013 // be sure). 1014 return Stop(ERR_FILE_NOT_FOUND); 1015 } 1016 return Stop(ERR_FAILED); 1017 default: 1018 NOTREACHED(); 1019 return Stop(ERR_UNEXPECTED); 1020 } 1021 return OK; 1022 } 1023 1024 // MLSD command 1025 int FtpNetworkTransaction::DoCtrlWriteMLSD() { 1026 next_state_ = STATE_CTRL_READ; 1027 return SendFtpCommand("MLSD", COMMAND_MLSD); 1028 } 1029 1030 int FtpNetworkTransaction::ProcessResponseMLSD( 1031 const FtpCtrlResponse& response) { 1032 switch (GetErrorClass(response.status_code)) { 1033 case ERROR_CLASS_INITIATED: 1034 response_.is_directory_listing = true; 1035 next_state_ = STATE_CTRL_READ; 1036 break; 1037 case ERROR_CLASS_OK: 1038 response_.is_directory_listing = true; 1039 next_state_ = STATE_CTRL_WRITE_QUIT; 1040 break; 1041 case ERROR_CLASS_INFO_NEEDED: 1042 return Stop(ERR_INVALID_RESPONSE); 1043 case ERROR_CLASS_TRANSIENT_ERROR: 1044 case ERROR_CLASS_PERMANENT_ERROR: 1045 // Fallback to the LIST command, more widely supported, 1046 // but without a specified output format. 1047 next_state_ = STATE_CTRL_WRITE_LIST; 1048 break; 1049 default: 1050 NOTREACHED(); 1051 return Stop(ERR_UNEXPECTED); 1052 } 1053 return OK; 1054 } 1055 1056 // LIST command 1057 int FtpNetworkTransaction::DoCtrlWriteLIST() { 1058 std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST"); 1059 next_state_ = STATE_CTRL_READ; 1060 return SendFtpCommand(command, COMMAND_LIST); 1061 } 1062 1063 int FtpNetworkTransaction::ProcessResponseLIST( 1064 const FtpCtrlResponse& response) { 1065 switch (GetErrorClass(response.status_code)) { 1066 case ERROR_CLASS_INITIATED: 1067 response_.is_directory_listing = true; 1068 next_state_ = STATE_CTRL_READ; 1069 break; 1070 case ERROR_CLASS_OK: 1071 response_.is_directory_listing = true; 1072 next_state_ = STATE_CTRL_WRITE_QUIT; 1073 break; 1074 case ERROR_CLASS_INFO_NEEDED: 1075 return Stop(ERR_INVALID_RESPONSE); 1076 case ERROR_CLASS_TRANSIENT_ERROR: 1077 return Stop(ERR_FAILED); 1078 case ERROR_CLASS_PERMANENT_ERROR: 1079 return Stop(ERR_FAILED); 1080 default: 1081 NOTREACHED(); 1082 return Stop(ERR_UNEXPECTED); 1083 } 1084 return OK; 1085 } 1086 1087 // QUIT command 1088 int FtpNetworkTransaction::DoCtrlWriteQUIT() { 1089 std::string command = "QUIT"; 1090 next_state_ = STATE_CTRL_READ; 1091 return SendFtpCommand(command, COMMAND_QUIT); 1092 } 1093 1094 int FtpNetworkTransaction::ProcessResponseQUIT( 1095 const FtpCtrlResponse& response) { 1096 ctrl_socket_->Disconnect(); 1097 return last_error_; 1098 } 1099 1100 // Data Connection 1101 1102 int FtpNetworkTransaction::DoDataConnect() { 1103 next_state_ = STATE_DATA_CONNECT_COMPLETE; 1104 AddressList data_addresses; 1105 // TODO(phajdan.jr): Use exactly same IP address as the control socket. 1106 // If the DNS name resolves to several different IPs, and they are different 1107 // physical servers, this will break. However, that configuration is very rare 1108 // in practice. 1109 data_addresses.Copy(addresses_.head()); 1110 data_addresses.SetPort(data_connection_port_); 1111 data_socket_.reset(socket_factory_->CreateTCPClientSocket(data_addresses)); 1112 return data_socket_->Connect(&io_callback_, load_log_); 1113 } 1114 1115 int FtpNetworkTransaction::DoDataConnectComplete(int result) { 1116 RecordDataConnectionError(result); 1117 if (retr_failed_) { 1118 next_state_ = STATE_CTRL_WRITE_CWD; 1119 } else { 1120 next_state_ = STATE_CTRL_WRITE_SIZE; 1121 } 1122 return OK; 1123 } 1124 1125 int FtpNetworkTransaction::DoDataRead() { 1126 DCHECK(read_data_buf_); 1127 DCHECK_GT(read_data_buf_len_, 0); 1128 1129 if (data_socket_ == NULL || !data_socket_->IsConnected()) { 1130 // If we don't destroy the data socket completely, some servers will wait 1131 // for us (http://crbug.com/21127). The half-closed TCP connection needs 1132 // to be closed on our side too. 1133 data_socket_.reset(); 1134 1135 // No more data so send QUIT Command now and wait for response. 1136 return Stop(OK); 1137 } 1138 1139 next_state_ = STATE_DATA_READ_COMPLETE; 1140 read_data_buf_->data()[0] = 0; 1141 return data_socket_->Read(read_data_buf_, read_data_buf_len_, 1142 &io_callback_); 1143 } 1144 1145 int FtpNetworkTransaction::DoDataReadComplete(int result) { 1146 return result; 1147 } 1148 1149 // We're using a histogram as a group of counters, with one bucket for each 1150 // enumeration value. We're only interested in the values of the counters. 1151 // Ignore the shape, average, and standard deviation of the histograms because 1152 // they are meaningless. 1153 // 1154 // We use two histograms. In the first histogram we tally whether the user has 1155 // seen an error of that type during the session. In the second histogram we 1156 // tally the total number of times the users sees each errer. 1157 void FtpNetworkTransaction::RecordDataConnectionError(int result) { 1158 // Gather data for http://crbug.com/3073. See how many users have trouble 1159 // establishing FTP data connection in passive FTP mode. 1160 enum { 1161 // Data connection successful. 1162 NET_ERROR_OK = 0, 1163 1164 // Local firewall blocked the connection. 1165 NET_ERROR_ACCESS_DENIED = 1, 1166 1167 // Connection timed out. 1168 NET_ERROR_TIMED_OUT = 2, 1169 1170 // Connection has been estabilished, but then got broken (either reset 1171 // or aborted). 1172 NET_ERROR_CONNECTION_BROKEN = 3, 1173 1174 // Connection has been refused. 1175 NET_ERROR_CONNECTION_REFUSED = 4, 1176 1177 // No connection to the internet. 1178 NET_ERROR_INTERNET_DISCONNECTED = 5, 1179 1180 // Could not reach the destination address. 1181 NET_ERROR_ADDRESS_UNREACHABLE = 6, 1182 1183 // A programming error in our network stack. 1184 NET_ERROR_UNEXPECTED = 7, 1185 1186 // Other kind of error. 1187 NET_ERROR_OTHER = 20, 1188 1189 NUM_OF_NET_ERROR_TYPES 1190 } type; 1191 switch (result) { 1192 case OK: 1193 type = NET_ERROR_OK; 1194 break; 1195 case ERR_ACCESS_DENIED: 1196 type = NET_ERROR_ACCESS_DENIED; 1197 break; 1198 case ERR_TIMED_OUT: 1199 type = NET_ERROR_TIMED_OUT; 1200 break; 1201 case ERR_CONNECTION_ABORTED: 1202 case ERR_CONNECTION_RESET: 1203 case ERR_CONNECTION_CLOSED: 1204 type = NET_ERROR_CONNECTION_BROKEN; 1205 break; 1206 case ERR_CONNECTION_FAILED: 1207 case ERR_CONNECTION_REFUSED: 1208 type = NET_ERROR_CONNECTION_REFUSED; 1209 break; 1210 case ERR_INTERNET_DISCONNECTED: 1211 type = NET_ERROR_INTERNET_DISCONNECTED; 1212 break; 1213 case ERR_ADDRESS_INVALID: 1214 case ERR_ADDRESS_UNREACHABLE: 1215 type = NET_ERROR_ADDRESS_UNREACHABLE; 1216 break; 1217 case ERR_UNEXPECTED: 1218 type = NET_ERROR_UNEXPECTED; 1219 break; 1220 default: 1221 type = NET_ERROR_OTHER; 1222 break; 1223 }; 1224 static bool had_error_type[NUM_OF_NET_ERROR_TYPES]; 1225 1226 DCHECK(type >= 0 && type < NUM_OF_NET_ERROR_TYPES); 1227 if (!had_error_type[type]) { 1228 had_error_type[type] = true; 1229 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorHappened", 1230 type, NUM_OF_NET_ERROR_TYPES); 1231 } 1232 UMA_HISTOGRAM_ENUMERATION("Net.FtpDataConnectionErrorCount", 1233 type, NUM_OF_NET_ERROR_TYPES); 1234 } 1235 1236 } // namespace net 1237