Index: content/browser/bluetooth/web_bluetooth_service_impl.cc |
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ea627d222e06e9e0117271725f0f50580c0b7a6e |
--- /dev/null |
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc |
@@ -0,0 +1,156 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/bluetooth/web_bluetooth_service_impl.h" |
+ |
+#include <vector> |
+ |
+#include "content/browser/bluetooth/bluetooth_blacklist.h" |
+#include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
+#include "content/browser/renderer_host/render_process_host_impl.h" |
+#include "content/public/browser/render_frame_host.h" |
+#include "device/bluetooth/bluetooth_gatt_characteristic.h" |
+ |
+using device::BluetoothGattService; |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+blink::mojom::WebBluetoothError TranslateGATTErrorAndRecord( |
+ BluetoothGattService::GattErrorCode error_code, |
+ UMAGATTOperation operation) { |
+ switch (error_code) { |
+ case BluetoothGattService::GATT_ERROR_UNKNOWN: |
+ RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::UNKNOWN); |
+ return blink::mojom::WebBluetoothError::GATT_UNKNOWN_ERROR; |
+ case BluetoothGattService::GATT_ERROR_FAILED: |
+ RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::FAILED); |
+ return blink::mojom::WebBluetoothError::GATT_UNKNOWN_FAILURE; |
+ case BluetoothGattService::GATT_ERROR_IN_PROGRESS: |
+ RecordGATTOperationOutcome(operation, |
+ UMAGATTOperationOutcome::IN_PROGRESS); |
+ return blink::mojom::WebBluetoothError::GATT_OPERATION_IN_PROGRESS; |
+ case BluetoothGattService::GATT_ERROR_INVALID_LENGTH: |
+ RecordGATTOperationOutcome(operation, |
+ UMAGATTOperationOutcome::INVALID_LENGTH); |
+ return blink::mojom::WebBluetoothError::GATT_INVALID_ATTRIBUTE_LENGTH; |
+ case BluetoothGattService::GATT_ERROR_NOT_PERMITTED: |
+ RecordGATTOperationOutcome(operation, |
+ UMAGATTOperationOutcome::NOT_PERMITTED); |
+ return blink::mojom::WebBluetoothError::GATT_NOT_PERMITTED; |
+ case BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED: |
+ RecordGATTOperationOutcome(operation, |
+ UMAGATTOperationOutcome::NOT_AUTHORIZED); |
+ return blink::mojom::WebBluetoothError::GATT_NOT_AUTHORIZED; |
+ case BluetoothGattService::GATT_ERROR_NOT_PAIRED: |
+ RecordGATTOperationOutcome(operation, |
+ UMAGATTOperationOutcome::NOT_PAIRED); |
+ return blink::mojom::WebBluetoothError::GATT_NOT_PAIRED; |
+ case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED: |
+ RecordGATTOperationOutcome(operation, |
+ UMAGATTOperationOutcome::NOT_SUPPORTED); |
+ return blink::mojom::WebBluetoothError::GATT_NOT_SUPPORTED; |
+ } |
+ NOTREACHED(); |
+ return blink::mojom::WebBluetoothError::GATT_UNTRANSLATED_ERROR_CODE; |
+} |
+ |
+} // namespace |
+ |
+using CacheQueryResult = BluetoothDispatcherHost::CacheQueryResult; |
+ |
+WebBluetoothServiceImpl::WebBluetoothServiceImpl( |
+ RenderFrameHost* render_frame_host, |
+ blink::mojom::WebBluetoothServiceRequest request) |
+ : render_frame_host_(render_frame_host), |
+ binding_(this, std::move(request)), |
+ weak_ptr_factory_(this) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+} |
+ |
+WebBluetoothServiceImpl::~WebBluetoothServiceImpl() {} |
+ |
+void WebBluetoothServiceImpl::RemoteCharacteristicWriteValue( |
+ const mojo::String& characteristic_instance_id, |
+ mojo::Array<uint8_t> value, |
+ const RemoteCharacteristicWriteValueCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ RecordWebBluetoothFunctionCall( |
+ UMAWebBluetoothFunction::CHARACTERISTIC_WRITE_VALUE); |
+ |
+ // We perform the length check on the renderer side. So if we |
+ // get a value with length > 512, we can assume it's a hostile |
+ // renderer and kill it. |
+ if (value.size() > 512) { |
+ CrashRendererAndClosePipe(bad_message::BDH_INVALID_WRITE_VALUE_LENGTH); |
+ return; |
+ } |
+ |
+ const CacheQueryResult query_result = |
+ GetBluetoothDispatcherHost()->QueryCacheForCharacteristic( |
+ GetOrigin(), characteristic_instance_id); |
+ |
+ if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
+ binding_.Close(); |
+ return; |
+ } |
+ |
+ if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
+ RecordCharacteristicWriteValueOutcome(query_result.outcome); |
+ callback.Run(query_result.GetWebError()); |
+ return; |
+ } |
+ |
+ if (BluetoothBlacklist::Get().IsExcludedFromWrites( |
+ query_result.characteristic->GetUUID())) { |
+ RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::BLACKLISTED); |
+ callback.Run(blink::mojom::WebBluetoothError::BLACKLISTED_WRITE); |
+ return; |
+ } |
+ |
+ query_result.characteristic->WriteRemoteCharacteristic( |
+ value.To<std::vector<uint8_t>>(), |
+ base::Bind(&WebBluetoothServiceImpl::OnWriteValueSuccess, |
+ weak_ptr_factory_.GetWeakPtr(), callback), |
+ base::Bind(&WebBluetoothServiceImpl::OnWriteValueFailed, |
+ weak_ptr_factory_.GetWeakPtr(), callback)); |
+} |
+ |
+void WebBluetoothServiceImpl::OnWriteValueSuccess( |
+ const RemoteCharacteristicWriteValueCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::SUCCESS); |
+ callback.Run(blink::mojom::WebBluetoothError::SUCCESS); |
+} |
+ |
+void WebBluetoothServiceImpl::OnWriteValueFailed( |
+ const RemoteCharacteristicWriteValueCallback& callback, |
+ device::BluetoothGattService::GattErrorCode error_code) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ callback.Run(TranslateGATTErrorAndRecord( |
+ error_code, UMAGATTOperation::CHARACTERISTIC_WRITE)); |
+} |
+ |
+RenderProcessHost* WebBluetoothServiceImpl::GetRenderProcessHost() { |
+ return render_frame_host_->GetProcess(); |
+} |
+ |
+BluetoothDispatcherHost* WebBluetoothServiceImpl::GetBluetoothDispatcherHost() { |
+ RenderProcessHostImpl* render_process_host_impl = |
+ static_cast<RenderProcessHostImpl*>(GetRenderProcessHost()); |
+ return render_process_host_impl->GetBluetoothDispatcherHost(); |
+} |
+ |
+void WebBluetoothServiceImpl::CrashRendererAndClosePipe( |
+ bad_message::BadMessageReason reason) { |
+ bad_message::ReceivedBadMessage(GetRenderProcessHost(), reason); |
+ binding_.Close(); |
+} |
+ |
+url::Origin WebBluetoothServiceImpl::GetOrigin() { |
+ return render_frame_host_->GetLastCommittedOrigin(); |
+} |
+ |
+} // namespace content |