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 |
736 if (!master_->IsOriginAllowed(header_fields_["origin"])) | 738 // Normalize origin (e.g. leading slash). |
| 739 GURL origin = GURL(header_fields_["origin"]).GetOrigin(); |
| 740 if (!origin.is_valid()) |
| 741 return STATUS_ABORT; |
| 742 // Here we check origin. This check may seem redundant because we verify |
| 743 // passport token later. However the earlier we can reject connection the |
| 744 // better. We receive origin field in websocket header way before receiving |
| 745 // passport string. |
| 746 if (!master_->IsOriginAllowed(origin.spec())) |
737 return STATUS_ABORT; | 747 return STATUS_ABORT; |
738 | 748 |
739 static const std::string kSecKey1 = "sec-websocket-key1"; | 749 static const std::string kSecKey1 = "sec-websocket-key1"; |
740 static const std::string kSecKey2 = "sec-websocket-key2"; | 750 static const std::string kSecKey2 = "sec-websocket-key2"; |
741 uint32 key_number1, key_number2; | 751 uint32 key_number1, key_number2; |
742 if (!FetchDecimalDigits(header_fields_[kSecKey1], | 752 if (!FetchDecimalDigits(header_fields_[kSecKey1], &key_number1) || |
743 &key_number1) || | 753 !FetchDecimalDigits(header_fields_[kSecKey2], &key_number2)) { |
744 !FetchDecimalDigits(header_fields_[kSecKey2], | |
745 &key_number2)) { | |
746 return STATUS_ABORT; | 754 return STATUS_ABORT; |
747 } | 755 } |
748 | 756 |
749 // We limit incoming header size so following numbers shall not be too high. | 757 // We limit incoming header size so following numbers shall not be too high. |
750 int spaces1 = CountSpaces(header_fields_[kSecKey1]); | 758 int spaces1 = CountSpaces(header_fields_[kSecKey1]); |
751 int spaces2 = CountSpaces(header_fields_[kSecKey2]); | 759 int spaces2 = CountSpaces(header_fields_[kSecKey2]); |
752 if (spaces1 == 0 || | 760 if (spaces1 == 0 || |
753 spaces2 == 0 || | 761 spaces2 == 0 || |
754 key_number1 % spaces1 != 0 || | 762 key_number1 % spaces1 != 0 || |
755 key_number2 % spaces2 != 0) { | 763 key_number2 % spaces2 != 0) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 uint8* buf_end = buf + buf_size; | 829 uint8* buf_end = buf + buf_size; |
822 uint8* term_pos = std::find(buf + 1, buf_end, 0xff); | 830 uint8* term_pos = std::find(buf + 1, buf_end, 0xff); |
823 if (term_pos == buf_end) { | 831 if (term_pos == buf_end) { |
824 if (buf_size >= WebSocketProxy::kHeaderLimit) { | 832 if (buf_size >= WebSocketProxy::kHeaderLimit) { |
825 // So big and still worth nothing. | 833 // So big and still worth nothing. |
826 return STATUS_ABORT; | 834 return STATUS_ABORT; |
827 } | 835 } |
828 return STATUS_INCOMPLETE; | 836 return STATUS_INCOMPLETE; |
829 } | 837 } |
830 | 838 |
831 std::string token; | 839 std::string passport; |
832 if (!FetchTokenNamePort(buf + 1, term_pos, &token, &destname_, &destport_)) | 840 if (!FetchPassportNamePort( |
| 841 buf + 1, term_pos, &passport, &destname_, &destport_)) { |
833 return STATUS_ABORT; | 842 return STATUS_ABORT; |
834 // TODO(dilmah): enable this once webSocketProxyPrivate.getToken is wired. | 843 } |
835 #if 0 | |
836 std::map<std::string, std::string> map; | 844 std::map<std::string, std::string> map; |
837 map["hostname"] = destname_; | 845 map["hostname"] = destname_; |
838 map["port"] = base::IntToString(destport_); | 846 map["port"] = base::IntToString(destport_); |
839 map["extension_id"] = FetchExtensionIdFromOrigin(header_fields_["origin"]); | 847 map["extension_id"] = FetchExtensionIdFromOrigin(header_fields_["origin"]); |
840 if (!browser::InternalAuthVerification::VerifyToken( | 848 if (!browser::InternalAuthVerification::VerifyPassport( |
841 "web_socket_proxy", token, map)) { | 849 passport, "web_socket_proxy", map)) { |
842 return STATUS_ABORT; | 850 return STATUS_ABORT; |
843 } | 851 } |
844 #endif | |
845 | 852 |
846 evbuffer_drain(evb, term_pos - buf + 1); | 853 evbuffer_drain(evb, term_pos - buf + 1); |
847 return STATUS_OK; | 854 return STATUS_OK; |
848 } | 855 } |
849 | 856 |
850 Conn::Status Conn::ConsumeFrameHeader(struct evbuffer* evb) { | 857 Conn::Status Conn::ConsumeFrameHeader(struct evbuffer* evb) { |
851 uint8* buf = EVBUFFER_DATA(evb); | 858 uint8* buf = EVBUFFER_DATA(evb); |
852 size_t buf_size = EVBUFFER_LENGTH(evb); | 859 size_t buf_size = EVBUFFER_LENGTH(evb); |
853 | 860 |
854 if (buf_size < 1) | 861 if (buf_size < 1) |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1281 void WebSocketProxy::Run() { | 1288 void WebSocketProxy::Run() { |
1282 static_cast<Serv*>(impl_)->Run(); | 1289 static_cast<Serv*>(impl_)->Run(); |
1283 } | 1290 } |
1284 | 1291 |
1285 void WebSocketProxy::Shutdown() { | 1292 void WebSocketProxy::Shutdown() { |
1286 static_cast<Serv*>(impl_)->Shutdown(); | 1293 static_cast<Serv*>(impl_)->Shutdown(); |
1287 } | 1294 } |
1288 | 1295 |
1289 } // namespace chromeos | 1296 } // namespace chromeos |
1290 | 1297 |
OLD | NEW |