| Index: components/certificate_transparency/log_dns_client.cc
|
| diff --git a/components/certificate_transparency/log_dns_client.cc b/components/certificate_transparency/log_dns_client.cc
|
| index 60e82304fbe1e98e80c42862318cd6333cf21077..cd2ef9c7b818f7cb971e2f9d2543de2bccf71d4c 100644
|
| --- a/components/certificate_transparency/log_dns_client.cc
|
| +++ b/components/certificate_transparency/log_dns_client.cc
|
| @@ -3,10 +3,11 @@
|
| // found in the LICENSE file.
|
|
|
| #include "components/certificate_transparency/log_dns_client.h"
|
|
|
| #include "base/bind.h"
|
| +#include "base/callback_helpers.h"
|
| #include "base/format_macros.h"
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| #include "base/memory/ptr_util.h"
|
| #include "base/strings/string_number_conversions.h"
|
| @@ -14,11 +15,10 @@
|
| #include "base/strings/stringprintf.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "base/time/time.h"
|
| #include "components/base32/base32.h"
|
| #include "crypto/sha2.h"
|
| -#include "net/base/net_errors.h"
|
| #include "net/cert/merkle_audit_proof.h"
|
| #include "net/dns/dns_client.h"
|
| #include "net/dns/dns_config_service.h"
|
| #include "net/dns/dns_protocol.h"
|
| #include "net/dns/dns_response.h"
|
| @@ -40,15 +40,15 @@ bool ParseTxtResponse(const net::DnsResponse& response, std::string* txt) {
|
| net::DnsRecordParser parser = response.Parser();
|
| // We don't care about the creation time, since we're going to throw
|
| // |parsed_record| away as soon as we've extracted the payload, so provide
|
| // the "null" time.
|
| auto parsed_record = net::RecordParsed::CreateFrom(&parser, base::Time());
|
| - if (parsed_record == nullptr)
|
| + if (!parsed_record)
|
| return false;
|
|
|
| auto* txt_record = parsed_record->rdata<net::TxtRecordRdata>();
|
| - if (txt_record == nullptr)
|
| + if (!txt_record)
|
| return false;
|
|
|
| // The draft CT-over-DNS RFC says that there MUST be exactly one string in the
|
| // TXT record.
|
| if (txt_record->texts().size() != 1)
|
| @@ -101,223 +101,289 @@ bool ParseAuditPath(const net::DnsResponse& response,
|
| // Encapsulates the state machine required to get an audit proof from a Merkle
|
| // leaf hash. This requires a DNS request to obtain the leaf index, then a
|
| // series of DNS requests to get the nodes of the proof.
|
| class LogDnsClient::AuditProofQuery {
|
| public:
|
| - using CompletionCallback =
|
| - base::Callback<void(int net_error, AuditProofQuery* query)>;
|
| -
|
| // The LogDnsClient is guaranteed to outlive the AuditProofQuery, so it's safe
|
| // to leave ownership of |dns_client| with LogDnsClient.
|
| AuditProofQuery(net::DnsClient* dns_client,
|
| const std::string& domain_for_log,
|
| uint64_t tree_size,
|
| const net::NetLogWithSource& net_log);
|
|
|
| - // Begins the process of getting an audit proof for the CT log entry with a
|
| - // leaf hash of |leaf_hash|. The |callback| will be invoked when finished.
|
| - void Start(base::StringPiece leaf_hash, CompletionCallback callback);
|
| -
|
| - // Transfers the audit proof to the caller.
|
| - // Only call this once the query has completed, otherwise the proof will be
|
| - // incomplete.
|
| - std::unique_ptr<net::ct::MerkleAuditProof> TakeProof();
|
| + // Begins the process of getting an audit |proof| for the CT log entry with a
|
| + // leaf hash of |leaf_hash|. If it cannot be obtained synchronously,
|
| + // net::ERR_IO_PENDING will be returned and |callback| will be invoked when
|
| + // the operation has completed asynchronously.
|
| + // Ownership of |proof| remains with the caller, and it must not be deleted
|
| + // until the operation is complete.
|
| + net::Error Start(std::string leaf_hash,
|
| + const net::CompletionCallback& callback,
|
| + net::ct::MerkleAuditProof* proof);
|
|
|
| private:
|
| - // Requests the leaf index of the CT log entry with |leaf_hash|.
|
| - void QueryLeafIndex(base::StringPiece leaf_hash);
|
| -
|
| - // Processes the response to a leaf index request.
|
| - // The received leaf index will be added to the proof.
|
| - void QueryLeafIndexComplete(net::DnsTransaction* transaction,
|
| - int net_error,
|
| - const net::DnsResponse* response);
|
| -
|
| - // Queries a CT log to retrieve part of an audit proof. The |node_index|
|
| - // indicates which node of the audit proof/ should be requested. The CT log
|
| - // may return up to 7 nodes, starting from |node_index| (this is the maximum
|
| - // that will fit in a DNS UDP packet). The nodes will be appended to the
|
| - // proof.
|
| - void QueryAuditProofNodes(uint64_t node_index);
|
| -
|
| - // Processes the response to an audit proof request.
|
| - // This will contain some, but not necessarily all, of the audit proof nodes.
|
| - void QueryAuditProofNodesComplete(net::DnsTransaction* transaction,
|
| - int net_error,
|
| - const net::DnsResponse* response);
|
| + enum class State {
|
| + NONE,
|
| + REQUEST_LEAF_INDEX,
|
| + REQUEST_LEAF_INDEX_COMPLETE,
|
| + REQUEST_AUDIT_PROOF_NODES,
|
| + REQUEST_AUDIT_PROOF_NODES_COMPLETE,
|
| + };
|
|
|
| + net::Error DoLoop(net::Error result);
|
| +
|
| + // When a DnsTransaction completes, store the response and resume the state
|
| + // machine. It is safe to store a pointer to |response| because |transaction|
|
| + // is kept alive in |current_dns_transaction_|.
|
| + void OnDnsTransactionComplete(net::DnsTransaction* transaction,
|
| + int net_error,
|
| + const net::DnsResponse* response);
|
| +
|
| + // Requests the leaf index for the CT log entry with |leaf_hash_|.
|
| + net::Error RequestLeafIndex();
|
| +
|
| + // Stores the received leaf index in |proof_->leaf_index|.
|
| + // If successful, the audit proof nodes will be requested next.
|
| + net::Error RequestLeafIndexComplete(net::Error result);
|
| +
|
| + // Requests the next batch of audit proof nodes from a CT log.
|
| + // The index of the first node required is determined by looking at how many
|
| + // nodes are already in |proof_->nodes|.
|
| + // The CT log may return up to 7 nodes - this is the maximum allowed by the
|
| + // CT-over-DNS draft RFC, as a TXT RDATA string can have a maximum length of
|
| + // 255 bytes and each node is 32 bytes long (a SHA-256 hash).
|
| + //
|
| + // The performance of this could be improved by sending all of the expected
|
| + // requests up front. Each response can contain a maximum of 7 audit path
|
| + // nodes, so for an audit proof of size 20, it could send 3 queries (for nodes
|
| + // 0-6, 7-13 and 14-19) immediately. Currently, it sends only the first and
|
| + // then, based on the number of nodes received, sends the next query.
|
| + // The complexity of the code would increase though, as it would need to
|
| + // detect gaps in the audit proof caused by the server not responding with the
|
| + // anticipated number of nodes. It would also undermine LogDnsClient's ability
|
| + // to rate-limit DNS requests.
|
| + net::Error RequestAuditProofNodes();
|
| +
|
| + // Appends the received audit proof nodes to |proof_->nodes|.
|
| + // If any nodes are missing, another request will follow this one.
|
| + net::Error RequestAuditProofNodesComplete(net::Error result);
|
| +
|
| + // Sends a TXT record request for the domain |qname|.
|
| + // Returns true if the request could be started.
|
| + // OnDnsTransactionComplete() will be invoked with the result of the request.
|
| + bool StartDnsTransaction(const std::string& qname);
|
| +
|
| + // The next state that this query will enter.
|
| + State next_state_;
|
| + // The DNS domain of the CT log that is being queried.
|
| std::string domain_for_log_;
|
| + // The Merkle leaf hash of the CT log entry an audit proof is required for.
|
| + std::string leaf_hash_;
|
| + // The size of the CT log's tree, from which the proof is requested.
|
| // TODO(robpercival): Remove |tree_size| once |proof_| has a tree_size member.
|
| uint64_t tree_size_;
|
| - std::unique_ptr<net::ct::MerkleAuditProof> proof_;
|
| - CompletionCallback callback_;
|
| + // The audit proof to populate.
|
| + net::ct::MerkleAuditProof* proof_;
|
| + // The callback to invoke when the query is complete.
|
| + net::CompletionCallback callback_;
|
| + // The DnsClient to use for sending DNS requests to the CT log.
|
| net::DnsClient* dns_client_;
|
| + // The most recent DNS request. Null if no DNS requests have been made.
|
| std::unique_ptr<net::DnsTransaction> current_dns_transaction_;
|
| + // The most recent DNS response. Only valid so long as the corresponding DNS
|
| + // request is stored in |current_dns_transaction_|.
|
| + const net::DnsResponse* last_dns_response_;
|
| + // The NetLog that DNS transactions will log to.
|
| net::NetLogWithSource net_log_;
|
| + // Produces WeakPtrs to |this| for binding callbacks.
|
| base::WeakPtrFactory<AuditProofQuery> weak_ptr_factory_;
|
| };
|
|
|
| LogDnsClient::AuditProofQuery::AuditProofQuery(
|
| net::DnsClient* dns_client,
|
| const std::string& domain_for_log,
|
| uint64_t tree_size,
|
| const net::NetLogWithSource& net_log)
|
| - : domain_for_log_(domain_for_log),
|
| + : next_state_(State::NONE),
|
| + domain_for_log_(domain_for_log),
|
| tree_size_(tree_size),
|
| dns_client_(dns_client),
|
| net_log_(net_log),
|
| weak_ptr_factory_(this) {
|
| DCHECK(dns_client_);
|
| DCHECK(!domain_for_log_.empty());
|
| }
|
|
|
| -void LogDnsClient::AuditProofQuery::Start(base::StringPiece leaf_hash,
|
| - CompletionCallback callback) {
|
| - current_dns_transaction_.reset();
|
| - proof_ = base::MakeUnique<net::ct::MerkleAuditProof>();
|
| +// |leaf_hash| is not a const-ref to allow callers to std::move that string into
|
| +// the method, avoiding the need to make a copy.
|
| +net::Error LogDnsClient::AuditProofQuery::Start(
|
| + std::string leaf_hash,
|
| + const net::CompletionCallback& callback,
|
| + net::ct::MerkleAuditProof* proof) {
|
| + // It should not already be in progress.
|
| + DCHECK_EQ(State::NONE, next_state_);
|
| + proof_ = proof;
|
| + leaf_hash_ = std::move(leaf_hash);
|
| callback_ = callback;
|
| - QueryLeafIndex(leaf_hash);
|
| + // The first step in the query is to request the leaf index corresponding to
|
| + // |leaf_hash| from the CT log.
|
| + next_state_ = State::REQUEST_LEAF_INDEX;
|
| + // Begin the state machine.
|
| + return DoLoop(net::OK);
|
| }
|
|
|
| -std::unique_ptr<net::ct::MerkleAuditProof>
|
| -LogDnsClient::AuditProofQuery::TakeProof() {
|
| - return std::move(proof_);
|
| +net::Error LogDnsClient::AuditProofQuery::DoLoop(net::Error result) {
|
| + CHECK_NE(State::NONE, next_state_);
|
| + do {
|
| + State state = next_state_;
|
| + next_state_ = State::NONE;
|
| + switch (state) {
|
| + case State::REQUEST_LEAF_INDEX:
|
| + result = RequestLeafIndex();
|
| + break;
|
| + case State::REQUEST_LEAF_INDEX_COMPLETE:
|
| + result = RequestLeafIndexComplete(result);
|
| + break;
|
| + case State::REQUEST_AUDIT_PROOF_NODES:
|
| + result = RequestAuditProofNodes();
|
| + break;
|
| + case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE:
|
| + result = RequestAuditProofNodesComplete(result);
|
| + break;
|
| + case State::NONE:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + } while (result != net::ERR_IO_PENDING && next_state_ != State::NONE);
|
| +
|
| + return result;
|
| +}
|
| +
|
| +void LogDnsClient::AuditProofQuery::OnDnsTransactionComplete(
|
| + net::DnsTransaction* transaction,
|
| + int net_error,
|
| + const net::DnsResponse* response) {
|
| + DCHECK_EQ(current_dns_transaction_.get(), transaction);
|
| + last_dns_response_ = response;
|
| + net::Error result = DoLoop(static_cast<net::Error>(net_error));
|
| +
|
| + // If DoLoop() indicates that I/O is pending, don't invoke the completion
|
| + // callback. OnDnsTransactionComplete() will be invoked again once the I/O
|
| + // is complete, and can invoke the completion callback then if appropriate.
|
| + if (result != net::ERR_IO_PENDING) {
|
| + // The callback will delete this query (now that it has finished), so copy
|
| + // |callback_| before running it so that it is not deleted along with the
|
| + // query, mid-callback-execution (which would result in a crash).
|
| + base::ResetAndReturn(&callback_).Run(result);
|
| + }
|
| }
|
|
|
| -void LogDnsClient::AuditProofQuery::QueryLeafIndex(
|
| - base::StringPiece leaf_hash) {
|
| - std::string encoded_leaf_hash =
|
| - base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING);
|
| +net::Error LogDnsClient::AuditProofQuery::RequestLeafIndex() {
|
| + std::string encoded_leaf_hash = base32::Base32Encode(
|
| + leaf_hash_, base32::Base32EncodePolicy::OMIT_PADDING);
|
| DCHECK_EQ(encoded_leaf_hash.size(), 52u);
|
|
|
| std::string qname = base::StringPrintf(
|
| - "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.data());
|
| + "%s.hash.%s.", encoded_leaf_hash.c_str(), domain_for_log_.c_str());
|
|
|
| - net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
|
| - if (factory == nullptr) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED,
|
| - base::Unretained(this)));
|
| - return;
|
| + if (!StartDnsTransaction(qname)) {
|
| + return net::ERR_NAME_RESOLUTION_FAILED;
|
| }
|
|
|
| - net::DnsTransactionFactory::CallbackType transaction_callback =
|
| - base::Bind(&LogDnsClient::AuditProofQuery::QueryLeafIndexComplete,
|
| - weak_ptr_factory_.GetWeakPtr());
|
| -
|
| - current_dns_transaction_ = factory->CreateTransaction(
|
| - qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_);
|
| -
|
| - current_dns_transaction_->Start();
|
| + next_state_ = State::REQUEST_LEAF_INDEX_COMPLETE;
|
| + return net::ERR_IO_PENDING;
|
| }
|
|
|
| -void LogDnsClient::AuditProofQuery::QueryLeafIndexComplete(
|
| - net::DnsTransaction* transaction,
|
| - int net_error,
|
| - const net::DnsResponse* response) {
|
| - // If we've received no response but no net::error either (shouldn't
|
| - // happen),
|
| - // report the response as invalid.
|
| - if (response == nullptr && net_error == net::OK) {
|
| - net_error = net::ERR_INVALID_RESPONSE;
|
| +// Stores the received leaf index in |proof_->leaf_index|.
|
| +// If successful, the audit proof nodes will be requested next.
|
| +net::Error LogDnsClient::AuditProofQuery::RequestLeafIndexComplete(
|
| + net::Error result) {
|
| + if (result != net::OK) {
|
| + return result;
|
| }
|
|
|
| - if (net_error != net::OK) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net_error, base::Unretained(this)));
|
| - return;
|
| - }
|
| -
|
| - if (!ParseLeafIndex(*response, &proof_->leaf_index)) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE,
|
| - base::Unretained(this)));
|
| - return;
|
| + DCHECK(last_dns_response_);
|
| + if (!ParseLeafIndex(*last_dns_response_, &proof_->leaf_index)) {
|
| + return net::ERR_DNS_MALFORMED_RESPONSE;
|
| }
|
|
|
| // Reject leaf index if it is out-of-range.
|
| // This indicates either:
|
| // a) the wrong tree_size was provided.
|
| // b) the wrong leaf hash was provided.
|
| // c) there is a bug server-side.
|
| // The first two are more likely, so return ERR_INVALID_ARGUMENT.
|
| if (proof_->leaf_index >= tree_size_) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net::ERR_INVALID_ARGUMENT,
|
| - base::Unretained(this)));
|
| - return;
|
| + return net::ERR_INVALID_ARGUMENT;
|
| }
|
|
|
| - // QueryAuditProof for the first batch of audit proof_ nodes (i.e. starting
|
| - // from 0).
|
| - QueryAuditProofNodes(0 /* start node index */);
|
| + next_state_ = State::REQUEST_AUDIT_PROOF_NODES;
|
| + return net::OK;
|
| }
|
|
|
| -void LogDnsClient::AuditProofQuery::QueryAuditProofNodes(uint64_t node_index) {
|
| - DCHECK_LT(proof_->leaf_index, tree_size_);
|
| - DCHECK_LT(node_index,
|
| - net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_));
|
| +net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodes() {
|
| + // Test pre-conditions (should be guaranteed by DNS response validation).
|
| + if (proof_->leaf_index >= tree_size_ ||
|
| + proof_->nodes.size() >=
|
| + net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_)) {
|
| + return net::ERR_UNEXPECTED;
|
| + }
|
|
|
| std::string qname = base::StringPrintf(
|
| - "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".tree.%s.", node_index,
|
| - proof_->leaf_index, tree_size_, domain_for_log_.data());
|
| + "%zu.%" PRIu64 ".%" PRIu64 ".tree.%s.", proof_->nodes.size(),
|
| + proof_->leaf_index, tree_size_, domain_for_log_.c_str());
|
|
|
| - net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
|
| - if (factory == nullptr) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net::Error::ERR_NAME_RESOLUTION_FAILED,
|
| - base::Unretained(this)));
|
| - return;
|
| + if (!StartDnsTransaction(qname)) {
|
| + return net::ERR_NAME_RESOLUTION_FAILED;
|
| }
|
|
|
| - net::DnsTransactionFactory::CallbackType transaction_callback =
|
| - base::Bind(&LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete,
|
| - weak_ptr_factory_.GetWeakPtr());
|
| -
|
| - current_dns_transaction_ = factory->CreateTransaction(
|
| - qname, net::dns_protocol::kTypeTXT, transaction_callback, net_log_);
|
| - current_dns_transaction_->Start();
|
| + next_state_ = State::REQUEST_AUDIT_PROOF_NODES_COMPLETE;
|
| + return net::ERR_IO_PENDING;
|
| }
|
|
|
| -void LogDnsClient::AuditProofQuery::QueryAuditProofNodesComplete(
|
| - net::DnsTransaction* transaction,
|
| - int net_error,
|
| - const net::DnsResponse* response) {
|
| - // If we receive no response but no net::error either (shouldn't happen),
|
| - // report the response as invalid.
|
| - if (response == nullptr && net_error == net::OK) {
|
| - net_error = net::ERR_INVALID_RESPONSE;
|
| - }
|
| -
|
| - if (net_error != net::OK) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net_error, base::Unretained(this)));
|
| - return;
|
| +net::Error LogDnsClient::AuditProofQuery::RequestAuditProofNodesComplete(
|
| + net::Error result) {
|
| + if (result != net::OK) {
|
| + return result;
|
| }
|
|
|
| const uint64_t audit_path_length =
|
| net::ct::CalculateAuditPathLength(proof_->leaf_index, tree_size_);
|
| +
|
| // The calculated |audit_path_length| can't ever be greater than 64, so
|
| // deriving the amount of memory to reserve from the untrusted |leaf_index|
|
| // is safe.
|
| proof_->nodes.reserve(audit_path_length);
|
|
|
| - if (!ParseAuditPath(*response, proof_.get())) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net::ERR_DNS_MALFORMED_RESPONSE,
|
| - base::Unretained(this)));
|
| - return;
|
| + DCHECK(last_dns_response_);
|
| + if (!ParseAuditPath(*last_dns_response_, proof_)) {
|
| + return net::ERR_DNS_MALFORMED_RESPONSE;
|
| }
|
|
|
| - const uint64_t audit_path_nodes_received = proof_->nodes.size();
|
| - if (audit_path_nodes_received < audit_path_length) {
|
| - QueryAuditProofNodes(audit_path_nodes_received);
|
| - return;
|
| + // Keep requesting more proof nodes until all of them are received.
|
| + if (proof_->nodes.size() < audit_path_length) {
|
| + next_state_ = State::REQUEST_AUDIT_PROOF_NODES;
|
| }
|
|
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback_, net::OK, base::Unretained(this)));
|
| + return net::OK;
|
| +}
|
| +
|
| +bool LogDnsClient::AuditProofQuery::StartDnsTransaction(
|
| + const std::string& qname) {
|
| + net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
|
| + if (!factory) {
|
| + return false;
|
| + }
|
| +
|
| + current_dns_transaction_ = factory->CreateTransaction(
|
| + qname, net::dns_protocol::kTypeTXT,
|
| + base::Bind(&LogDnsClient::AuditProofQuery::OnDnsTransactionComplete,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + net_log_);
|
| +
|
| + current_dns_transaction_->Start();
|
| + return true;
|
| }
|
|
|
| LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
|
| const net::NetLogWithSource& net_log,
|
| size_t max_concurrent_queries)
|
| @@ -340,69 +406,56 @@ void LogDnsClient::OnDNSChanged() {
|
|
|
| void LogDnsClient::OnInitialDNSConfigRead() {
|
| UpdateDnsConfig();
|
| }
|
|
|
| -// The performance of this could be improved by sending all of the expected
|
| -// queries up front. Each response can contain a maximum of 7 audit path nodes,
|
| -// so for an audit proof of size 20, it could send 3 queries (for nodes 0-6,
|
| -// 7-13 and 14-19) immediately. Currently, it sends only the first and then,
|
| -// based on the number of nodes received, sends the next query. The complexity
|
| -// of the code would increase though, as it would need to detect gaps in the
|
| -// audit proof caused by the server not responding with the anticipated number
|
| -// of nodes. Ownership of the proof would need to change, as it would be shared
|
| -// between simultaneous DNS transactions. Throttling of queries would also need
|
| -// to take into account this increase in parallelism.
|
| -void LogDnsClient::QueryAuditProof(const std::string& domain_for_log,
|
| - base::StringPiece leaf_hash,
|
| - uint64_t tree_size,
|
| - const AuditProofCallback& callback) {
|
| +// |leaf_hash| is not a const-ref to allow callers to std::move that string into
|
| +// the method, avoiding LogDnsClient::AuditProofQuery having to make a copy.
|
| +net::Error LogDnsClient::QueryAuditProof(
|
| + base::StringPiece domain_for_log,
|
| + std::string leaf_hash,
|
| + uint64_t tree_size,
|
| + net::ct::MerkleAuditProof* proof,
|
| + const net::CompletionCallback& callback) {
|
| + DCHECK(proof);
|
| +
|
| if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
|
| - return;
|
| + return net::ERR_INVALID_ARGUMENT;
|
| }
|
|
|
| if (HasMaxConcurrentQueriesInProgress()) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(callback, net::Error::ERR_TEMPORARILY_THROTTLED, nullptr));
|
| - return;
|
| + return net::ERR_TEMPORARILY_THROTTLED;
|
| }
|
|
|
| - audit_proof_queries_.emplace_back(new AuditProofQuery(
|
| - dns_client_.get(), domain_for_log, tree_size, net_log_));
|
| + AuditProofQuery* query = new AuditProofQuery(
|
| + dns_client_.get(), domain_for_log.as_string(), tree_size, net_log_);
|
| + // Transfers ownership of |query| to |audit_proof_queries_|.
|
| + audit_proof_queries_.emplace_back(query);
|
|
|
| - AuditProofQuery::CompletionCallback internal_callback =
|
| - base::Bind(&LogDnsClient::QueryAuditProofComplete,
|
| - weak_ptr_factory_.GetWeakPtr(), callback);
|
| -
|
| - audit_proof_queries_.back()->Start(leaf_hash, internal_callback);
|
| + return query->Start(std::move(leaf_hash),
|
| + base::Bind(&LogDnsClient::QueryAuditProofComplete,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + base::Unretained(query), callback),
|
| + proof);
|
| }
|
|
|
| -void LogDnsClient::QueryAuditProofComplete(const AuditProofCallback& callback,
|
| - int result,
|
| - AuditProofQuery* query) {
|
| +void LogDnsClient::QueryAuditProofComplete(
|
| + AuditProofQuery* query,
|
| + const net::CompletionCallback& callback,
|
| + int net_error) {
|
| DCHECK(query);
|
|
|
| - std::unique_ptr<net::ct::MerkleAuditProof> proof;
|
| - if (result == net::OK) {
|
| - proof = query->TakeProof();
|
| - }
|
| -
|
| // Finished with the query - destroy it.
|
| auto query_iterator =
|
| std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
|
| [query](const std::unique_ptr<AuditProofQuery>& p) {
|
| return p.get() == query;
|
| });
|
| DCHECK(query_iterator != audit_proof_queries_.end());
|
| audit_proof_queries_.erase(query_iterator);
|
|
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(callback, result, base::Passed(&proof)));
|
| + callback.Run(net_error);
|
| }
|
|
|
| bool LogDnsClient::HasMaxConcurrentQueriesInProgress() const {
|
| return max_concurrent_queries_ != 0 &&
|
| audit_proof_queries_.size() >= max_concurrent_queries_;
|
|
|