OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "content/browser/bluetooth/bluetooth_device_chooser_controller.h" | 5 #include "content/browser/bluetooth/bluetooth_device_chooser_controller.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 #include <unordered_set> | 9 #include <unordered_set> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
15 #include "content/browser/bluetooth/bluetooth_blacklist.h" | 15 #include "content/browser/bluetooth/bluetooth_blacklist.h" |
16 #include "content/browser/bluetooth/bluetooth_metrics.h" | 16 #include "content/browser/bluetooth/bluetooth_metrics.h" |
17 #include "content/browser/bluetooth/first_device_bluetooth_chooser.h" | 17 #include "content/browser/bluetooth/first_device_bluetooth_chooser.h" |
18 #include "content/browser/bluetooth/web_bluetooth_service_impl.h" | 18 #include "content/browser/bluetooth/web_bluetooth_service_impl.h" |
19 #include "content/public/browser/browser_thread.h" | 19 #include "content/public/browser/browser_thread.h" |
20 #include "content/public/browser/content_browser_client.h" | 20 #include "content/public/browser/content_browser_client.h" |
21 #include "content/public/browser/render_frame_host.h" | 21 #include "content/public/browser/render_frame_host.h" |
22 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
23 #include "content/public/browser/web_contents_delegate.h" | 23 #include "content/public/browser/web_contents_delegate.h" |
24 #include "device/bluetooth/bluetooth_adapter.h" | 24 #include "device/bluetooth/bluetooth_adapter.h" |
25 #include "device/bluetooth/bluetooth_discovery_session.h" | 25 #include "device/bluetooth/bluetooth_discovery_session.h" |
26 | 26 |
| 27 using device::BluetoothUUID; |
| 28 |
27 namespace content { | 29 namespace content { |
28 | 30 |
29 namespace { | 31 namespace { |
30 constexpr size_t kMaxLengthForDeviceName = | 32 constexpr size_t kMaxLengthForDeviceName = |
31 29; // max length of device name in filter. | 33 29; // max length of device name in filter. |
32 | 34 |
33 void LogRequestDeviceOptions( | 35 void LogRequestDeviceOptions( |
34 const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { | 36 const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) { |
35 VLOG(1) << "requestDevice called with the following filters: "; | 37 VLOG(1) << "requestDevice called with the following filters: "; |
36 int i = 0; | 38 int i = 0; |
37 for (const auto& filter : options->filters) { | 39 for (const auto& filter : options->filters) { |
38 VLOG(1) << "Filter #" << ++i; | 40 VLOG(1) << "Filter #" << ++i; |
39 if (!filter->name.is_null()) | 41 if (!filter->name.is_null()) |
40 VLOG(1) << "Name: " << filter->name; | 42 VLOG(1) << "Name: " << filter->name; |
41 | 43 |
42 if (!filter->name_prefix.is_null()) | 44 if (!filter->name_prefix.is_null()) |
43 VLOG(1) << "Name Prefix: " << filter->name_prefix; | 45 VLOG(1) << "Name Prefix: " << filter->name_prefix; |
44 | 46 |
45 if (!filter->services.is_null()) { | 47 if (!filter->services.is_null()) { |
46 VLOG(1) << "Services: "; | 48 VLOG(1) << "Services: "; |
47 VLOG(1) << "\t["; | 49 VLOG(1) << "\t["; |
48 for (const auto& service : filter->services) | 50 for (const auto& service : filter->services) |
49 VLOG(1) << "\t\t" << service; | 51 VLOG(1) << "\t\t" << service->canonical_value(); |
50 VLOG(1) << "\t]"; | 52 VLOG(1) << "\t]"; |
51 } | 53 } |
52 } | 54 } |
53 } | 55 } |
54 | 56 |
55 bool IsValidUUID(const mojo::String& uuid) { | |
56 device::BluetoothUUID parsed_uuid(uuid); | |
57 return parsed_uuid.IsValid() && | |
58 parsed_uuid.format() == device::BluetoothUUID::kFormat128Bit; | |
59 } | |
60 | |
61 bool HasInvalidOptionalServices( | |
62 const mojo::Array<mojo::String>& optional_services) { | |
63 return optional_services.end() != std::find_if_not(optional_services.begin(), | |
64 optional_services.end(), | |
65 IsValidUUID); | |
66 } | |
67 | |
68 bool IsEmptyOrInvalidFilter( | 57 bool IsEmptyOrInvalidFilter( |
69 const blink::mojom::WebBluetoothScanFilterPtr& filter) { | 58 const blink::mojom::WebBluetoothScanFilterPtr& filter) { |
70 // At least one member needs to be present. | 59 // At least one member needs to be present. |
71 if (filter->name.is_null() && filter->name_prefix.is_null() && | 60 if (filter->name.is_null() && filter->name_prefix.is_null() && |
72 filter->services.is_null()) | 61 filter->services.is_null()) |
73 return true; | 62 return true; |
74 | 63 |
75 // The renderer will never send a name or a name_prefix longer than | 64 // The renderer will never send a name or a name_prefix longer than |
76 // kMaxLengthForDeviceName. | 65 // kMaxLengthForDeviceName. |
77 if (!filter->name.is_null() && filter->name.size() > kMaxLengthForDeviceName) | 66 if (!filter->name.is_null() && filter->name.size() > kMaxLengthForDeviceName) |
78 return true; | 67 return true; |
79 if (!filter->name_prefix.is_null() && | 68 if (!filter->name_prefix.is_null() && |
80 filter->name_prefix.size() > kMaxLengthForDeviceName) | 69 filter->name_prefix.size() > kMaxLengthForDeviceName) |
81 return true; | 70 return true; |
82 | 71 |
83 if (!filter->services.is_null()) { | |
84 const auto& services = filter->services; | |
85 return services.end() != | |
86 std::find_if_not(services.begin(), services.end(), IsValidUUID); | |
87 } | |
88 | |
89 return false; | 72 return false; |
90 } | 73 } |
91 | 74 |
92 bool HasEmptyOrInvalidFilter( | 75 bool HasEmptyOrInvalidFilter( |
93 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { | 76 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { |
94 return filters.empty() | 77 return filters.empty() |
95 ? true | 78 ? true |
96 : filters.end() != std::find_if(filters.begin(), filters.end(), | 79 : filters.end() != std::find_if(filters.begin(), filters.end(), |
97 IsEmptyOrInvalidFilter); | 80 IsEmptyOrInvalidFilter); |
98 } | 81 } |
(...skipping 10 matching lines...) Expand all Loading... |
109 } | 92 } |
110 | 93 |
111 if (!filter->name_prefix.is_null() && | 94 if (!filter->name_prefix.is_null() && |
112 (!base::StartsWith(device_name, filter->name_prefix.get(), | 95 (!base::StartsWith(device_name, filter->name_prefix.get(), |
113 base::CompareCase::SENSITIVE))) { | 96 base::CompareCase::SENSITIVE))) { |
114 return false; | 97 return false; |
115 } | 98 } |
116 | 99 |
117 if (!filter->services.is_null()) { | 100 if (!filter->services.is_null()) { |
118 const auto& device_uuid_list = device.GetUUIDs(); | 101 const auto& device_uuid_list = device.GetUUIDs(); |
119 const std::set<device::BluetoothUUID> device_uuids(device_uuid_list.begin(), | 102 const std::unordered_set<BluetoothUUID, device::BluetoothUUIDHash> |
120 device_uuid_list.end()); | 103 device_uuids(device_uuid_list.begin(), device_uuid_list.end()); |
121 for (const auto& service : filter->services) { | 104 for (const base::Optional<BluetoothUUID>& service : filter->services) { |
122 if (!ContainsKey(device_uuids, device::BluetoothUUID(service))) { | 105 if (!ContainsKey(device_uuids, service.value())) { |
123 return false; | 106 return false; |
124 } | 107 } |
125 } | 108 } |
126 } | 109 } |
127 | 110 |
128 return true; | 111 return true; |
129 } | 112 } |
130 | 113 |
131 bool MatchesFilters( | 114 bool MatchesFilters( |
132 const device::BluetoothDevice& device, | 115 const device::BluetoothDevice& device, |
133 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { | 116 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { |
134 DCHECK(!HasEmptyOrInvalidFilter(filters)); | 117 DCHECK(!HasEmptyOrInvalidFilter(filters)); |
135 for (const auto& filter : filters) { | 118 for (const auto& filter : filters) { |
136 if (MatchesFilter(device, filter)) { | 119 if (MatchesFilter(device, filter)) { |
137 return true; | 120 return true; |
138 } | 121 } |
139 } | 122 } |
140 return false; | 123 return false; |
141 } | 124 } |
142 | 125 |
143 std::unique_ptr<device::BluetoothDiscoveryFilter> ComputeScanFilter( | 126 std::unique_ptr<device::BluetoothDiscoveryFilter> ComputeScanFilter( |
144 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { | 127 const mojo::Array<blink::mojom::WebBluetoothScanFilterPtr>& filters) { |
145 std::unordered_set<std::string> services; | 128 std::unordered_set<BluetoothUUID, device::BluetoothUUIDHash> services; |
146 for (const auto& filter : filters) { | 129 for (const auto& filter : filters) { |
147 for (const std::string& service : filter->services) { | 130 for (const base::Optional<BluetoothUUID>& service : filter->services) { |
148 services.insert(service); | 131 services.insert(service.value()); |
149 } | 132 } |
150 } | 133 } |
151 auto discovery_filter = base::MakeUnique<device::BluetoothDiscoveryFilter>( | 134 auto discovery_filter = base::MakeUnique<device::BluetoothDiscoveryFilter>( |
152 device::BluetoothDiscoveryFilter::TRANSPORT_DUAL); | 135 device::BluetoothDiscoveryFilter::TRANSPORT_DUAL); |
153 for (const std::string& service : services) { | 136 for (const BluetoothUUID& service : services) { |
154 discovery_filter->AddUUID(device::BluetoothUUID(service)); | 137 discovery_filter->AddUUID(service); |
155 } | 138 } |
156 return discovery_filter; | 139 return discovery_filter; |
157 } | 140 } |
158 | 141 |
159 void StopDiscoverySession( | 142 void StopDiscoverySession( |
160 std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { | 143 std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { |
161 // Nothing goes wrong if the discovery session fails to stop, and we don't | 144 // Nothing goes wrong if the discovery session fails to stop, and we don't |
162 // need to wait for it before letting the user's script proceed, so we ignore | 145 // need to wait for it before letting the user's script proceed, so we ignore |
163 // the results here. | 146 // the results here. |
164 discovery_session->Stop(base::Bind(&base::DoNothing), | 147 discovery_session->Stop(base::Bind(&base::DoNothing), |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 210 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
228 | 211 |
229 // GetDevice should only be called once. | 212 // GetDevice should only be called once. |
230 DCHECK(success_callback_.is_null()); | 213 DCHECK(success_callback_.is_null()); |
231 DCHECK(error_callback_.is_null()); | 214 DCHECK(error_callback_.is_null()); |
232 | 215 |
233 success_callback_ = success_callback; | 216 success_callback_ = success_callback; |
234 error_callback_ = error_callback; | 217 error_callback_ = error_callback; |
235 | 218 |
236 // The renderer should never send empty filters. | 219 // The renderer should never send empty filters. |
237 if (HasEmptyOrInvalidFilter(options->filters) || | 220 if (HasEmptyOrInvalidFilter(options->filters)) { |
238 HasInvalidOptionalServices(options->optional_services)) { | |
239 web_bluetooth_service_->CrashRendererAndClosePipe( | 221 web_bluetooth_service_->CrashRendererAndClosePipe( |
240 bad_message::BDH_EMPTY_OR_INVALID_FILTERS); | 222 bad_message::BDH_EMPTY_OR_INVALID_FILTERS); |
241 return; | 223 return; |
242 } | 224 } |
243 options_ = std::move(options); | 225 options_ = std::move(options); |
244 LogRequestDeviceOptions(options_); | 226 LogRequestDeviceOptions(options_); |
245 | 227 |
246 // Check blacklist to reject invalid filters and adjust optional_services. | 228 // Check blacklist to reject invalid filters and adjust optional_services. |
247 if (BluetoothBlacklist::Get().IsExcluded(options_->filters)) { | 229 if (BluetoothBlacklist::Get().IsExcluded(options_->filters)) { |
248 RecordRequestDeviceOutcome( | 230 RecordRequestDeviceOutcome( |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 | 461 |
480 void BluetoothDeviceChooserController::PostErrorCallback( | 462 void BluetoothDeviceChooserController::PostErrorCallback( |
481 blink::mojom::WebBluetoothError error) { | 463 blink::mojom::WebBluetoothError error) { |
482 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( | 464 if (!base::ThreadTaskRunnerHandle::Get()->PostTask( |
483 FROM_HERE, base::Bind(error_callback_, error))) { | 465 FROM_HERE, base::Bind(error_callback_, error))) { |
484 LOG(WARNING) << "No TaskRunner."; | 466 LOG(WARNING) << "No TaskRunner."; |
485 } | 467 } |
486 } | 468 } |
487 | 469 |
488 } // namespace content | 470 } // namespace content |
OLD | NEW |