2
* Copyright 2013 Google Inc.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
// Author: jmaessen@google.com (Jan Maessen)
19
// This contains some utilities for working with the critical_keys
20
// proto, and for updating support values. This is primarily used by
21
// CriticalSelectorFinder and CriticalImagesFinder. These finders use the
22
// critical_keys proto to store a "support value" for each possible key (image
23
// URL or selector name) in the property cache. When a beacon result arrives,
24
// the support for each critical key in the result is increased by
25
// support_interval. When a new beacon is sent, existing support is decayed by
26
// multiplying by support_interval/(support_interval+1) and rounding down. This
27
// means that a single key returned with a beacon will be considered critical
28
// until support_interval subsequent beacons have been injected. Because
29
// support decays exponentially, repeated support for a key in multiple beacon
30
// results cause that key to be considered critical longer: two beacon results
31
// will expire after somewhat less than twice as long, three after rather less
32
// than three times as long, and so forth. This class also handles converting
33
// over old protobufs that did not use the support system.
35
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_CRITICAL_FINDER_SUPPORT_UTIL_H_
36
#define NET_INSTAWEB_REWRITER_PUBLIC_CRITICAL_FINDER_SUPPORT_UTIL_H_
38
#include "net/instaweb/rewriter/critical_keys.pb.h"
39
#include "net/instaweb/util/public/basictypes.h"
40
#include "net/instaweb/util/public/property_cache.h"
41
#include "net/instaweb/util/public/string.h"
42
#include "net/instaweb/util/public/string_util.h"
43
#include "net/instaweb/util/public/timer.h"
45
namespace net_instaweb {
47
// The amount of time after generating a nonce that we will accept it as valid.
48
// This keeps an attacker from accumulating large numbers of valid nonces to
49
// send many beacon responses at once.
50
const int64 kBeaconTimeoutIntervalMs = Timer::kMinuteMs;
52
// The number of valid beacons received that will switch from high frequency to
53
// low frequency beaconing.
54
const int64 kHighFreqBeaconCount = 3;
56
// The multiplier to apply to RewriteOptions::beacon_reinstrument_time_sec() to
57
// determine the low frequency beaconing interval. For example, the default
58
// value rebeaconing value is 5 seconds, so we will rebeacon every 5 seconds in
59
// high frequency mode, and every 500 seconds (~8 minutes) in low frequency
61
const int64 kLowFreqBeaconMult = 100;
63
// The limit on the number of nonces that can expire before we stop trying to do
64
// high frequency beaconing. This is a signal that beacons are not configured
65
// correctly and so we drop into low frequency beaconing mode.
66
const int64 kNonceExpirationLimit = 5;
78
struct BeaconMetadata {
79
BeaconMetadata() : status(kDoNotBeacon) { }
84
// Check whether the given nonce is valid, invalidating any expired nonce
85
// entries we might encounter. To avoid the need to copy and clear the nonce
86
// list, we invalidate the entry used and any expired entries by clearing the
87
// nonce value and timestamp. These entries will be reused by
88
// AddNonceToCriticalSelectors.
89
bool ValidateAndExpireNonce(int64 now_ms, StringPiece nonce,
90
CriticalKeys* critical_keys);
92
// Generate a list of the critical keys from a proto, storing it into keys.
93
// Takes into account legacy keys that may have been added before. A key is
94
// considered critical if its support is at least support_percentage of the
95
// maximum possible support value (which ramps up as beacon results arrive).
96
// When support_percentage = 0, any support is sufficient; when
97
// support_percentage = 100 all beacon results must support criticality.
98
void GetCriticalKeysFromProto(int64 support_percentage,
99
const CriticalKeys& critical_keys,
102
// Add support for new_set to existing support. The new_set should be obtained
103
// from a fully-validated beacon result -- this means PrepareForBeaconInsertion
104
// should have been called if required, and the resulting nonce should have been
105
// checked. If require_prior_support then there must be an existing support
106
// entry (possibly 0) for new support to be registered.
107
void UpdateCriticalKeys(bool require_prior_support,
108
const StringSet& new_set, int support_value,
109
CriticalKeys* critical_keys);
111
bool ShouldBeacon(const CriticalKeys& proto, const RewriteDriver& driver);
113
// Update the property cache with a new set of keys. This will update the
114
// support value for the new keys. If require_prior_support is set, any keys
115
// that are not already present in the property cache will be ignored (to
116
// prevent spurious keys from being injected). Note that it only increases the
117
// support value for the new keys, it does not decay values that are not
118
// present. PrepareForBeaconInsertion should have been called previously if
119
// !should_replace_prior_result and nonces must be checked.
120
void WriteCriticalKeysToPropertyCache(
121
const StringSet& new_keys, StringPiece nonce, int support_interval,
122
bool should_replace_prior_result, bool require_prior_support,
123
StringPiece property_name, const PropertyCache* cache,
124
const PropertyCache::Cohort* cohort, AbstractPropertyPage* page,
125
MessageHandler* message_handler, Timer* timer);
127
// Given a set of candidate critical keys, decide whether beaconing should take
128
// place. We should *always* beacon if there's new critical key data. Otherwise
129
// re-beaconing is based on a time and request interval, and 2 modes of
130
// beaconing frequency are supported. At first, beaconing occurs at a
131
// high frequency until we have collected kHighFreqBeaconCount beacons; after
132
// that, we transition into low frequency beaconing mode, where beaconing occurs
133
// less often. We also track the number of expired nonces since the last valid
134
// beacon was received to see if beaconing is set up correctly, and if it looks
135
// like it isn't, only do low frequency beaconing. Sets status and nonce
136
// appropriately in *result (nonce will be empty if no nonce is required). If
137
// candidate keys are not required, keys may be empty (but new candidate
138
// detection will not occur). If result->status != kDontBeacon, caller should
139
// write proto back to the property cache using UpdateInPropertyCache.
140
void PrepareForBeaconInsertionHelper(CriticalKeys* proto,
141
NonceGenerator* nonce_generator,
142
RewriteDriver* driver,
143
bool using_candidate_key_detection,
144
BeaconMetadata* result);
146
// Update the candidate key set in proto. If new candidate keys are detected,
147
// they are inserted into proto with a support value of 0, and true is returned.
148
// Otherwise returns false. If clear_rebeacon_timestamp is set, the rebeacon
149
// timestamp field in the proto is cleared to force rebeaconing on the next
151
bool UpdateCandidateKeys(const StringSet& keys, CriticalKeys* proto,
152
bool clear_rebeacon_timestamp);
154
// Based on the CriticalKeys data seen so far, describe whether beacon metadata
155
// is available. This returns false until data is received.
156
inline bool IsBeaconDataAvailable(const CriticalKeys& proto) {
157
return (proto.valid_beacons_received() > 0);
160
} // namespace net_instaweb
162
#endif // NET_INSTAWEB_REWRITER_PUBLIC_CRITICAL_FINDER_SUPPORT_UTIL_H_