Chromium Code Reviews| 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/load_log.h" | 11 #include "net/base/load_log.h" |
| 11 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
| 12 #include "net/base/net_util.h" | 13 #include "net/base/net_util.h" |
| 13 #include "net/ftp/ftp_network_session.h" | 14 #include "net/ftp/ftp_network_session.h" |
| 14 #include "net/ftp/ftp_request_info.h" | 15 #include "net/ftp/ftp_request_info.h" |
| 15 #include "net/socket/client_socket.h" | 16 #include "net/socket/client_socket.h" |
| 16 #include "net/socket/client_socket_factory.h" | 17 #include "net/socket/client_socket_factory.h" |
| 17 | 18 |
| 18 // TODO(ibrar): Try to avoid sscanf. | 19 // TODO(ibrar): Try to avoid sscanf. |
| 19 #if !defined(COMPILER_MSVC) | 20 #if !defined(COMPILER_MSVC) |
| 20 #define sscanf_s sscanf | 21 #define sscanf_s sscanf |
| 21 #endif | 22 #endif |
| 22 | 23 |
| 23 const char kCRLF[] = "\r\n"; | 24 const char kCRLF[] = "\r\n"; |
| 24 | 25 |
| 25 const int kCtrlBufLen = 1024; | 26 const int kCtrlBufLen = 1024; |
| 26 | 27 |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 29 // Returns true if |input| can be safely used as a part of FTP command. | 30 // Returns true if |input| can be safely used as a part of FTP command. |
| 30 bool IsValidFTPCommandString(const std::string& input) { | 31 bool IsValidFTPCommandString(const std::string& input) { |
| 31 // RFC 959 only allows ASCII strings. | |
|
eroman
2009/09/18 22:51:23
Please add a comment in IsValidFTPComment() that w
| |
| 32 if (!IsStringASCII(input)) | |
| 33 return false; | |
| 34 | |
| 35 // Protect agains newline injection attack. | 32 // Protect agains newline injection attack. |
| 36 if (input.find_first_of("\r\n") != std::string::npos) | 33 if (input.find_first_of("\r\n") != std::string::npos) |
| 37 return false; | 34 return false; |
| 38 | 35 |
| 39 return true; | 36 return true; |
| 40 } | 37 } |
| 41 | 38 |
| 42 } // namespace | 39 } // namespace |
| 43 | 40 |
| 44 namespace net { | 41 namespace net { |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 315 user_callback_ = NULL; | 312 user_callback_ = NULL; |
| 316 c->Run(rv); | 313 c->Run(rv); |
| 317 } | 314 } |
| 318 | 315 |
| 319 void FtpNetworkTransaction::OnIOComplete(int result) { | 316 void FtpNetworkTransaction::OnIOComplete(int result) { |
| 320 int rv = DoLoop(result); | 317 int rv = DoLoop(result); |
| 321 if (rv != ERR_IO_PENDING) | 318 if (rv != ERR_IO_PENDING) |
| 322 DoCallback(rv); | 319 DoCallback(rv); |
| 323 } | 320 } |
| 324 | 321 |
| 322 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand() const { | |
| 323 std::string path = (request_->url.has_path() ? request_->url.path() : "/"); | |
| 324 UnescapeRule::Type unescape_rules = UnescapeRule::SPACES | | |
| 325 UnescapeRule::URL_SPECIAL_CHARS; | |
| 326 path = UnescapeURLComponent(path, unescape_rules); | |
|
eroman
2009/09/18 22:51:23
Please add a comment that escaping to non-ASCII is
| |
| 327 DCHECK(IsValidFTPCommandString(path)); | |
| 328 return path; | |
| 329 } | |
| 330 | |
| 325 int FtpNetworkTransaction::DoLoop(int result) { | 331 int FtpNetworkTransaction::DoLoop(int result) { |
| 326 DCHECK(next_state_ != STATE_NONE); | 332 DCHECK(next_state_ != STATE_NONE); |
| 327 | 333 |
| 328 int rv = result; | 334 int rv = result; |
| 329 do { | 335 do { |
| 330 State state = next_state_; | 336 State state = next_state_; |
| 331 next_state_ = STATE_NONE; | 337 next_state_ = STATE_NONE; |
| 332 switch (state) { | 338 switch (state) { |
| 333 case STATE_CTRL_INIT: | 339 case STATE_CTRL_INIT: |
| 334 DCHECK(rv == OK); | 340 DCHECK(rv == OK); |
| (...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 return Stop(ERR_FAILED); | 787 return Stop(ERR_FAILED); |
| 782 default: | 788 default: |
| 783 NOTREACHED(); | 789 NOTREACHED(); |
| 784 return Stop(ERR_UNEXPECTED); | 790 return Stop(ERR_UNEXPECTED); |
| 785 } | 791 } |
| 786 return OK; | 792 return OK; |
| 787 } | 793 } |
| 788 | 794 |
| 789 // SIZE command | 795 // SIZE command |
| 790 int FtpNetworkTransaction::DoCtrlWriteSIZE() { | 796 int FtpNetworkTransaction::DoCtrlWriteSIZE() { |
| 791 std::string command = "SIZE"; | 797 std::string command = "SIZE " + GetRequestPathForFtpCommand(); |
| 792 if (request_->url.has_path()) { | |
| 793 command.append(" "); | |
| 794 command.append(request_->url.path()); | |
| 795 } | |
| 796 next_state_ = STATE_CTRL_READ; | 798 next_state_ = STATE_CTRL_READ; |
| 797 return SendFtpCommand(command, COMMAND_SIZE); | 799 return SendFtpCommand(command, COMMAND_SIZE); |
| 798 } | 800 } |
| 799 | 801 |
| 800 int FtpNetworkTransaction::ProcessResponseSIZE( | 802 int FtpNetworkTransaction::ProcessResponseSIZE( |
| 801 const FtpCtrlResponse& response) { | 803 const FtpCtrlResponse& response) { |
| 802 switch (GetErrorClass(response.status_code)) { | 804 switch (GetErrorClass(response.status_code)) { |
| 803 case ERROR_CLASS_INITIATED: | 805 case ERROR_CLASS_INITIATED: |
| 804 break; | 806 break; |
| 805 case ERROR_CLASS_OK: | 807 case ERROR_CLASS_OK: |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 819 default: | 821 default: |
| 820 NOTREACHED(); | 822 NOTREACHED(); |
| 821 return Stop(ERR_UNEXPECTED); | 823 return Stop(ERR_UNEXPECTED); |
| 822 } | 824 } |
| 823 next_state_ = STATE_CTRL_WRITE_MDTM; | 825 next_state_ = STATE_CTRL_WRITE_MDTM; |
| 824 return OK; | 826 return OK; |
| 825 } | 827 } |
| 826 | 828 |
| 827 // RETR command | 829 // RETR command |
| 828 int FtpNetworkTransaction::DoCtrlWriteRETR() { | 830 int FtpNetworkTransaction::DoCtrlWriteRETR() { |
| 829 std::string command = "RETR"; | 831 std::string command = "RETR " + GetRequestPathForFtpCommand(); |
| 830 if (request_->url.has_path()) { | |
| 831 command.append(" "); | |
| 832 command.append(request_->url.path()); | |
| 833 } else { | |
| 834 command.append(" /"); | |
| 835 } | |
| 836 next_state_ = STATE_CTRL_READ; | 832 next_state_ = STATE_CTRL_READ; |
| 837 return SendFtpCommand(command, COMMAND_RETR); | 833 return SendFtpCommand(command, COMMAND_RETR); |
| 838 } | 834 } |
| 839 | 835 |
| 840 int FtpNetworkTransaction::ProcessResponseRETR( | 836 int FtpNetworkTransaction::ProcessResponseRETR( |
| 841 const FtpCtrlResponse& response) { | 837 const FtpCtrlResponse& response) { |
| 842 switch (GetErrorClass(response.status_code)) { | 838 switch (GetErrorClass(response.status_code)) { |
| 843 case ERROR_CLASS_INITIATED: | 839 case ERROR_CLASS_INITIATED: |
| 844 // We want the client to start reading the response at this point. | 840 // We want the client to start reading the response at this point. |
| 845 // It got here either through Start or RestartWithAuth. We want that | 841 // It got here either through Start or RestartWithAuth. We want that |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 872 break; | 868 break; |
| 873 default: | 869 default: |
| 874 NOTREACHED(); | 870 NOTREACHED(); |
| 875 return Stop(ERR_UNEXPECTED); | 871 return Stop(ERR_UNEXPECTED); |
| 876 } | 872 } |
| 877 return OK; | 873 return OK; |
| 878 } | 874 } |
| 879 | 875 |
| 880 // MDMT command | 876 // MDMT command |
| 881 int FtpNetworkTransaction::DoCtrlWriteMDTM() { | 877 int FtpNetworkTransaction::DoCtrlWriteMDTM() { |
| 882 std::string command = "MDTM"; | 878 std::string command = "MDTM " + GetRequestPathForFtpCommand(); |
| 883 if (request_->url.has_path()) { | |
| 884 command.append(" "); | |
| 885 command.append(request_->url.path()); | |
| 886 } else { | |
| 887 command.append(" /"); | |
| 888 } | |
| 889 next_state_ = STATE_CTRL_READ; | 879 next_state_ = STATE_CTRL_READ; |
| 890 return SendFtpCommand(command, COMMAND_MDTM); | 880 return SendFtpCommand(command, COMMAND_MDTM); |
| 891 } | 881 } |
| 892 | 882 |
| 893 int FtpNetworkTransaction::ProcessResponseMDTM( | 883 int FtpNetworkTransaction::ProcessResponseMDTM( |
| 894 const FtpCtrlResponse& response) { | 884 const FtpCtrlResponse& response) { |
| 895 switch (GetErrorClass(response.status_code)) { | 885 switch (GetErrorClass(response.status_code)) { |
| 896 case ERROR_CLASS_INITIATED: | 886 case ERROR_CLASS_INITIATED: |
| 897 return Stop(ERR_FAILED); | 887 return Stop(ERR_FAILED); |
| 898 case ERROR_CLASS_OK: | 888 case ERROR_CLASS_OK: |
| 899 next_state_ = STATE_CTRL_WRITE_RETR; | 889 next_state_ = STATE_CTRL_WRITE_RETR; |
| 900 break; | 890 break; |
| 901 case ERROR_CLASS_INFO_NEEDED: | 891 case ERROR_CLASS_INFO_NEEDED: |
| 902 return Stop(ERR_FAILED); | 892 return Stop(ERR_FAILED); |
| 903 case ERROR_CLASS_TRANSIENT_ERROR: | 893 case ERROR_CLASS_TRANSIENT_ERROR: |
| 904 return Stop(ERR_FAILED); | 894 return Stop(ERR_FAILED); |
| 905 case ERROR_CLASS_PERMANENT_ERROR: | 895 case ERROR_CLASS_PERMANENT_ERROR: |
| 906 next_state_ = STATE_CTRL_WRITE_RETR; | 896 next_state_ = STATE_CTRL_WRITE_RETR; |
| 907 break; | 897 break; |
| 908 default: | 898 default: |
| 909 NOTREACHED(); | 899 NOTREACHED(); |
| 910 return Stop(ERR_UNEXPECTED); | 900 return Stop(ERR_UNEXPECTED); |
| 911 } | 901 } |
| 912 return OK; | 902 return OK; |
| 913 } | 903 } |
| 914 | 904 |
| 915 | 905 |
| 916 // CWD command | 906 // CWD command |
| 917 int FtpNetworkTransaction::DoCtrlWriteCWD() { | 907 int FtpNetworkTransaction::DoCtrlWriteCWD() { |
| 918 std::string command = "CWD"; | 908 std::string command = "CWD " + GetRequestPathForFtpCommand(); |
| 919 if (request_->url.has_path()) { | |
| 920 command.append(" "); | |
| 921 command.append(request_->url.path()); | |
| 922 } else { | |
| 923 command.append(" /"); | |
| 924 } | |
| 925 next_state_ = STATE_CTRL_READ; | 909 next_state_ = STATE_CTRL_READ; |
| 926 return SendFtpCommand(command, COMMAND_CWD); | 910 return SendFtpCommand(command, COMMAND_CWD); |
| 927 } | 911 } |
| 928 | 912 |
| 929 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { | 913 int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) { |
| 930 switch (GetErrorClass(response.status_code)) { | 914 switch (GetErrorClass(response.status_code)) { |
| 931 case ERROR_CLASS_INITIATED: | 915 case ERROR_CLASS_INITIATED: |
| 932 return Stop(ERR_INVALID_RESPONSE); | 916 return Stop(ERR_INVALID_RESPONSE); |
| 933 case ERROR_CLASS_OK: | 917 case ERROR_CLASS_OK: |
| 934 next_state_ = STATE_CTRL_WRITE_LIST; | 918 next_state_ = STATE_CTRL_WRITE_LIST; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1038 read_data_buf_->data()[0] = 0; | 1022 read_data_buf_->data()[0] = 0; |
| 1039 return data_socket_->Read(read_data_buf_, read_data_buf_len_, | 1023 return data_socket_->Read(read_data_buf_, read_data_buf_len_, |
| 1040 &io_callback_); | 1024 &io_callback_); |
| 1041 } | 1025 } |
| 1042 | 1026 |
| 1043 int FtpNetworkTransaction::DoDataReadComplete(int result) { | 1027 int FtpNetworkTransaction::DoDataReadComplete(int result) { |
| 1044 return result; | 1028 return result; |
| 1045 } | 1029 } |
| 1046 | 1030 |
| 1047 } // namespace net | 1031 } // namespace net |
| OLD | NEW |