blob: efebfa284787be2b82ec02b416a8b9c8a2885e42 [file] [log] [blame]
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: matterbury@google.com (Matt Atterbury)
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_LOCAL_STORAGE_CACHE_FILTER_H_
#define NET_INSTAWEB_REWRITER_PUBLIC_LOCAL_STORAGE_CACHE_FILTER_H_
#include <set>
#include "net/instaweb/rewriter/cached_result.pb.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_filter.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/statistics.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/html/html_element.h"
namespace net_instaweb {
/*
* The Local Storage Cache rewriter reduces HTTP requests by inlining resources
* and using browser-side javascript to store the inlined resources in local
* storage. The javascript also creates a cookie that reflects the resources it
* has in local storage. On a repeat view, the server uses the cookie to
* determine if it should replace an inlined resource with a script snippet
* that loads the resource from local storage. In effect, we get browser
* caching of inlined resources, theoretically speeding up first view (by
* inlining) and repeat view (by not resending the inlined resource).
*/
class LocalStorageCacheFilter : public RewriteFilter {
public:
static const char kLscCookieName[];
static const char kLscInitializer[]; // public for the test harness only.
// Statistics' names.
static const char kCandidatesFound[];
static const char kStoredTotal[];
static const char kStoredImages[];
static const char kStoredCss[];
static const char kCandidatesAdded[];
static const char kCandidatesRemoved[];
// State information for an inline filter using LSC.
class InlineState {
public:
InlineState() : initialized_(false), enabled_(false) {}
private:
friend class LocalStorageCacheFilter;
bool initialized_;
bool enabled_;
GoogleString url_;
};
explicit LocalStorageCacheFilter(RewriteDriver* rewrite_driver);
virtual ~LocalStorageCacheFilter();
// May be called multiple times, if there are multiple statistics objects.
static void InitStats(Statistics* statistics);
virtual void StartDocumentImpl();
virtual void EndDocument();
virtual void StartElementImpl(HtmlElement* element);
virtual void EndElementImpl(HtmlElement* element);
virtual const char* Name() const { return "LocalStorageCache"; }
virtual const char* id() const {
return RewriteOptions::kLocalStorageCacheId;
}
std::set<StringPiece>* mutable_cookie_hashes() { return &cookie_hashes_; }
// Tell the LSC that the resource with the given url is a candidate for
// storing in the browser's local storage. If LSC is disabled it's a no-op,
// otherwise it determines the LSC's version of the url and, if
// skip_cookie_check is true or the hash of the LSC's url is in the LSC's
// cookie, adds the LSC's url as an attribute of the given element, which the
// LSC later uses to tell that the element is suitable for storing in local
// cache. Returns true if the attribute was added. Saves various computed
// values in the given state variable for any subsequent call (a filter might
// need to call this method once with skip_cookie_check false, then again
// later with it true).
// url is the URL from the HTML element, src from img, href from style.
// driver is the request's context.
// is_enabled is set to true if the local storage cache filter is enabled.
// skip_cookie_check if true skips the checking of the cookie for the hash
// and adds the LSC's url attribute if LSC is enabled.
// element is the element to add the attribute to.
// state is where to save the computed values.
static bool AddStorableResource(const StringPiece& url,
RewriteDriver* driver,
bool skip_cookie_check,
HtmlElement* element,
InlineState* state);
// Tell the LSC to add its attributes to the given element:
// data-pagespeed-lsc-hash and, if the resource has an expiry time [in
// cached], data-pagespeed-lsc-expiry. This is a no-op if LSC is disabled.
// url is the URL of the resource being rewritten.
// cached is the result of the resource rewrite.
// driver is the request's context.
// element is the element to update.
// Returns true if the element was updated.
static bool AddLscAttributes(const StringPiece url,
const CachedResult& cached,
RewriteDriver* driver,
HtmlElement* element);
// Remove the LSC attributes from the given element.
static void RemoveLscAttributes(HtmlElement* element,
RewriteDriver* driver);
private:
void InsertOurScriptElement(HtmlElement* before);
static bool IsHashInCookie(const RewriteDriver* driver,
const StringPiece cookie_name,
const StringPiece hash,
std::set<StringPiece>* hash_set);
static GoogleString ExtractOtherImgAttributes(const HtmlElement* element);
static GoogleString GenerateHashFromUrlAndElement(const RewriteDriver* driver,
const StringPiece& lsc_url,
const HtmlElement* element);
// Have we inserted the script of utility functions?
bool script_inserted_;
// Have we seen any inlined resources that need the utility functions?
bool script_needs_inserting_;
// The set of hashes in the local storage cache cookie. Each element points
// into the rewrite driver's cookies() - that must not change underneath us.
std::set<StringPiece> cookie_hashes_;
// # of times an img/link was found with a data-pagespeed-lsc-url attribute.
Variable* num_local_storage_cache_candidates_found_;
// # of times the hash of an img/link was found in the hash cookie.
Variable* num_local_storage_cache_stored_total_;
// # of times an img's hash was found in the hash cookie.
Variable* num_local_storage_cache_stored_images_;
// # of times a link's hash was found in the hash cookie.
Variable* num_local_storage_cache_stored_css_;
// # of times we added the hash and expiry attributes to a candidate img/link.
Variable* num_local_storage_cache_candidates_added_;
// # of times we removed the lsc attributes from a candidate img/link.
Variable* num_local_storage_cache_candidates_removed_;
DISALLOW_COPY_AND_ASSIGN(LocalStorageCacheFilter);
};
} // namespace net_instaweb
#endif // NET_INSTAWEB_REWRITER_PUBLIC_LOCAL_STORAGE_CACHE_FILTER_H_