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

Unified Diff: device/usb/webusb_descriptors.cc

Issue 1646783002: Update webusb_descriptors.cc to parse the new WebUSB descriptors. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@io_buffer
Patch Set: Sometimes MSVC complains about passing size_type to BarrierClosure. Created 4 years, 11 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « device/usb/webusb_descriptors.h ('k') | device/usb/webusb_descriptors_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: device/usb/webusb_descriptors.cc
diff --git a/device/usb/webusb_descriptors.cc b/device/usb/webusb_descriptors.cc
index 43ad170f44da0ae2e052199e7b9221b946c9af6b..27a3d38ea8f8ae6531284945373424e4475a2162 100644
--- a/device/usb/webusb_descriptors.cc
+++ b/device/usb/webusb_descriptors.cc
@@ -5,9 +5,19 @@
#include <stddef.h>
#include <iterator>
+#include <map>
+#include <set>
+#include "base/barrier_closure.h"
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/logging.h"
+#include "components/device_event_log/device_event_log.h"
+#include "device/usb/usb_device_handle.h"
#include "device/usb/webusb_descriptors.h"
+#include "net/base/io_buffer.h"
+
+using net::IOBufferWithSize;
namespace device {
@@ -15,6 +25,8 @@ namespace {
// These constants are defined by the Universal Serial Device 3.0 Specification
// Revision 1.0.
+const uint8_t kGetDescriptorRequest = 0x06;
+
const uint8_t kBosDescriptorType = 0x0F;
const uint8_t kDeviceCapabilityDescriptorType = 0x10;
@@ -22,136 +34,325 @@ const uint8_t kPlatformDevCapabilityType = 0x05;
// These constants are defined by the WebUSB specification:
// http://wicg.github.io/webusb/
+const uint8_t kGetAllowedOriginsRequest = 0x01;
+const uint8_t kGetUrlRequest = 0x02;
+
const uint8_t kWebUsbCapabilityUUID[16] = {
// Little-endian encoding of {3408b638-09a9-47a0-8bfd-a0768815b665}.
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65};
-const uint8_t kDescriptorSetDescriptorType = 0x00;
-const uint8_t kConfigurationSubsetDescriptorType = 0x01;
-const uint8_t kFunctionSubsetDescriptorType = 0x02;
-const uint8_t kUrlDescriptorType = 0x03;
+const int kControlTransferTimeout = 60000; // 1 minute
+
+using ReadWebUsbDescriptorsCallback =
+ base::Callback<void(scoped_ptr<WebUsbAllowedOrigins> allowed_origins,
+ const GURL& landing_page)>;
+
+using ReadWebUsbAllowedOriginsCallback =
+ base::Callback<void(scoped_ptr<WebUsbAllowedOrigins> allowed_origins)>;
+
+// Parses a WebUSB Function Subset Header:
+// http://wicg.github.io/webusb/#dfn-function-subset-header
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | length | type | 1st interface | origin[0] |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | origin[1] | ...
+// +-+-+-+-+-+-+-+-+-+-+-+------
+bool ParseFunction(WebUsbFunctionSubset* function,
+ std::vector<uint8_t>::const_iterator* it,
+ std::vector<uint8_t>::const_iterator end) {
+ const uint8_t kDescriptorType = 0x02;
+ const uint8_t kDescriptorMinLength = 3;
-bool ParseUrl(GURL* url,
- std::vector<uint8_t>::const_iterator* it,
- std::vector<uint8_t>::const_iterator end) {
- // These conditions must be guaranteed by the caller.
- DCHECK(*it != end);
+ // If this isn't the end of the buffer then there must be at least one byte
+ // available, the length of the descriptor.
+ if (*it == end)
+ return false;
uint8_t length = (*it)[0];
- DCHECK_LE(length, std::distance(*it, end));
- DCHECK_GE(length, 2);
- DCHECK_EQ((*it)[1], kUrlDescriptorType);
- if (length == 2) {
+ // Is this a valid Function Subset Header? It must be long enough, fit within
+ // the buffer and have the right descriptor type.
+ if (length < kDescriptorMinLength || std::distance(*it, end) < length ||
+ (*it)[1] != kDescriptorType) {
return false;
}
- const char* str = reinterpret_cast<const char*>(&(*it)[2]);
- *url = GURL(std::string(str, length - 2));
- if (!url->is_valid()) {
- return false;
+ function->first_interface = (*it)[2];
+
+ // Everything after the mandatory fields are origin indicies.
+ std::advance(*it, kDescriptorMinLength);
+ uint8_t num_origins = length - kDescriptorMinLength;
+ function->origin_ids.reserve(num_origins);
+ for (size_t i = 0; i < num_origins; ++i) {
+ uint8_t index = *(*it)++;
+ if (index == 0)
+ return false;
+ function->origin_ids.push_back(index);
}
- std::advance(*it, length);
return true;
}
-bool ParseFunction(WebUsbFunctionSubset* function,
- std::vector<uint8_t>::const_iterator* it,
- std::vector<uint8_t>::const_iterator end) {
- // These conditions must be guaranteed by the caller.
- DCHECK(*it != end);
+// Parses a WebUSB Configuration Subset Header:
+// http://wicg.github.io/webusb/#dfn-configuration-subset-header
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | length | type | config value | num functions |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | origin[0] | origin[1] | ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+------
+bool ParseConfiguration(WebUsbConfigurationSubset* configuration,
+ std::vector<uint8_t>::const_iterator* it,
+ std::vector<uint8_t>::const_iterator end) {
+ const uint8_t kDescriptorType = 0x01;
+ const uint8_t kDescriptorMinLength = 4;
+
+ // If this isn't the end of the buffer then there must be at least one byte
+ // available, the length of the descriptor.
+ if (*it == end)
+ return false;
uint8_t length = (*it)[0];
- DCHECK_LE(length, std::distance(*it, end));
- DCHECK_GE(length, 2);
- DCHECK_EQ((*it)[1], kFunctionSubsetDescriptorType);
- if (length != 5) {
+ // Is this a valid Configuration Subset Header? It must be long enough, fit
+ // within the buffer and have the right descriptor type.
+ if (length < kDescriptorMinLength || std::distance(*it, end) < length ||
+ (*it)[1] != kDescriptorType) {
return false;
}
- function->first_interface = (*it)[2];
+ configuration->configuration_value = (*it)[2];
+ uint8_t num_functions = (*it)[3];
+
+ // The next |length - 4| bytes after the mandatory fields are origin indicies.
+ std::advance(*it, kDescriptorMinLength);
+ uint8_t num_origins = length - kDescriptorMinLength;
+ configuration->origin_ids.reserve(num_origins);
+ for (size_t i = 0; i < num_origins; ++i) {
+ uint8_t index = *(*it)++;
+ if (index == 0)
+ return false;
+ configuration->origin_ids.push_back(index);
+ }
- // Validate the Function Subset header.
- uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
- if (length > total_length || total_length > std::distance(*it, end)) {
- return false;
+ // |num_functions| function descriptors then follow the descriptor.
+ for (size_t i = 0; i < num_functions; ++i) {
+ WebUsbFunctionSubset function;
+ if (!ParseFunction(&function, it, end))
+ return false;
+ configuration->functions.push_back(function);
}
- end = *it + total_length;
- std::advance(*it, length);
+ return true;
+}
- while (*it != end) {
- uint8_t length = (*it)[0];
- if (length < 2 || std::distance(*it, end) < length) {
- return false;
+void OnDoneReadingUrls(scoped_ptr<WebUsbAllowedOrigins> allowed_origins,
+ uint8_t landing_page_id,
+ scoped_ptr<std::map<uint8_t, GURL>> url_map,
+ const ReadWebUsbDescriptorsCallback& callback) {
+ for (uint8_t origin_id : allowed_origins->origin_ids) {
+ const auto& it = url_map->find(origin_id);
+ if (it != url_map->end())
+ allowed_origins->origins.push_back(it->second.GetOrigin());
+ }
+
+ for (auto& configuration : allowed_origins->configurations) {
+ for (uint8_t origin_id : configuration.origin_ids) {
+ const auto& it = url_map->find(origin_id);
+ if (it != url_map->end())
+ configuration.origins.push_back(it->second.GetOrigin());
}
- uint8_t type = (*it)[1];
- if (type == kUrlDescriptorType) {
- GURL url;
- if (!ParseUrl(&url, it, end)) {
- return false;
+ for (auto& function : configuration.functions) {
+ for (uint8_t origin_id : function.origin_ids) {
+ const auto& it = url_map->find(origin_id);
+ if (it != url_map->end())
+ function.origins.push_back(it->second.GetOrigin());
}
- function->origins.push_back(url.GetOrigin());
- } else {
- return false;
}
}
- return true;
+ GURL landing_page;
+ if (landing_page_id != 0)
+ landing_page = (*url_map)[landing_page_id];
+
+ callback.Run(std::move(allowed_origins), landing_page);
}
-bool ParseConfiguration(WebUsbConfigurationSubset* configuration,
- std::vector<uint8_t>::const_iterator* it,
- std::vector<uint8_t>::const_iterator end) {
- // These conditions must be guaranteed by the caller.
- DCHECK(*it != end);
- uint8_t length = (*it)[0];
- DCHECK_LE(length, std::distance(*it, end));
- DCHECK_GE(length, 2);
- DCHECK_EQ((*it)[1], kConfigurationSubsetDescriptorType);
+void OnReadUrlDescriptor(std::map<uint8_t, GURL>* url_map,
+ uint8_t index,
+ const base::Closure& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED) {
+ USB_LOG(EVENT) << "Failed to read WebUSB URL descriptor: " << index;
+ callback.Run();
+ return;
+ }
- if (length != 5) {
- return false;
+ GURL url;
+ if (ParseWebUsbUrlDescriptor(
+ std::vector<uint8_t>(buffer->data(), buffer->data() + length),
+ &url)) {
+ (*url_map)[index] = url;
}
+ callback.Run();
+}
- configuration->configuration_value = (*it)[2];
+// Reads the descriptor with |index| from the device, adds the value to
+// |url_map| and then runs |callback|.
+void ReadUrlDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
+ uint8_t vendor_code,
+ std::map<uint8_t, GURL>* url_map,
+ uint8_t index,
+ const base::Closure& callback) {
+ scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(255);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
+ vendor_code, index, kGetUrlRequest, buffer, buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadUrlDescriptor, url_map, index, callback));
+}
- // Validate the Configuration Subset header.
- uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
- if (length > total_length || total_length > std::distance(*it, end)) {
- return false;
+// Reads URL descriptors from the device so that it can fill |allowed_origins|
+// with the GURLs matching the indicies already collected.
+void ReadUrlDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
+ uint8_t vendor_code,
+ uint8_t landing_page_id,
+ const ReadWebUsbDescriptorsCallback& callback,
+ scoped_ptr<WebUsbAllowedOrigins> allowed_origins) {
+ if (!allowed_origins) {
+ callback.Run(nullptr, GURL());
+ return;
}
- end = *it + total_length;
- std::advance(*it, length);
+ std::set<uint8_t> to_request;
+ if (landing_page_id != 0)
+ to_request.insert(landing_page_id);
- while (*it != end) {
- uint8_t length = (*it)[0];
- if (length < 2 || std::distance(*it, end) < length) {
- return false;
+ to_request.insert(allowed_origins->origin_ids.begin(),
+ allowed_origins->origin_ids.end());
+ for (auto& config : allowed_origins->configurations) {
+ to_request.insert(config.origin_ids.begin(), config.origin_ids.end());
+ for (auto& function : config.functions) {
+ to_request.insert(function.origin_ids.begin(), function.origin_ids.end());
}
+ }
- uint8_t type = (*it)[1];
- if (type == kFunctionSubsetDescriptorType) {
- WebUsbFunctionSubset function;
- if (!ParseFunction(&function, it, end)) {
- return false;
- }
- configuration->functions.push_back(function);
- } else if (type == kUrlDescriptorType) {
- GURL url;
- if (!ParseUrl(&url, it, end)) {
- return false;
- }
- configuration->origins.push_back(url.GetOrigin());
- } else {
- return false;
- }
+ scoped_ptr<std::map<uint8_t, GURL>> url_map(new std::map<uint8_t, GURL>());
+ std::map<uint8_t, GURL>* url_map_ptr = url_map.get();
+ base::Closure barrier = base::BarrierClosure(
+ static_cast<int>(to_request.size()),
+ base::Bind(&OnDoneReadingUrls, base::Passed(&allowed_origins),
+ landing_page_id, base::Passed(&url_map), callback));
+
+ for (uint8_t index : to_request) {
+ ReadUrlDescriptor(device_handle, vendor_code, url_map_ptr, index, barrier);
}
+}
- return true;
+void OnReadWebUsbAllowedOrigins(
+ const ReadWebUsbAllowedOriginsCallback& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED) {
+ USB_LOG(EVENT) << "Failed to read WebUSB allowed origins.";
+ callback.Run(nullptr);
+ return;
+ }
+
+ scoped_ptr<WebUsbAllowedOrigins> allowed_origins(new WebUsbAllowedOrigins());
+ if (allowed_origins->Parse(
+ std::vector<uint8_t>(buffer->data(), buffer->data() + length))) {
+ callback.Run(std::move(allowed_origins));
+ } else {
+ callback.Run(nullptr);
+ }
+}
+
+void OnReadWebUsbAllowedOriginsHeader(
+ scoped_refptr<UsbDeviceHandle> device_handle,
+ const ReadWebUsbAllowedOriginsCallback& callback,
+ uint8_t vendor_code,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED || length != 4) {
+ USB_LOG(EVENT) << "Failed to read WebUSB allowed origins header.";
+ callback.Run(nullptr);
+ return;
+ }
+
+ uint16_t new_length = buffer->data()[2] | (buffer->data()[3] << 8);
+ scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
+ vendor_code, 0, kGetAllowedOriginsRequest, new_buffer, new_buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadWebUsbAllowedOrigins, callback));
+}
+
+void ReadWebUsbAllowedOrigins(
+ scoped_refptr<UsbDeviceHandle> device_handle,
+ uint8_t vendor_code,
+ const ReadWebUsbAllowedOriginsCallback& callback) {
+ scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(4);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
+ vendor_code, 0, kGetAllowedOriginsRequest, buffer, buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadWebUsbAllowedOriginsHeader, device_handle, callback,
+ vendor_code));
+}
+
+void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
+ const ReadWebUsbDescriptorsCallback& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED) {
+ USB_LOG(EVENT) << "Failed to read BOS descriptor.";
+ callback.Run(nullptr, GURL());
+ return;
+ }
+
+ WebUsbPlatformCapabilityDescriptor descriptor;
+ if (!descriptor.ParseFromBosDescriptor(
+ std::vector<uint8_t>(buffer->data(), buffer->data() + length))) {
+ callback.Run(nullptr, GURL());
+ return;
+ }
+
+ ReadWebUsbAllowedOrigins(
+ device_handle, descriptor.vendor_code,
+ base::Bind(&ReadUrlDescriptors, device_handle, descriptor.vendor_code,
+ descriptor.landing_page_id, callback));
+}
+
+void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
+ const ReadWebUsbDescriptorsCallback& callback,
+ UsbTransferStatus status,
+ scoped_refptr<net::IOBuffer> buffer,
+ size_t length) {
+ if (status != USB_TRANSFER_COMPLETED || length != 5) {
+ USB_LOG(EVENT) << "Failed to read BOS descriptor header.";
+ callback.Run(nullptr, GURL());
+ return;
+ }
+
+ uint16_t new_length = buffer->data()[2] | (buffer->data()[3] << 8);
+ scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
+ kGetDescriptorRequest, kBosDescriptorType << 8, 0, new_buffer,
+ new_buffer->size(), kControlTransferTimeout,
+ base::Bind(&OnReadBosDescriptor, device_handle, callback));
}
} // namespace
@@ -165,49 +366,59 @@ WebUsbConfigurationSubset::WebUsbConfigurationSubset()
WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {}
-WebUsbDescriptorSet::WebUsbDescriptorSet() {}
-
-WebUsbDescriptorSet::~WebUsbDescriptorSet() {}
-
-bool WebUsbDescriptorSet::Parse(const std::vector<uint8_t>& bytes) {
- if (bytes.size() < 4) {
+WebUsbAllowedOrigins::WebUsbAllowedOrigins() {}
+
+WebUsbAllowedOrigins::~WebUsbAllowedOrigins() {}
+
+// Parses a WebUSB Allowed Origins Header:
+// http://wicg.github.io/webusb/#dfn-allowed-origins-header
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | length | type | total length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | num configs | origin[0] | origin[1] | ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+------
+bool WebUsbAllowedOrigins::Parse(const std::vector<uint8_t>& bytes) {
+ const uint8_t kDescriptorType = 0x00;
+ const uint8_t kDescriptorMinLength = 5;
+
+ // The buffer must be at least the length of this descriptor's mandatory
+ // fields.
+ if (bytes.size() < kDescriptorMinLength)
return false;
- }
- // Validate the descriptor set header.
+ // Validate that the length of this descriptor and the total length of the
+ // entire block of descriptors is consistent with the length of the buffer.
+ uint8_t length = bytes[0];
uint16_t total_length = bytes[2] + (bytes[3] << 8);
- if (bytes[0] != 4 || // bLength
- bytes[1] != kDescriptorSetDescriptorType || // bDescriptorType
- 4 > total_length || total_length > bytes.size()) { // wTotalLength
+ if (length < 5 || length > bytes.size() || // bLength
+ bytes[1] != kDescriptorType || // bDescriptorType
+ total_length < length || total_length > bytes.size()) { // wTotalLength
return false;
}
std::vector<uint8_t>::const_iterator it = bytes.begin();
- std::vector<uint8_t>::const_iterator end = it + total_length;
- std::advance(it, 4);
-
- while (it != bytes.end()) {
- uint8_t length = it[0];
- if (length < 2 || std::distance(it, end) < length) {
+ uint8_t num_configurations = bytes[4];
+
+ // The next |length - 5| bytes after the mandatory fields are origin indicies.
+ std::advance(it, kDescriptorMinLength);
+ uint8_t num_origins = length - kDescriptorMinLength;
+ origin_ids.reserve(num_origins);
+ for (size_t i = 0; i < num_origins; ++i) {
+ uint8_t index = *it++;
+ if (index == 0)
return false;
- }
+ origin_ids.push_back(index);
+ }
- uint8_t type = it[1];
- if (type == kConfigurationSubsetDescriptorType) {
- WebUsbConfigurationSubset configuration;
- if (!ParseConfiguration(&configuration, &it, end)) {
- return false;
- }
- configurations.push_back(configuration);
- } else if (type == kUrlDescriptorType) {
- GURL url;
- if (!ParseUrl(&url, &it, end)) {
- return false;
- }
- origins.push_back(url.GetOrigin());
- } else {
+ // |num_configurations| configuration descriptors then follow the descriptor.
+ for (size_t i = 0; i < num_configurations; ++i) {
+ WebUsbConfigurationSubset configuration;
+ if (!ParseConfiguration(&configuration, &it, bytes.end()))
return false;
- }
+ configurations.push_back(configuration);
}
return true;
@@ -240,7 +451,6 @@ bool WebUsbPlatformCapabilityDescriptor::ParseFromBosDescriptor(
std::advance(it, 5);
uint8_t length = 0;
- bool found_vendor_code = false;
for (size_t i = 0; i < num_device_caps; ++i, std::advance(it, length)) {
if (it == end) {
return false;
@@ -270,8 +480,8 @@ bool WebUsbPlatformCapabilityDescriptor::ParseFromBosDescriptor(
continue;
}
- if (length < 23) {
- // The WebUSB capability descriptor must be at least 23 bytes (to allow
+ if (length < 22) {
+ // The WebUSB capability descriptor must be at least 22 bytes (to allow
// for future versions).
return false;
}
@@ -281,24 +491,74 @@ bool WebUsbPlatformCapabilityDescriptor::ParseFromBosDescriptor(
continue;
}
- // Version 1.0 only defines a single field, bVendorCode.
+ // Version 1.0 defines two fields for a total length of 24 bytes.
+ if (length != 24) {
+ return false;
+ }
+
vendor_code = it[22];
- found_vendor_code = true;
+ landing_page_id = it[23];
+ return true;
}
- return found_vendor_code;
+ return false;
}
+// Parses a WebUSB URL Descriptor:
+// http://wicg.github.io/webusb/#dfn-url-descriptor
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | length | type | prefix | data[0] |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | data[1] | ...
+// +-+-+-+-+-+-+-+-+-+-+-+------
bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output) {
- if (bytes.size() < 2) {
+ const uint8_t kDescriptorType = 0x03;
+ const uint8_t kDescriptorMinLength = 3;
+
+ if (bytes.size() < kDescriptorMinLength) {
return false;
}
+
+ // Validate that the length is consistent and fits within the buffer.
uint8_t length = bytes[0];
- if (length != bytes.size() || bytes[1] != kUrlDescriptorType) {
+ if (length < kDescriptorMinLength || length < bytes.size() ||
+ bytes[1] != kDescriptorType) {
return false;
}
- std::vector<uint8_t>::const_iterator it = bytes.begin();
- return ParseUrl(output, &it, bytes.end());
+
+ // Look up the URL prefix and append the rest of the data in the descriptor.
+ std::string url;
+ switch (bytes[2]) {
+ case 0:
+ url.append("http://");
+ break;
+ case 1:
+ url.append("https://");
+ break;
+ default:
+ return false;
+ }
+ url.append(reinterpret_cast<const char*>(bytes.data() + 3), length - 3);
+
+ *output = GURL(url);
+ if (!output->is_valid()) {
+ return false;
+ }
+
+ return true;
+}
+
+void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
+ const ReadWebUsbDescriptorsCallback& callback) {
+ scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(5);
+ device_handle->ControlTransfer(
+ USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
+ kGetDescriptorRequest, kBosDescriptorType << 8, 0, buffer, buffer->size(),
+ kControlTransferTimeout,
+ base::Bind(&OnReadBosDescriptorHeader, device_handle, callback));
}
} // namespace device
« no previous file with comments | « device/usb/webusb_descriptors.h ('k') | device/usb/webusb_descriptors_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698