2
* Copyright 2012 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: pulkitg@google.com (Pulkit Goyal)
19
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_CRITICAL_IMAGES_FINDER_H_
20
#define NET_INSTAWEB_REWRITER_PUBLIC_CRITICAL_IMAGES_FINDER_H_
25
#include "net/instaweb/rewriter/critical_images.pb.h"
26
#include "net/instaweb/rewriter/public/critical_finder_support_util.h"
27
#include "net/instaweb/util/public/basictypes.h"
28
#include "net/instaweb/util/public/property_cache.h"
29
#include "net/instaweb/util/public/string.h"
30
#include "net/instaweb/util/public/string_util.h"
32
namespace net_instaweb {
41
typedef std::map<GoogleString, std::pair<int32, int32> >
42
RenderedImageDimensionsMap;
44
// The instantiated CriticalImagesFinder is held by ServerContext, meaning
45
// there is only 1 per server. CriticalImagesInfo stores all of the request
46
// specific data needed by CriticalImagesFinder, and is held by the
48
// TODO(jud): Instead of a separate CriticalImagesInfo that gets populated from
49
// the CriticalImages protobuf value, we could just store the protobuf value in
50
// RewriteDriver and eliminate CriticalImagesInfo. Revisit this when updating
51
// this class to support multiple beacon responses.
52
struct CriticalImagesInfo {
54
: is_critical_image_info_present(false) {}
55
StringSet html_critical_images;
56
StringSet css_critical_images;
58
bool is_critical_image_info_present;
59
RenderedImageDimensionsMap rendered_images_map;
63
// Finds critical images i.e. images which are above the fold for a given url.
64
// This information may be used by DelayImagesFilter.
65
class CriticalImagesFinder {
68
kDisabled, // Data will never be forthcoming
69
kNoDataYet, // Data is expected but we don't have it yet
70
kAvailable, // Data is available
72
static const char kCriticalImagesValidCount[];
73
static const char kCriticalImagesExpiredCount[];
74
static const char kCriticalImagesNotFoundCount[];
75
static const char kCriticalImagesPropertyName[];
76
// Property name for the rendered image dimensions retreived from webkit
77
// render response for the page.
78
static const char kRenderedImageDimensionsProperty[];
80
CriticalImagesFinder(const PropertyCache::Cohort* cohort, Statistics* stats);
81
virtual ~CriticalImagesFinder();
83
static void InitStats(Statistics* statistics);
85
// Checks whether IsHtmlCriticalImage will return meaningful results about
86
// critical images. Users of IsHtmlCriticalImage should check this function
87
// and supply default behaviors when Available != kAvailable.
88
virtual Availability Available(RewriteDriver* driver);
90
// In order to handle varying critical image sets returned by the beacon, we
91
// store a history of the last N critical images, and only declare an image
92
// critical if it appears critical in the last M out of N sets reported. This
93
// function returns what percentage of the sets need to include the image for
94
// it be considered critical.
95
virtual int PercentSeenForCritical() const {
96
return kDefaultPercentSeenForCritical;
99
// Minimum interval to store support for critical image results. This affects
100
// how long we keep around evidence that an image might be critical; we'll
101
// remember the fact for at least SupportInterval beacon insertions if it only
102
// occurs once, and we'll remember it longer if multiple beacons support image
103
// criticality. By default, SupportInteval() = 1 and we only store one beacon
104
// result. The beacon critical image finder should override this to store a
105
// larger number of sets.
106
virtual int SupportInterval() const {
107
return kDefaultImageSupportInterval;
110
// Checks whether the requested image is present in the critical set or not.
111
// Users of this function should also check Available() to see if the
112
// implementation of this function returns meaningful results and provide a
113
// default behavior if it does not. If no critical set value has been
114
// obtained, returns false (not critical).
115
// TODO(jud): It would be simpler to modify these interfaces to take
116
// HtmlElement* instead of GoogleStrings. This would move some complexity in
117
// getting the correct URL from the caller into this function. For instance,
118
// if an image has been modified by LazyloadImages then the actual src we want
119
// to check is in the pagespeed_lazyload_src attribute, not in src.
120
bool IsHtmlCriticalImage(StringPiece image_url, RewriteDriver* driver);
122
bool IsCssCriticalImage(StringPiece image_url, RewriteDriver* driver);
124
// Returns true if rendered dimensions exist for the image_src_url and
125
// populates dimensions in the std::pair.
126
bool GetRenderedImageDimensions(
127
RewriteDriver* driver,
128
const GoogleUrl& image_src_gurl,
129
std::pair<int32, int32>* dimensions);
131
// Get the critical image sets. Returns an empty set if there is no critical
132
// image information.
133
const StringSet& GetHtmlCriticalImages(RewriteDriver* driver);
134
const StringSet& GetCssCriticalImages(RewriteDriver* driver);
136
// Utility functions for manually setting the critical image sets. These
137
// should only be used by unit tests that need to setup a specific set of
138
// critical images. For normal users of CriticalImagesFinder, the critical
139
// images will be populated from entries in the property cache. Note that
140
// these always return a non-NULL StringSet value (implying "beacon result
142
StringSet* mutable_html_critical_images(RewriteDriver* driver);
143
StringSet* mutable_css_critical_images(RewriteDriver* driver);
145
// Compute the critical images for the driver's url.
146
virtual void ComputeCriticalImages(RewriteDriver* driver) = 0;
148
// Identifies which cohort in the PropertyCache the critical image information
150
// TODO(jud): Make this protected. There is a lingering public usage in
151
// critical_images_beacon_filter.cc.
152
const PropertyCache::Cohort* cohort() const { return cohort_; }
154
// Updates the critical images property cache entry. Returns whether the
155
// update succeeded or not. Note that this base implementation does not call
156
// WriteCohort. This should be called in the subclass if the cohort is not
157
// written elsewhere. NULL is permitted for the critical image sets if only
158
// one of the html or css sets is being updated, but not the other.
159
bool UpdateCriticalImagesCacheEntryFromDriver(
160
const StringSet* html_critical_images_set,
161
const StringSet* css_critical_images_set,
162
RewriteDriver* driver);
164
// Setup the HTML and CSS critical image sets in critical_images_info from the
165
// property_value. Return true if property_value had a value, and
166
// deserialization of it succeeded. Here because helper code needs access to
168
static bool PopulateCriticalImagesFromPropertyValue(
169
const PropertyValue* property_value, CriticalImages* critical_images);
171
// Alternative interface to update the critical images cache entry. This is
172
// useful in contexts like the beacon handler where the RewriteDriver for the
173
// original request no longer exists.
174
static bool UpdateCriticalImagesCacheEntry(
175
const StringSet* html_critical_images_set,
176
const StringSet* css_critical_images_set,
177
const RenderedImages* rendered_images_set,
178
int support_interval,
179
const PropertyCache::Cohort* cohort,
180
AbstractPropertyPage* page);
182
// Returns true if the critical images are available, false otherwise. This is
183
// virtual only to be overridden in tests.
184
virtual bool IsCriticalImageInfoPresent(RewriteDriver* driver);
186
// Extracts rendered images' dimensions from property cache.
187
virtual RenderedImages* ExtractRenderedImageDimensionsFromCache(
188
RewriteDriver* driver);
190
// Adds the given url to the html critical image set for the driver.
191
void AddHtmlCriticalImage(const GoogleString& url,
192
RewriteDriver* driver);
194
// Parses Json map returned from beacon js and populates RenderedImages proto.
195
// Caller takes ownership of the returned pointer.
196
RenderedImages* JsonMapToRenderedImagesMap(const GoogleString& str,
197
const RewriteOptions* options);
199
// Returns true if it's time to inject a beacon onto the page. The default
200
// finder doesn't use beaconing, so it always returns false.
201
virtual bool ShouldBeacon(RewriteDriver* driver) { return false; }
203
// Check property cache state and prepare to insert beacon. Returns the
204
// metadata where result.status == kDoNotBeacon if no beaconing should occur,
205
// and result.nonce contains the nonce if required (default implementation
206
// always beacons without a nonce).
207
virtual BeaconMetadata PrepareForBeaconInsertion(RewriteDriver* driver) {
208
BeaconMetadata result;
209
result.status = kBeaconNoNonce;
213
// For implementations that use beaconing, update the candidate images in the
214
// property cache. New images are a signal that we should beacon more often
215
// for a few requests. The beaconing argument should indicate if the current
216
// request is injecting a beacon. If so, we don't need to trigger a beacon on
217
// the next request even if the candidate images have changed.
218
virtual void UpdateCandidateImagesForBeaconing(const StringSet& images,
219
RewriteDriver* driver,
223
// Completes a critical image set update operation and writes the data back to
224
// the property cache.
225
static bool UpdateAndWriteBackCriticalImagesCacheEntry(
226
const StringSet* html_critical_images_set,
227
const StringSet* css_critical_images_set,
228
const RenderedImages* rendered_images_set,
229
int support_interval,
230
const PropertyCache::Cohort* cohort,
231
AbstractPropertyPage* page,
232
CriticalImages* critical_images);
234
// Gets critical images if present in the property cache and updates the
235
// critical_images set in RewriteDriver with the obtained set. If you
236
// override this method, driver->critical_images_info() must not return NULL
237
// after this function has been called.
238
virtual void UpdateCriticalImagesSetInDriver(RewriteDriver* driver);
240
virtual GoogleString GetKeyForUrl(StringPiece url) { return url.as_string(); }
242
// Extracts the critical images from the given property_value into
243
// critical_images_info, after checking if the property value is still valid
244
// using the provided TTL. It also updates stats variables.
245
CriticalImagesInfo* ExtractCriticalImagesFromCache(
246
RewriteDriver* driver,
247
const PropertyValue* property_value);
250
friend class CriticalImagesFinderTestBase;
252
// Update a CriticalImages protobuf value with new critical image sets. If
253
// either of the html or css sets are NULL, those fields in critical_images
254
// will not be updated. Returns true if either of the critical image sets in
255
// critical_images was updated.
256
static bool UpdateCriticalImages(const StringSet* html_critical_images,
257
const StringSet* css_critical_images,
258
int support_interval,
259
CriticalImages* critical_images);
261
// By default, store 1 critical image set and require an image to be in that
262
// set for it to be critical.
263
static const int kDefaultPercentSeenForCritical = 100;
264
static const int kDefaultImageSupportInterval = 1;
266
const PropertyCache::Cohort* cohort_;
268
Variable* critical_images_valid_count_;
269
Variable* critical_images_expired_count_;
270
Variable* critical_images_not_found_count_;
272
DISALLOW_COPY_AND_ASSIGN(CriticalImagesFinder);
275
} // namespace net_instaweb
277
#endif // NET_INSTAWEB_REWRITER_PUBLIC_CRITICAL_IMAGES_FINDER_H_