1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DEVICE_DESCRIPTION_SERVICE_H_
#define CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DEVICE_DESCRIPTION_SERVICE_H_
#include <memory>
#include <string>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
#include "chrome/browser/media/router/discovery/dial/parsed_dial_device_description.h"
#include "chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser.h"
namespace media_router {
class DeviceDescriptionFetcher;
class SafeDialDeviceDescriptionParser;
// This class fetches and parses device description XML for DIAL devices. Actual
// parsing happens in a separate utility process via SafeDeviceDescriptionParser
// (instead of in this class).
// This class is not sequence safe.
class DeviceDescriptionService {
public:
// Represents cached device description data parsed from device description
// XML.
struct CacheEntry {
CacheEntry();
CacheEntry(const CacheEntry& other);
~CacheEntry();
// The expiration time from the cache.
base::Time expire_time;
// The device description version number (non-negative).
int32_t config_id;
// Parsed device description data from XML.
ParsedDialDeviceDescription description_data;
};
// Called if parsing device description XML in utility process succeeds, and
// all fields are valid.
// |device_data|: The device to look up.
// |description_data|: Device description data from device description XML.
using DeviceDescriptionParseSuccessCallback = base::RepeatingCallback<void(
const DialDeviceData& device_data,
const ParsedDialDeviceDescription& description_data)>;
// Called if parsing device description XML in utility process fails, or some
// parsed fields are missing or invalid.
using DeviceDescriptionParseErrorCallback =
base::RepeatingCallback<void(const DialDeviceData& device_data,
const std::string& error_message)>;
DeviceDescriptionService(
const DeviceDescriptionParseSuccessCallback& success_cb,
const DeviceDescriptionParseErrorCallback& error_cb);
DeviceDescriptionService(const DeviceDescriptionService&) = delete;
DeviceDescriptionService& operator=(const DeviceDescriptionService&) = delete;
virtual ~DeviceDescriptionService();
// For each device in |devices|, if there is a valid cache entry for it, call
// |success_cb_| with cached device description; otherwise start fetching
// device description XML and parsing XML in utility process. Call
// |success_cb_| if both fetching and parsing succeeds; otherwise call
// |error_cb_|.
virtual void GetDeviceDescriptions(
const std::vector<DialDeviceData>& devices);
protected:
// Parses the device description data in |description_data| and invokes
// OnParsedDeviceDescription() when done, passing |device_data| along.
// Made visible so it can be overwritten in tests.
virtual void ParseDeviceDescription(
const DialDeviceData& device_data,
const DialDeviceDescriptionData& description_data);
// Overridden by unit tests.
virtual std::unique_ptr<DeviceDescriptionFetcher> CreateFetcher(
const DialDeviceData& device_data,
base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
base::OnceCallback<void(const std::string&)> error_cb);
private:
friend class DeviceDescriptionServiceTest;
friend class TestDeviceDescriptionService;
FRIEND_TEST_ALL_PREFIXES(DeviceDescriptionServiceTest,
TestGetDeviceDescriptionRemoveOutDatedFetchers);
FRIEND_TEST_ALL_PREFIXES(DeviceDescriptionServiceTest,
TestGetDeviceDescriptionFetchURL);
FRIEND_TEST_ALL_PREFIXES(DeviceDescriptionServiceTest,
TestGetDeviceDescriptionFetchURLError);
FRIEND_TEST_ALL_PREFIXES(DeviceDescriptionServiceTest,
TestCleanUpCacheEntries);
FRIEND_TEST_ALL_PREFIXES(DeviceDescriptionServiceTest,
TestSafeParserProperlyCreated);
// Checks the cache for a valid device description. If the entry is found but
// is expired, it is removed from the cache. Returns cached entry of
// parsed device description. Returns nullptr if cache entry does not exist or
// is not valid.
// |device_data|: The device to look up.
const CacheEntry* CheckAndUpdateCache(const DialDeviceData& device_data);
// Issues a HTTP GET request for the device description. No-op if there is
// already a pending request.
// |device_data|: The device to look up.
void FetchDeviceDescription(const DialDeviceData& device_data);
// Invoked when HTTP GET request finishes.
// |device_data|: Device data initiating the HTTP request.
// |description_data|: Response from HTTP request.
void OnDeviceDescriptionFetchComplete(
const DialDeviceData& device_data,
const DialDeviceDescriptionData& description_data);
// Invoked when HTTP GET request fails.
// |device_data|: Device data initiating the HTTP request.
// |error_message|: Error message from HTTP request.
void OnDeviceDescriptionFetchError(const DialDeviceData& device_data,
const std::string& error_message);
// Invoked when SafeDialDeviceDescriptionParser finishes parsing device
// description XML.
// |device_data|: Device data initiating XML parsing in utility process.
// |device_description|: Parsed device description from utility process,
// empty if parsing failed.
// |parsing_error|: error encountered while parsing DIAL device description.
void OnParsedDeviceDescription(
const DialDeviceData& device_data,
const ParsedDialDeviceDescription& device_description,
SafeDialDeviceDescriptionParser::ParsingResult parsing_result);
// Remove expired cache entries from |description_map_|.
void CleanUpCacheEntries();
// Used by unit tests.
virtual base::Time GetNow();
// Map of current device description fetches in progress, keyed by device
// label.
std::map<std::string, std::unique_ptr<DeviceDescriptionFetcher>>
device_description_fetcher_map_;
// The number of device description still pending to be parsed.
uint32_t pending_device_count_ = 0U;
// Map of current cached device descriptions, keyed by device label.
std::map<std::string, CacheEntry> description_cache_;
// See comments for DeviceDescriptionParseSuccessCallback.
DeviceDescriptionParseSuccessCallback success_cb_;
// See comments for DeviceDescriptionParseErrorCallback.
DeviceDescriptionParseErrorCallback error_cb_;
// Timer for clean up expired cache entries.
std::unique_ptr<base::RepeatingTimer> clean_up_timer_;
// Safe DIAL parser. Does the parsing in a utility process.
SafeDialDeviceDescriptionParser device_description_parser_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_DISCOVERY_DIAL_DEVICE_DESCRIPTION_SERVICE_H_
|