OLD | NEW |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this | 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 | 2 // source code is governed by a BSD-style license that can be found in the |
3 // LICENSE file. | 3 // 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/string_util.h" | 8 #include "base/string_util.h" |
9 #include "net/base/connection_type_histograms.h" | 9 #include "net/base/connection_type_histograms.h" |
10 #include "net/base/escape.h" | 10 #include "net/base/escape.h" |
11 #include "net/base/load_log.h" | 11 #include "net/base/load_log.h" |
12 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
13 #include "net/base/net_util.h" | 13 #include "net/base/net_util.h" |
14 #include "net/ftp/ftp_network_session.h" | 14 #include "net/ftp/ftp_network_session.h" |
15 #include "net/ftp/ftp_request_info.h" | 15 #include "net/ftp/ftp_request_info.h" |
| 16 #include "net/ftp/ftp_util.h" |
16 #include "net/socket/client_socket.h" | 17 #include "net/socket/client_socket.h" |
17 #include "net/socket/client_socket_factory.h" | 18 #include "net/socket/client_socket_factory.h" |
18 | 19 |
19 // TODO(ibrar): Try to avoid sscanf. | 20 // TODO(ibrar): Try to avoid sscanf. |
20 #if !defined(COMPILER_MSVC) | 21 #if !defined(COMPILER_MSVC) |
21 #define sscanf_s sscanf | 22 #define sscanf_s sscanf |
22 #endif | 23 #endif |
23 | 24 |
24 const char kCRLF[] = "\r\n"; | 25 const char kCRLF[] = "\r\n"; |
25 | 26 |
(...skipping 27 matching lines...) Expand all Loading... |
53 user_callback_(NULL), | 54 user_callback_(NULL), |
54 session_(session), | 55 session_(session), |
55 request_(NULL), | 56 request_(NULL), |
56 resolver_(session->host_resolver()), | 57 resolver_(session->host_resolver()), |
57 read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), | 58 read_ctrl_buf_(new IOBuffer(kCtrlBufLen)), |
58 ctrl_response_buffer_(new FtpCtrlResponseBuffer()), | 59 ctrl_response_buffer_(new FtpCtrlResponseBuffer()), |
59 read_data_buf_len_(0), | 60 read_data_buf_len_(0), |
60 file_data_len_(0), | 61 file_data_len_(0), |
61 write_command_buf_written_(0), | 62 write_command_buf_written_(0), |
62 last_error_(OK), | 63 last_error_(OK), |
| 64 system_type_(SYSTEM_TYPE_UNKNOWN), |
63 retr_failed_(false), | 65 retr_failed_(false), |
64 data_connection_port_(0), | 66 data_connection_port_(0), |
65 socket_factory_(socket_factory), | 67 socket_factory_(socket_factory), |
66 next_state_(STATE_NONE) { | 68 next_state_(STATE_NONE) { |
67 } | 69 } |
68 | 70 |
69 FtpNetworkTransaction::~FtpNetworkTransaction() { | 71 FtpNetworkTransaction::~FtpNetworkTransaction() { |
70 } | 72 } |
71 | 73 |
72 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, | 74 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info, |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 user_callback_ = NULL; | 318 user_callback_ = NULL; |
317 c->Run(rv); | 319 c->Run(rv); |
318 } | 320 } |
319 | 321 |
320 void FtpNetworkTransaction::OnIOComplete(int result) { | 322 void FtpNetworkTransaction::OnIOComplete(int result) { |
321 int rv = DoLoop(result); | 323 int rv = DoLoop(result); |
322 if (rv != ERR_IO_PENDING) | 324 if (rv != ERR_IO_PENDING) |
323 DoCallback(rv); | 325 DoCallback(rv); |
324 } | 326 } |
325 | 327 |
326 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand() const { | 328 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand( |
327 std::string path = (request_->url.has_path() ? request_->url.path() : "/"); | 329 bool is_directory) const { |
| 330 std::string path(current_remote_directory_); |
| 331 if (request_->url.has_path()) |
| 332 path.append(request_->url.path()); |
| 333 // Make sure that if the path is expected to be a file, it won't end |
| 334 // with a trailing slash. |
| 335 if (!is_directory && path.length() > 1 && path[path.length() - 1] == '/') |
| 336 path.erase(path.length() - 1); |
328 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | | 337 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | |
329 UnescapeRule::URL_SPECIAL_CHARS; | 338 UnescapeRule::URL_SPECIAL_CHARS; |
330 // This may unescape to non-ASCII characters, but we allow that. See the | 339 // This may unescape to non-ASCII characters, but we allow that. See the |
331 // comment for IsValidFTPCommandString. | 340 // comment for IsValidFTPCommandString. |
332 path = UnescapeURLComponent(path, unescape_rules); | 341 path = UnescapeURLComponent(path, unescape_rules); |
| 342 |
| 343 if (system_type_ == SYSTEM_TYPE_VMS) { |
| 344 if (is_directory) |
| 345 path = FtpUtil::UnixDirectoryPathToVMS(path); |
| 346 else |
| 347 path = FtpUtil::UnixFilePathToVMS(path); |
| 348 } |
| 349 |
333 DCHECK(IsValidFTPCommandString(path)); | 350 DCHECK(IsValidFTPCommandString(path)); |
334 return path; | 351 return path; |
335 } | 352 } |
336 | 353 |
337 int FtpNetworkTransaction::DoLoop(int result) { | 354 int FtpNetworkTransaction::DoLoop(int result) { |
338 DCHECK(next_state_ != STATE_NONE); | 355 DCHECK(next_state_ != STATE_NONE); |
339 | 356 |
340 int rv = result; | 357 int rv = result; |
341 do { | 358 do { |
342 State state = next_state_; | 359 State state = next_state_; |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 std::string command = "SYST"; | 644 std::string command = "SYST"; |
628 next_state_ = STATE_CTRL_READ; | 645 next_state_ = STATE_CTRL_READ; |
629 return SendFtpCommand(command, COMMAND_SYST); | 646 return SendFtpCommand(command, COMMAND_SYST); |
630 } | 647 } |
631 | 648 |
632 int FtpNetworkTransaction::ProcessResponseSYST( | 649 int FtpNetworkTransaction::ProcessResponseSYST( |
633 const FtpCtrlResponse& response) { | 650 const FtpCtrlResponse& response) { |
634 switch (GetErrorClass(response.status_code)) { | 651 switch (GetErrorClass(response.status_code)) { |
635 case ERROR_CLASS_INITIATED: | 652 case ERROR_CLASS_INITIATED: |
636 return Stop(ERR_INVALID_RESPONSE); | 653 return Stop(ERR_INVALID_RESPONSE); |
637 case ERROR_CLASS_OK: | 654 case ERROR_CLASS_OK: { |
638 // TODO(ibrar): Process SYST response properly. | 655 // All important info should be on the first line. |
| 656 std::string line = response.lines[0]; |
| 657 // The response should be ASCII, which allows us to do case-insensitive |
| 658 // comparisons easily. If it is not ASCII, we leave the system type |
| 659 // as unknown. |
| 660 if (IsStringASCII(line)) { |
| 661 line = StringToLowerASCII(line); |
| 662 // The "magic" strings we test for below have been gathered by an |
| 663 // empirical study. |
| 664 if (line.find("l8") != std::string::npos || |
| 665 line.find("unix") != std::string::npos || |
| 666 line.find("bsd") != std::string::npos) { |
| 667 system_type_ = SYSTEM_TYPE_UNIX; |
| 668 } else if (line.find("win32") != std::string::npos || |
| 669 line.find("windows") != std::string::npos) { |
| 670 system_type_ = SYSTEM_TYPE_WINDOWS; |
| 671 } else if (line.find("os/2") != std::string::npos) { |
| 672 system_type_ = SYSTEM_TYPE_OS2; |
| 673 } else if (line.find("vms") != std::string::npos) { |
| 674 system_type_ = SYSTEM_TYPE_VMS; |
| 675 } |
| 676 } |
639 next_state_ = STATE_CTRL_WRITE_PWD; | 677 next_state_ = STATE_CTRL_WRITE_PWD; |
640 break; | 678 break; |
| 679 } |
641 case ERROR_CLASS_INFO_NEEDED: | 680 case ERROR_CLASS_INFO_NEEDED: |
642 return Stop(ERR_INVALID_RESPONSE); | 681 return Stop(ERR_INVALID_RESPONSE); |
643 case ERROR_CLASS_TRANSIENT_ERROR: | 682 case ERROR_CLASS_TRANSIENT_ERROR: |
644 return Stop(ERR_FAILED); | 683 return Stop(ERR_FAILED); |
645 case ERROR_CLASS_PERMANENT_ERROR: | 684 case ERROR_CLASS_PERMANENT_ERROR: |
646 // Server does not recognize the SYST command so proceed. | 685 // Server does not recognize the SYST command so proceed. |
647 next_state_ = STATE_CTRL_WRITE_PWD; | 686 next_state_ = STATE_CTRL_WRITE_PWD; |
648 break; | 687 break; |
649 default: | 688 default: |
650 NOTREACHED(); | 689 NOTREACHED(); |
651 return Stop(ERR_UNEXPECTED); | 690 return Stop(ERR_UNEXPECTED); |
652 } | 691 } |
653 return OK; | 692 return OK; |
654 } | 693 } |
655 | 694 |
656 // PWD command. | 695 // PWD command. |
657 int FtpNetworkTransaction::DoCtrlWritePWD() { | 696 int FtpNetworkTransaction::DoCtrlWritePWD() { |
658 std::string command = "PWD"; | 697 std::string command = "PWD"; |
659 next_state_ = STATE_CTRL_READ; | 698 next_state_ = STATE_CTRL_READ; |
660 return SendFtpCommand(command, COMMAND_PWD); | 699 return SendFtpCommand(command, COMMAND_PWD); |
661 } | 700 } |
662 | 701 |
663 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { | 702 int FtpNetworkTransaction::ProcessResponsePWD(const FtpCtrlResponse& response) { |
664 switch (GetErrorClass(response.status_code)) { | 703 switch (GetErrorClass(response.status_code)) { |
665 case ERROR_CLASS_INITIATED: | 704 case ERROR_CLASS_INITIATED: |
666 return Stop(ERR_INVALID_RESPONSE); | 705 return Stop(ERR_INVALID_RESPONSE); |
667 case ERROR_CLASS_OK: | 706 case ERROR_CLASS_OK: { |
| 707 // The info we look for should be on the first line. |
| 708 std::string line = response.lines[0]; |
| 709 if (line.empty()) |
| 710 return Stop(ERR_INVALID_RESPONSE); |
| 711 std::string::size_type quote_pos = line.find('"'); |
| 712 if (quote_pos != std::string::npos) { |
| 713 line = line.substr(quote_pos + 1); |
| 714 quote_pos = line.find('"'); |
| 715 if (quote_pos == std::string::npos) |
| 716 return Stop(ERR_INVALID_RESPONSE); |
| 717 line = line.substr(0, quote_pos); |
| 718 } |
| 719 if (system_type_ == SYSTEM_TYPE_VMS) |
| 720 line = FtpUtil::VMSPathToUnix(line); |
| 721 if (line[line.length() - 1] == '/') |
| 722 line.erase(line.length() - 1); |
| 723 current_remote_directory_ = line; |
668 next_state_ = STATE_CTRL_WRITE_TYPE; | 724 next_state_ = STATE_CTRL_WRITE_TYPE; |
669 break; | 725 break; |
| 726 } |
670 case ERROR_CLASS_INFO_NEEDED: | 727 case ERROR_CLASS_INFO_NEEDED: |
671 return Stop(ERR_INVALID_RESPONSE); | 728 return Stop(ERR_INVALID_RESPONSE); |
672 case ERROR_CLASS_TRANSIENT_ERROR: | 729 case ERROR_CLASS_TRANSIENT_ERROR: |
673 return Stop(ERR_FAILED); | 730 return Stop(ERR_FAILED); |
674 case ERROR_CLASS_PERMANENT_ERROR: | 731 case ERROR_CLASS_PERMANENT_ERROR: |
675 return Stop(ERR_FAILED); | 732 return Stop(ERR_FAILED); |
676 default: | 733 default: |
677 NOTREACHED(); | 734 NOTREACHED(); |
678 return Stop(ERR_UNEXPECTED); | 735 return Stop(ERR_UNEXPECTED); |
679 } | 736 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 return Stop(ERR_FAILED); | 850 return Stop(ERR_FAILED); |
794 default: | 851 default: |
795 NOTREACHED(); | 852 NOTREACHED(); |
796 return Stop(ERR_UNEXPECTED); | 853 return Stop(ERR_UNEXPECTED); |
797 } | 854 } |
798 return OK; | 855 return OK; |
799 } | 856 } |
800 | 857 |
801 // SIZE command | 858 // SIZE command |
802 int FtpNetworkTransaction::DoCtrlWriteSIZE() { | 859 int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
803 std::string command = "SIZE " + GetRequestPathForFtpCommand(); | 860 std::string command = "SIZE " + GetRequestPathForFtpCommand(false); |
804 next_state_ = STATE_CTRL_READ; | 861 next_state_ = STATE_CTRL_READ; |
805 return SendFtpCommand(command, COMMAND_SIZE); | 862 return SendFtpCommand(command, COMMAND_SIZE); |
806 } | 863 } |
807 | 864 |
808 int FtpNetworkTransaction::ProcessResponseSIZE( | 865 int FtpNetworkTransaction::ProcessResponseSIZE( |
809 const FtpCtrlResponse& response) { | 866 const FtpCtrlResponse& response) { |
810 switch (GetErrorClass(response.status_code)) { | 867 switch (GetErrorClass(response.status_code)) { |
811 case ERROR_CLASS_INITIATED: | 868 case ERROR_CLASS_INITIATED: |
812 break; | 869 break; |
813 case ERROR_CLASS_OK: | 870 case ERROR_CLASS_OK: |
(...skipping 13 matching lines...) Expand all Loading... |
827 default: | 884 default: |
828 NOTREACHED(); | 885 NOTREACHED(); |
829 return Stop(ERR_UNEXPECTED); | 886 return Stop(ERR_UNEXPECTED); |
830 } | 887 } |
831 next_state_ = STATE_CTRL_WRITE_MDTM; | 888 next_state_ = STATE_CTRL_WRITE_MDTM; |
832 return OK; | 889 return OK; |
833 } | 890 } |
834 | 891 |
835 // RETR command | 892 // RETR command |
836 int FtpNetworkTransaction::DoCtrlWriteRETR() { | 893 int FtpNetworkTransaction::DoCtrlWriteRETR() { |
837 std::string command = "RETR " + GetRequestPathForFtpCommand(); | 894 std::string command = "RETR " + GetRequestPathForFtpCommand(false); |
838 next_state_ = STATE_CTRL_READ; | 895 next_state_ = STATE_CTRL_READ; |
839 return SendFtpCommand(command, COMMAND_RETR); | 896 return SendFtpCommand(command, COMMAND_RETR); |
840 } | 897 } |
841 | 898 |
842 int FtpNetworkTransaction::ProcessResponseRETR( | 899 int FtpNetworkTransaction::ProcessResponseRETR( |
843 const FtpCtrlResponse& response) { | 900 const FtpCtrlResponse& response) { |
844 switch (GetErrorClass(response.status_code)) { | 901 switch (GetErrorClass(response.status_code)) { |
845 case ERROR_CLASS_INITIATED: | 902 case ERROR_CLASS_INITIATED: |
846 // We want the client to start reading the response at this point. | 903 // We want the client to start reading the response at this point. |
847 // It got here either through Start or RestartWithAuth. We want that | 904 // It got here either through Start or RestartWithAuth. We want that |
(...skipping 26 matching lines...) Expand all Loading... |
874 break; | 931 break; |
875 default: | 932 default: |
876 NOTREACHED(); | 933 NOTREACHED(); |
877 return Stop(ERR_UNEXPECTED); | 934 return Stop(ERR_UNEXPECTED); |
878 } | 935 } |
879 return OK; | 936 return OK; |
880 } | 937 } |
881 | 938 |
882 // MDMT command | 939 // MDMT command |
883 int FtpNetworkTransaction::DoCtrlWriteMDTM() { | 940 int FtpNetworkTransaction::DoCtrlWriteMDTM() { |
884 std::string command = "MDTM " + GetRequestPathForFtpCommand(); | 941 std::string command = "MDTM " + GetRequestPathForFtpCommand(false); |
885 next_state_ = STATE_CTRL_READ; | 942 next_state_ = STATE_CTRL_READ; |
886 return SendFtpCommand(command, COMMAND_MDTM); | 943 return SendFtpCommand(command, COMMAND_MDTM); |
887 } | 944 } |
888 | 945 |
889 int FtpNetworkTransaction::ProcessResponseMDTM( | 946 int FtpNetworkTransaction::ProcessResponseMDTM( |
890 const FtpCtrlResponse& response) { | 947 const FtpCtrlResponse& response) { |
891 switch (GetErrorClass(response.status_code)) { | 948 switch (GetErrorClass(response.status_code)) { |
892 case ERROR_CLASS_INITIATED: | 949 case ERROR_CLASS_INITIATED: |
893 return Stop(ERR_FAILED); | 950 return Stop(ERR_FAILED); |
894 case ERROR_CLASS_OK: | 951 case ERROR_CLASS_OK: |
895 next_state_ = STATE_CTRL_WRITE_RETR; | 952 next_state_ = STATE_CTRL_WRITE_RETR; |
896 break; | 953 break; |
897 case ERROR_CLASS_INFO_NEEDED: | 954 case ERROR_CLASS_INFO_NEEDED: |
898 return Stop(ERR_FAILED); | 955 return Stop(ERR_FAILED); |
899 case ERROR_CLASS_TRANSIENT_ERROR: | 956 case ERROR_CLASS_TRANSIENT_ERROR: |
900 return Stop(ERR_FAILED); | 957 return Stop(ERR_FAILED); |
901 case ERROR_CLASS_PERMANENT_ERROR: | 958 case ERROR_CLASS_PERMANENT_ERROR: |
902 next_state_ = STATE_CTRL_WRITE_RETR; | 959 next_state_ = STATE_CTRL_WRITE_RETR; |
903 break; | 960 break; |
904 default: | 961 default: |
905 NOTREACHED(); | 962 NOTREACHED(); |
906 return Stop(ERR_UNEXPECTED); | 963 return Stop(ERR_UNEXPECTED); |
907 } | 964 } |
908 return OK; | 965 return OK; |
909 } | 966 } |
910 | 967 |
911 | 968 |
912 // CWD command | 969 // CWD command |
913 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 970 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
914 std::string command = "CWD " + GetRequestPathForFtpCommand(); | 971 std::string command = "CWD " + GetRequestPathForFtpCommand(true); |
915 next_state_ = STATE_CTRL_READ; | 972 next_state_ = STATE_CTRL_READ; |
916 return SendFtpCommand(command, COMMAND_CWD); | 973 return SendFtpCommand(command, COMMAND_CWD); |
917 } | 974 } |
918 | 975 |
919 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { | 976 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
920 switch (GetErrorClass(response.status_code)) { | 977 switch (GetErrorClass(response.status_code)) { |
921 case ERROR_CLASS_INITIATED: | 978 case ERROR_CLASS_INITIATED: |
922 return Stop(ERR_INVALID_RESPONSE); | 979 return Stop(ERR_INVALID_RESPONSE); |
923 case ERROR_CLASS_OK: | 980 case ERROR_CLASS_OK: |
924 next_state_ = STATE_CTRL_WRITE_LIST; | 981 next_state_ = STATE_CTRL_WRITE_LIST; |
(...skipping 13 matching lines...) Expand all Loading... |
938 return Stop(ERR_FAILED); | 995 return Stop(ERR_FAILED); |
939 default: | 996 default: |
940 NOTREACHED(); | 997 NOTREACHED(); |
941 return Stop(ERR_UNEXPECTED); | 998 return Stop(ERR_UNEXPECTED); |
942 } | 999 } |
943 return OK; | 1000 return OK; |
944 } | 1001 } |
945 | 1002 |
946 // LIST command | 1003 // LIST command |
947 int FtpNetworkTransaction::DoCtrlWriteLIST() { | 1004 int FtpNetworkTransaction::DoCtrlWriteLIST() { |
948 std::string command = "LIST"; | 1005 std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST"); |
949 next_state_ = STATE_CTRL_READ; | 1006 next_state_ = STATE_CTRL_READ; |
950 return SendFtpCommand(command, COMMAND_LIST); | 1007 return SendFtpCommand(command, COMMAND_LIST); |
951 } | 1008 } |
952 | 1009 |
953 int FtpNetworkTransaction::ProcessResponseLIST( | 1010 int FtpNetworkTransaction::ProcessResponseLIST( |
954 const FtpCtrlResponse& response) { | 1011 const FtpCtrlResponse& response) { |
955 switch (GetErrorClass(response.status_code)) { | 1012 switch (GetErrorClass(response.status_code)) { |
956 case ERROR_CLASS_INITIATED: | 1013 case ERROR_CLASS_INITIATED: |
957 response_.is_directory_listing = true; | 1014 response_.is_directory_listing = true; |
958 break; | 1015 break; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1028 read_data_buf_->data()[0] = 0; | 1085 read_data_buf_->data()[0] = 0; |
1029 return data_socket_->Read(read_data_buf_, read_data_buf_len_, | 1086 return data_socket_->Read(read_data_buf_, read_data_buf_len_, |
1030 &io_callback_); | 1087 &io_callback_); |
1031 } | 1088 } |
1032 | 1089 |
1033 int FtpNetworkTransaction::DoDataReadComplete(int result) { | 1090 int FtpNetworkTransaction::DoDataReadComplete(int result) { |
1034 return result; | 1091 return result; |
1035 } | 1092 } |
1036 | 1093 |
1037 } // namespace net | 1094 } // namespace net |
OLD | NEW |