| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "web_socket_proxy.h" | 5 #include "web_socket_proxy.h" |
| 6 | 6 |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include <sys/types.h> | 23 #include <sys/types.h> |
| 24 #include <sys/wait.h> | 24 #include <sys/wait.h> |
| 25 | 25 |
| 26 #include "base/base64.h" | 26 #include "base/base64.h" |
| 27 #include "base/basictypes.h" | 27 #include "base/basictypes.h" |
| 28 #include "base/logging.h" | 28 #include "base/logging.h" |
| 29 #include "base/md5.h" | 29 #include "base/md5.h" |
| 30 #include "base/memory/scoped_ptr.h" | 30 #include "base/memory/scoped_ptr.h" |
| 31 #include "base/string_number_conversions.h" | 31 #include "base/string_number_conversions.h" |
| 32 #include "base/string_util.h" | 32 #include "base/string_util.h" |
| 33 #include "chrome/browser/internal_auth.h" |
| 33 #include "content/browser/browser_thread.h" | 34 #include "content/browser/browser_thread.h" |
| 34 #include "content/common/notification_service.h" | 35 #include "content/common/notification_service.h" |
| 35 #include "content/common/notification_type.h" | 36 #include "content/common/notification_type.h" |
| 36 // TODO(dilmah): enable this once webSocketProxyPrivate.getToken is wired. | 37 #include "content/common/url_constants.h" |
| 37 #if 0 | 38 #include "googleurl/src/gurl.h" |
| 38 #include "chrome/browser/internal_auth.h" | |
| 39 #endif | |
| 40 #include "third_party/libevent/evdns.h" | 39 #include "third_party/libevent/evdns.h" |
| 41 #include "third_party/libevent/event.h" | 40 #include "third_party/libevent/event.h" |
| 42 | 41 |
| 43 namespace chromeos { | 42 namespace chromeos { |
| 44 | 43 |
| 45 namespace { | 44 namespace { |
| 46 | 45 |
| 47 const uint8 kCRLF[] = "\r\n"; | 46 const uint8 kCRLF[] = "\r\n"; |
| 48 const uint8 kCRLFCRLF[] = "\r\n\r\n"; | 47 const uint8 kCRLFCRLF[] = "\r\n\r\n"; |
| 49 | 48 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 *result *= 10; | 97 *result *= 10; |
| 99 int digit = s[i] - '0'; | 98 int digit = s[i] - '0'; |
| 100 if (*result > std::numeric_limits<uint32>::max() - digit) | 99 if (*result > std::numeric_limits<uint32>::max() - digit) |
| 101 return false; | 100 return false; |
| 102 *result += digit; | 101 *result += digit; |
| 103 } | 102 } |
| 104 } | 103 } |
| 105 return got_something; | 104 return got_something; |
| 106 } | 105 } |
| 107 | 106 |
| 108 // Parses "token:hostname:port:" string. Returns true on success. | 107 // Parses "passport:hostname:port:" string. Returns true on success. |
| 109 bool FetchTokenNamePort( | 108 bool FetchPassportNamePort( |
| 110 uint8* begin, uint8* end, | 109 uint8* begin, uint8* end, |
| 111 std::string* token, std::string* name, uint32* port) { | 110 std::string* passport, std::string* name, uint32* port) { |
| 112 std::string input(begin, end); | 111 std::string input(begin, end); |
| 113 if (input[input.size() - 1] != ':') | 112 if (input[input.size() - 1] != ':') |
| 114 return false; | 113 return false; |
| 115 input.resize(input.size() - 1); | 114 input.resize(input.size() - 1); |
| 116 | 115 |
| 117 size_t pos = input.find_last_of(':'); | 116 size_t pos = input.find_last_of(':'); |
| 118 if (pos == std::string::npos) | 117 if (pos == std::string::npos) |
| 119 return false; | 118 return false; |
| 120 std::string port_str(input, pos + 1); | 119 std::string port_str(input, pos + 1); |
| 121 if (port_str.empty()) | 120 if (port_str.empty()) |
| 122 return false; | 121 return false; |
| 123 const char kAsciiDigits[] = "0123456789"; | 122 const char kAsciiDigits[] = "0123456789"; |
| 124 COMPILE_ASSERT(sizeof(kAsciiDigits) == 10 + 1, mess_with_digits); | 123 COMPILE_ASSERT(sizeof(kAsciiDigits) == 10 + 1, mess_with_digits); |
| 125 if (port_str.find_first_not_of(kAsciiDigits) != std::string::npos) | 124 if (port_str.find_first_not_of(kAsciiDigits) != std::string::npos) |
| 126 return false; | 125 return false; |
| 127 if (!FetchDecimalDigits(port_str, port) || | 126 if (!FetchDecimalDigits(port_str, port) || |
| 128 *port <= 0 || | 127 *port <= 0 || |
| 129 *port >= (1 << 16)) { | 128 *port >= (1 << 16)) { |
| 130 return false; | 129 return false; |
| 131 } | 130 } |
| 132 input.resize(pos); | 131 input.resize(pos); |
| 133 | 132 |
| 134 pos = input.find_first_of(':'); | 133 pos = input.find_first_of(':'); |
| 135 if (pos == std::string::npos) | 134 if (pos == std::string::npos) |
| 136 return false; | 135 return false; |
| 137 token->assign(input, 0, pos); | 136 passport->assign(input, 0, pos); |
| 138 name->assign(input, pos + 1, std::string::npos); | 137 name->assign(input, pos + 1, std::string::npos); |
| 139 return !name->empty(); | 138 return !name->empty(); |
| 140 } | 139 } |
| 141 | 140 |
| 142 std::string FetchExtensionIdFromOrigin(const std::string origin) { | 141 std::string FetchExtensionIdFromOrigin(const std::string &origin) { |
| 143 // Origin of extension looks like "chrome-extension://EXTENSION_ID". | 142 GURL url(origin); |
| 144 return origin.substr(origin.find_last_of('/')); | 143 if (url.SchemeIs(chrome::kExtensionScheme)) |
| 144 return url.host(); |
| 145 else |
| 146 return std::string(); |
| 145 } | 147 } |
| 146 | 148 |
| 147 inline size_t strlen(const uint8* s) { | 149 inline size_t strlen(const uint8* s) { |
| 148 return ::strlen(reinterpret_cast<const char*>(s)); | 150 return ::strlen(reinterpret_cast<const char*>(s)); |
| 149 } | 151 } |
| 150 | 152 |
| 151 void SendNotification() { | 153 void SendNotification() { |
| 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 153 NotificationService::current()->Notify( | 155 NotificationService::current()->Notify( |
| 154 NotificationType::WEB_SOCKET_PROXY_STARTED, | 156 NotificationType::WEB_SOCKET_PROXY_STARTED, |
| (...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 if (!key.empty()) | 728 if (!key.empty()) |
| 727 header_fields_[key] = FetchLowerCasedASCIISnippet(npos, pos); | 729 header_fields_[key] = FetchLowerCasedASCIISnippet(npos, pos); |
| 728 } | 730 } |
| 729 | 731 |
| 730 // Values of Upgrade and Connection fields are hardcoded in the protocol. | 732 // Values of Upgrade and Connection fields are hardcoded in the protocol. |
| 731 if (header_fields_["upgrade"] != "websocket" || | 733 if (header_fields_["upgrade"] != "websocket" || |
| 732 header_fields_["connection"] != "upgrade") { | 734 header_fields_["connection"] != "upgrade") { |
| 733 return STATUS_ABORT; | 735 return STATUS_ABORT; |
| 734 } | 736 } |
| 735 | 737 |
| 738 // Here we check origin. This check may seem redundant because we verify |
| 739 // passport token later. However the earlier we can reject connection the |
| 740 // better. We receive origin field in websocket header way before receiving |
| 741 // passport string. |
| 736 if (!master_->IsOriginAllowed(header_fields_["origin"])) | 742 if (!master_->IsOriginAllowed(header_fields_["origin"])) |
| 737 return STATUS_ABORT; | 743 return STATUS_ABORT; |
| 738 | 744 |
| 739 static const std::string kSecKey1 = "sec-websocket-key1"; | 745 static const std::string kSecKey1 = "sec-websocket-key1"; |
| 740 static const std::string kSecKey2 = "sec-websocket-key2"; | 746 static const std::string kSecKey2 = "sec-websocket-key2"; |
| 741 uint32 key_number1, key_number2; | 747 uint32 key_number1, key_number2; |
| 742 if (!FetchDecimalDigits(header_fields_[kSecKey1], | 748 if (!FetchDecimalDigits(header_fields_[kSecKey1], &key_number1) || |
| 743 &key_number1) || | 749 !FetchDecimalDigits(header_fields_[kSecKey2], &key_number2)) { |
| 744 !FetchDecimalDigits(header_fields_[kSecKey2], | |
| 745 &key_number2)) { | |
| 746 return STATUS_ABORT; | 750 return STATUS_ABORT; |
| 747 } | 751 } |
| 748 | 752 |
| 749 // We limit incoming header size so following numbers shall not be too high. | 753 // We limit incoming header size so following numbers shall not be too high. |
| 750 int spaces1 = CountSpaces(header_fields_[kSecKey1]); | 754 int spaces1 = CountSpaces(header_fields_[kSecKey1]); |
| 751 int spaces2 = CountSpaces(header_fields_[kSecKey2]); | 755 int spaces2 = CountSpaces(header_fields_[kSecKey2]); |
| 752 if (spaces1 == 0 || | 756 if (spaces1 == 0 || |
| 753 spaces2 == 0 || | 757 spaces2 == 0 || |
| 754 key_number1 % spaces1 != 0 || | 758 key_number1 % spaces1 != 0 || |
| 755 key_number2 % spaces2 != 0) { | 759 key_number2 % spaces2 != 0) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 uint8* buf_end = buf + buf_size; | 825 uint8* buf_end = buf + buf_size; |
| 822 uint8* term_pos = std::find(buf + 1, buf_end, 0xff); | 826 uint8* term_pos = std::find(buf + 1, buf_end, 0xff); |
| 823 if (term_pos == buf_end) { | 827 if (term_pos == buf_end) { |
| 824 if (buf_size >= WebSocketProxy::kHeaderLimit) { | 828 if (buf_size >= WebSocketProxy::kHeaderLimit) { |
| 825 // So big and still worth nothing. | 829 // So big and still worth nothing. |
| 826 return STATUS_ABORT; | 830 return STATUS_ABORT; |
| 827 } | 831 } |
| 828 return STATUS_INCOMPLETE; | 832 return STATUS_INCOMPLETE; |
| 829 } | 833 } |
| 830 | 834 |
| 831 std::string token; | 835 std::string passport; |
| 832 if (!FetchTokenNamePort(buf + 1, term_pos, &token, &destname_, &destport_)) | 836 if (!FetchPassportNamePort( |
| 837 buf + 1, term_pos, &passport, &destname_, &destport_)) { |
| 833 return STATUS_ABORT; | 838 return STATUS_ABORT; |
| 834 // TODO(dilmah): enable this once webSocketProxyPrivate.getToken is wired. | 839 } |
| 835 #if 0 | |
| 836 std::map<std::string, std::string> map; | 840 std::map<std::string, std::string> map; |
| 837 map["hostname"] = destname_; | 841 map["hostname"] = destname_; |
| 838 map["port"] = base::IntToString(destport_); | 842 map["port"] = base::IntToString(destport_); |
| 839 map["extension_id"] = FetchExtensionIdFromOrigin(header_fields_["origin"]); | 843 map["extension_id"] = FetchExtensionIdFromOrigin(header_fields_["origin"]); |
| 840 if (!browser::InternalAuthVerification::VerifyToken( | 844 if (!browser::InternalAuthVerification::VerifyPassport( |
| 841 "web_socket_proxy", token, map)) { | 845 passport, "web_socket_proxy", map)) { |
| 842 return STATUS_ABORT; | 846 return STATUS_ABORT; |
| 843 } | 847 } |
| 844 #endif | |
| 845 | 848 |
| 846 evbuffer_drain(evb, term_pos - buf + 1); | 849 evbuffer_drain(evb, term_pos - buf + 1); |
| 847 return STATUS_OK; | 850 return STATUS_OK; |
| 848 } | 851 } |
| 849 | 852 |
| 850 Conn::Status Conn::ConsumeFrameHeader(struct evbuffer* evb) { | 853 Conn::Status Conn::ConsumeFrameHeader(struct evbuffer* evb) { |
| 851 uint8* buf = EVBUFFER_DATA(evb); | 854 uint8* buf = EVBUFFER_DATA(evb); |
| 852 size_t buf_size = EVBUFFER_LENGTH(evb); | 855 size_t buf_size = EVBUFFER_LENGTH(evb); |
| 853 | 856 |
| 854 if (buf_size < 1) | 857 if (buf_size < 1) |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1281 void WebSocketProxy::Run() { | 1284 void WebSocketProxy::Run() { |
| 1282 static_cast<Serv*>(impl_)->Run(); | 1285 static_cast<Serv*>(impl_)->Run(); |
| 1283 } | 1286 } |
| 1284 | 1287 |
| 1285 void WebSocketProxy::Shutdown() { | 1288 void WebSocketProxy::Shutdown() { |
| 1286 static_cast<Serv*>(impl_)->Shutdown(); | 1289 static_cast<Serv*>(impl_)->Shutdown(); |
| 1287 } | 1290 } |
| 1288 | 1291 |
| 1289 } // namespace chromeos | 1292 } // namespace chromeos |
| 1290 | 1293 |
| OLD | NEW |