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

Side by Side Diff: chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm

Issue 2132723003: [Mac] Make the local_discovery client more resilient to invalid UTF-8. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: '' Created 4 years, 5 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 #import <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 #include <stdint.h> 6 #include <stdint.h>
7 7
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/callback.h"
9 #include "base/mac/scoped_nsobject.h" 10 #include "base/mac/scoped_nsobject.h"
10 #include "base/macros.h" 11 #include "base/macros.h"
11 #include "base/run_loop.h" 12 #include "base/run_loop.h"
12 #include "chrome/browser/local_discovery/service_discovery_client.h" 13 #include "chrome/browser/local_discovery/service_discovery_client.h"
13 #include "chrome/browser/local_discovery/service_discovery_client_mac.h" 14 #include "chrome/browser/local_discovery/service_discovery_client_mac.h"
14 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 15 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
15 #include "content/public/test/test_browser_thread_bundle.h" 16 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "net/base/ip_endpoint.h" 17 #include "net/base/ip_endpoint.h"
17 #include "net/base/sockaddr_storage.h" 18 #include "net/base/sockaddr_storage.h"
18 #include "testing/gtest_mac.h" 19 #include "testing/gtest_mac.h"
19 20
20 @interface TestNSNetService : NSNetService { 21 @interface TestNSNetService : NSNetService {
21 @private 22 @private
22 NSData* data_; 23 base::scoped_nsobject<NSData> data_;
23 NSArray* addresses_; 24 base::scoped_nsobject<NSArray> addresses_;
24 } 25 }
25 - (id)initWithData:(NSData*)data; 26 - (id)initWithData:(NSData*)data;
26 - (void)setAddresses:(NSArray*)addresses; 27 - (void)setAddresses:(NSArray*)addresses;
27 @end 28 @end
28 29
29 @implementation TestNSNetService 30 @implementation TestNSNetService
30 31
31 - (id)initWithData:(NSData*)data { 32 - (id)initWithData:(NSData*)data {
32 if ((self = [super init])) { 33 if ((self = [super init])) {
33 data_ = data; 34 data_.reset([data retain]);
34 } 35 }
35 return self; 36 return self;
36 } 37 }
37 38
38 - (void)setAddresses:(NSArray*)addresses { 39 - (void)setAddresses:(NSArray*)addresses {
39 addresses_ = addresses; 40 addresses_.reset([addresses copy]);
40 } 41 }
41 42
42 - (NSArray*)addresses { 43 - (NSArray*)addresses {
43 return addresses_; 44 return addresses_;
44 } 45 }
45 46
46 - (NSData*)TXTRecordData { 47 - (NSData*)TXTRecordData {
47 return data_; 48 return data_;
48 } 49 }
49 50
50 @end 51 @end
51 52
52 namespace local_discovery { 53 namespace local_discovery {
53 54
54 class ServiceDiscoveryClientMacTest : public CocoaTest { 55 class ServiceDiscoveryClientMacTest : public CocoaTest {
55 public: 56 public:
56 ServiceDiscoveryClientMacTest() : num_updates_(0), num_resolves_(0) { 57 ServiceDiscoveryClientMacTest()
57 client_mac_ = new ServiceDiscoveryClientMac(); 58 : client_(new ServiceDiscoveryClientMac()),
58 client_ = client_mac_.get(); 59 num_updates_(0),
60 num_resolves_(0) {
59 } 61 }
60 62
61 void OnServiceUpdated( 63 void OnServiceUpdated(
62 ServiceWatcher::UpdateType update, 64 ServiceWatcher::UpdateType update,
63 const std::string& service_name) { 65 const std::string& service_name) {
64 last_update_ = update; 66 last_update_ = update;
65 last_service_name_ = service_name; 67 last_service_name_ = service_name;
66 num_updates_++; 68 num_updates_++;
67 } 69 }
68 70
69
70 void OnResolveComplete( 71 void OnResolveComplete(
71 ServiceResolver::RequestStatus status, 72 ServiceResolver::RequestStatus status,
72 const ServiceDescription& service_description) { 73 const ServiceDescription& service_description) {
73 last_status_ = status; 74 last_status_ = status;
74 last_service_description_ = service_description; 75 last_service_description_ = service_description;
75 num_resolves_++; 76 num_resolves_++;
76 } 77 }
77 78
79 ServiceDiscoveryClient* client() { return client_.get(); }
80
78 protected: 81 protected:
79 content::TestBrowserThreadBundle thread_bundle_; 82 content::TestBrowserThreadBundle thread_bundle_;
80 83
81 scoped_refptr<ServiceDiscoveryClientMac> client_mac_; 84 scoped_refptr<ServiceDiscoveryClientMac> client_;
82 ServiceDiscoveryClient* client_; // weak
83 85
84 ServiceWatcher::UpdateType last_update_; 86 ServiceWatcher::UpdateType last_update_;
85 std::string last_service_name_; 87 std::string last_service_name_;
86 int num_updates_; 88 int num_updates_;
87 ServiceResolver::RequestStatus last_status_; 89 ServiceResolver::RequestStatus last_status_;
88 ServiceDescription last_service_description_; 90 ServiceDescription last_service_description_;
89 int num_resolves_; 91 int num_resolves_;
90 }; 92 };
91 93
92 TEST_F(ServiceDiscoveryClientMacTest, ServiceWatcher) { 94 TEST_F(ServiceDiscoveryClientMacTest, ServiceWatcher) {
93 const std::string test_service_type = "_testing._tcp.local"; 95 const std::string test_service_type = "_testing._tcp.local";
94 const std::string test_service_name = "Test.123"; 96 const std::string test_service_name = "Test.123";
95 97
96 std::unique_ptr<ServiceWatcher> watcher = client_->CreateServiceWatcher( 98 std::unique_ptr<ServiceWatcher> watcher = client()->CreateServiceWatcher(
97 test_service_type, 99 test_service_type,
98 base::Bind(&ServiceDiscoveryClientMacTest::OnServiceUpdated, 100 base::Bind(&ServiceDiscoveryClientMacTest::OnServiceUpdated,
99 base::Unretained(this))); 101 base::Unretained(this)));
100 watcher->Start(); 102 watcher->Start();
101 103
102 // Weak pointer to implementation class. 104 // Weak pointer to implementation class.
103 ServiceWatcherImplMac* watcher_impl = 105 ServiceWatcherImplMac* watcher_impl =
104 static_cast<ServiceWatcherImplMac*>(watcher.get()); 106 static_cast<ServiceWatcherImplMac*>(watcher.get());
105 // Simulate service update events. 107 // Simulate service update events.
106 watcher_impl->OnServicesUpdate( 108 watcher_impl->OnServicesUpdate(
107 ServiceWatcher::UPDATE_ADDED, test_service_name); 109 ServiceWatcher::UPDATE_ADDED, test_service_name);
108 watcher_impl->OnServicesUpdate( 110 watcher_impl->OnServicesUpdate(
109 ServiceWatcher::UPDATE_CHANGED, test_service_name); 111 ServiceWatcher::UPDATE_CHANGED, test_service_name);
110 watcher_impl->OnServicesUpdate( 112 watcher_impl->OnServicesUpdate(
111 ServiceWatcher::UPDATE_REMOVED, test_service_name); 113 ServiceWatcher::UPDATE_REMOVED, test_service_name);
112 EXPECT_EQ(last_service_name_, test_service_name + "." + test_service_type); 114 EXPECT_EQ(last_service_name_, test_service_name + "." + test_service_type);
113 EXPECT_EQ(num_updates_, 3); 115 EXPECT_EQ(num_updates_, 3);
114 } 116 }
115 117
116 TEST_F(ServiceDiscoveryClientMacTest, ServiceResolver) { 118 TEST_F(ServiceDiscoveryClientMacTest, ServiceResolver) {
117 const std::string test_service_name = "Test.123._testing._tcp.local"; 119 const std::string test_service_name = "Test.123._testing._tcp.local";
118 std::unique_ptr<ServiceResolver> resolver = client_->CreateServiceResolver( 120 std::unique_ptr<ServiceResolver> resolver = client()->CreateServiceResolver(
119 test_service_name, 121 test_service_name,
120 base::Bind(&ServiceDiscoveryClientMacTest::OnResolveComplete, 122 base::Bind(&ServiceDiscoveryClientMacTest::OnResolveComplete,
121 base::Unretained(this))); 123 base::Unretained(this)));
122 124
123 const uint8_t record_bytes[] = {2, 'a', 'b', 3, 'd', '=', 'e'}; 125 const uint8_t record_bytes[] = {2, 'a', 'b', 3, 'd', '=', 'e'};
124 base::scoped_nsobject<TestNSNetService> test_service([[TestNSNetService alloc] 126 base::scoped_nsobject<TestNSNetService> test_service([[TestNSNetService alloc]
125 initWithData:[[NSData alloc] initWithBytes:record_bytes 127 initWithData:[NSData dataWithBytes:record_bytes
126 length:arraysize(record_bytes)]]); 128 length:arraysize(record_bytes)]]);
127 129
128 const std::string kIp = "2001:4860:4860::8844"; 130 const std::string kIp = "2001:4860:4860::8844";
129 const uint16_t kPort = 4321; 131 const uint16_t kPort = 4321;
130 net::IPAddress ip_address; 132 net::IPAddress ip_address;
131 ASSERT_TRUE(ip_address.AssignFromIPLiteral(kIp)); 133 ASSERT_TRUE(ip_address.AssignFromIPLiteral(kIp));
132 net::IPEndPoint endpoint(ip_address, kPort); 134 net::IPEndPoint endpoint(ip_address, kPort);
133 net::SockaddrStorage storage; 135 net::SockaddrStorage storage;
134 ASSERT_TRUE(endpoint.ToSockAddr(storage.addr, &storage.addr_len)); 136 ASSERT_TRUE(endpoint.ToSockAddr(storage.addr, &storage.addr_len));
135 NSData* discoveryHost = 137 NSData* discoveryHost =
136 [NSData dataWithBytes:storage.addr length:storage.addr_len]; 138 [NSData dataWithBytes:storage.addr length:storage.addr_len];
137 NSArray* addresses = @[ discoveryHost ]; 139 NSArray* addresses = @[ discoveryHost ];
138 [test_service setAddresses:addresses]; 140 [test_service setAddresses:addresses];
139 141
140 ServiceResolverImplMac* resolver_impl = 142 ServiceResolverImplMac* resolver_impl =
141 static_cast<ServiceResolverImplMac*>(resolver.get()); 143 static_cast<ServiceResolverImplMac*>(resolver.get());
142 resolver_impl->GetContainerForTesting()->SetServiceForTesting( 144 resolver_impl->GetContainerForTesting()->SetServiceForTesting(
143 base::scoped_nsobject<NSNetService>(test_service)); 145 base::scoped_nsobject<NSNetService>(test_service));
144 resolver->StartResolving(); 146 resolver->StartResolving();
145 147
146 resolver_impl->GetContainerForTesting()->OnResolveUpdate( 148 resolver_impl->GetContainerForTesting()->OnResolveUpdate(
147 ServiceResolver::STATUS_SUCCESS); 149 ServiceResolver::STATUS_SUCCESS);
148 150
149 base::RunLoop().RunUntilIdle(); 151 base::RunLoop().RunUntilIdle();
150 152
151 EXPECT_EQ(1, num_resolves_); 153 EXPECT_EQ(1, num_resolves_);
152 EXPECT_EQ(2u, last_service_description_.metadata.size()); 154
155 const std::vector<std::string>& metadata =
156 last_service_description_.metadata;
157 EXPECT_EQ(2u, metadata.size());
158 EXPECT_NE(metadata.end(),
159 std::find(metadata.begin(), metadata.end(), "ab"));
160 EXPECT_NE(metadata.end(),
161 std::find(metadata.begin(), metadata.end(), "d=e"));
162
153 EXPECT_EQ(ip_address, last_service_description_.ip_address); 163 EXPECT_EQ(ip_address, last_service_description_.ip_address);
154 EXPECT_EQ(kPort, last_service_description_.address.port()); 164 EXPECT_EQ(kPort, last_service_description_.address.port());
155 EXPECT_EQ(kIp, last_service_description_.address.host()); 165 EXPECT_EQ(kIp, last_service_description_.address.host());
156 } 166 }
157 167
168 // https://crbug.com/586628
169 TEST_F(ServiceDiscoveryClientMacTest, ResolveInvalidUnicodeRecord) {
170 const std::string test_service_name = "Test.123._testing._tcp.local";
171 std::unique_ptr<ServiceResolver> resolver = client()->CreateServiceResolver(
172 test_service_name,
173 base::Bind(&ServiceDiscoveryClientMacTest::OnResolveComplete,
174 base::Unretained(this)));
175
176 const uint8_t record_bytes[] = {
177 3, 'a', '=', 'b',
178 // The bytes after name= are the UTF-8 encoded representation of
179 // U+1F4A9, with the first two bytes of the code unit sequence transposed.
180 9, 'n', 'a', 'm', 'e', '=', 0x9F, 0xF0, 0x92, 0xA9,
181 5, 'c', 'd', '=', 'e', '9',
182 };
183 base::scoped_nsobject<TestNSNetService> test_service([[TestNSNetService alloc]
184 initWithData:[NSData dataWithBytes:record_bytes
185 length:arraysize(record_bytes)]]);
186
187 const std::string kIp = "2001:4860:4860::8844";
188 const uint16_t kPort = 4321;
189 net::IPAddress ip_address;
190 ASSERT_TRUE(ip_address.AssignFromIPLiteral(kIp));
191 net::IPEndPoint endpoint(ip_address, kPort);
192 net::SockaddrStorage storage;
193 ASSERT_TRUE(endpoint.ToSockAddr(storage.addr, &storage.addr_len));
194 NSData* discovery_host =
195 [NSData dataWithBytes:storage.addr length:storage.addr_len];
196 NSArray* addresses = @[ discovery_host ];
197 [test_service setAddresses:addresses];
198
199 ServiceResolverImplMac* resolver_impl =
200 static_cast<ServiceResolverImplMac*>(resolver.get());
201 resolver_impl->GetContainerForTesting()->SetServiceForTesting(
202 base::scoped_nsobject<NSNetService>(test_service));
203 resolver->StartResolving();
204
205 resolver_impl->GetContainerForTesting()->OnResolveUpdate(
206 ServiceResolver::STATUS_SUCCESS);
207
208 base::RunLoop().RunUntilIdle();
209
210 EXPECT_EQ(1, num_resolves_);
211
212 const std::vector<std::string>& metadata =
213 last_service_description_.metadata;
214 EXPECT_EQ(2u, metadata.size());
215 EXPECT_NE(metadata.end(),
216 std::find(metadata.begin(), metadata.end(), "a=b"));
217 EXPECT_NE(metadata.end(),
218 std::find(metadata.begin(), metadata.end(), "cd=e9"));
219
220 EXPECT_EQ(ip_address, last_service_description_.ip_address);
221 EXPECT_EQ(kPort, last_service_description_.address.port());
222 EXPECT_EQ(kIp, last_service_description_.address.host());
223 }
224
225 TEST_F(ServiceDiscoveryClientMacTest, ResolveInvalidServiceName) {
226 base::RunLoop run_loop;
227
228 // This is the same invalid U+1F4A9 code unit sequence as in
229 // ResolveInvalidUnicodeRecord.
230 const std::string test_service_name =
231 "Test\x9F\xF0\x92\xA9.123._testing._tcp.local";
232 std::unique_ptr<ServiceResolver> resolver = client()->CreateServiceResolver(
233 test_service_name,
234 base::Bind(
235 [](ServiceDiscoveryClientMacTest* test,
236 base::Closure quit_closure,
237 ServiceResolver::RequestStatus status,
238 const ServiceDescription& service_description) {
239 test->OnResolveComplete(status, service_description);
240 quit_closure.Run();
241 },
242 base::Unretained(this), run_loop.QuitClosure()));
243 resolver->StartResolving();
244
245 run_loop.Run();
246
247 EXPECT_EQ(1, num_resolves_);
248 EXPECT_EQ(ServiceResolver::STATUS_KNOWN_NONEXISTENT, last_status_);
249 }
250
158 } // namespace local_discovery 251 } // namespace local_discovery
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698