Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: net/ftp/ftp_network_transaction.cc

Issue 215058: Correctly talk to VMS servers (translate UNIX paths to VMS and vice versa). (Closed)
Patch Set: fixes Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/ftp/ftp_network_transaction.h ('k') | net/ftp/ftp_network_transaction_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/ftp/ftp_network_transaction.h ('k') | net/ftp/ftp_network_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698