blob: 1f06d57e0cde0350228d9f39692a6fe40652a740 [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: rahulbansal@google.com (Rahul Bansal)
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_SPLIT_HTML_FILTER_H_
#define NET_INSTAWEB_REWRITER_PUBLIC_SPLIT_HTML_FILTER_H_
#include <vector>
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/script_tag_scanner.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "net/instaweb/rewriter/public/suppress_prehead_filter.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/json.h"
#include "pagespeed/kernel/base/json_writer.h"
#include "pagespeed/kernel/base/null_writer.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
namespace net_instaweb {
class HtmlElement;
class RewriteOptions;
class SplitHtmlConfig;
class SplitHtmlState;
class StaticAssetManager;
class Writer;
// Splits the incoming html content into above the fold html and below the
// fold json based on critical line specification stored in property cache.
// This filter will stream above the fold html and send below the fold json at
// EndDocument. It directly writes to the http request.
class SplitHtmlFilter : public SuppressPreheadFilter {
public:
static const char kSplitSuffixJsFormatString[];
static const char kSplitTwoChunkSuffixJsFormatString[];
static const char kLoadHiResImages[];
static const char kMetaReferer[];
explicit SplitHtmlFilter(RewriteDriver* rewrite_driver);
virtual ~SplitHtmlFilter();
virtual void DetermineEnabled(GoogleString* disabled_reason);
virtual void StartDocument();
virtual void EndDocument();
virtual void StartElement(HtmlElement* element);
virtual void EndElement(HtmlElement* element);
static const GoogleString& GetBlinkJsUrl(
const RewriteOptions* options,
const StaticAssetManager* static_asset_manager);
virtual const char* Name() const { return "SplitHtmlFilter"; }
private:
const SplitHtmlConfig* config() const {
return driver()->split_html_config();
}
const StaticAssetManager* static_asset_manager() const {
return driver()->server_context()->static_asset_manager();
}
void ServeNonCriticalPanelContents(const Json::Value& json);
// Sets panel-id attribute to the element. This is not used by client-side
// binding now.
void MarkElementWithPanelId(HtmlElement* element,
const GoogleString& panel_id);
// Reads the panel-id attribute and returns the value
GoogleString GetPanelIdForInstance(HtmlElement* element);
// Returns a string representation of the critical line config.
GoogleString GenerateCriticalLineConfigString();
// Pops the json from top of the stack and merges with parent panel which is
// one below it.
void EndPanelInstance();
// Pushes new Json to the top of the stack corresponding to element.
void StartPanelInstance(HtmlElement* element);
// Inserts <!-- GooglePanel begin --> and <!-- GooglePanel end --> stubs.
void InsertPanelStub(HtmlElement* element, const GoogleString& panel_id);
// Appends dict to the dictionary array
void AppendJsonData(Json::Value* dictionary, const Json::Value& dict);
void WriteString(const StringPiece& str);
// Inserts lazy load and other scripts needed for split initialization into
// the head element. If no head tag in the page, it inserts one before
// body tag.
void InsertSplitInitScripts(HtmlElement* element);
void InvokeBaseHtmlFilterStartDocument();
void InvokeBaseHtmlFilterStartElement(HtmlElement* element);
void InvokeBaseHtmlFilterEndElement(HtmlElement* element);
void InvokeBaseHtmlFilterEndDocument();
// Returns true, if the cross-origin is allowed by looking it up in
// RewriteOptions::access_control_allow_origins()
// Note: The cross-origin must match exactly inclusing the protocol.
// The only wildcard supported is '*' which means allow all domains.
bool IsAllowedCrossDomainRequest(StringPiece cross_origin);
scoped_ptr<SplitHtmlState> state_;
const RewriteOptions* options_;
std::vector<ElementJsonPair> element_json_stack_;
Json::FastWriter fast_writer_;
scoped_ptr<JsonWriter> json_writer_;
Writer* original_writer_;
NullWriter null_writer_;
StringPiece url_;
bool script_written_;
bool flush_head_enabled_;
bool disable_filter_;
bool inside_pagespeed_no_defer_script_;
bool serve_response_in_two_chunks_;
int last_script_index_before_panel_stub_;
bool panel_seen_;
ScriptTagScanner script_tag_scanner_;
DISALLOW_COPY_AND_ASSIGN(SplitHtmlFilter);
};
} // namespace net_instaweb
#endif // NET_INSTAWEB_REWRITER_PUBLIC_SPLIT_HTML_FILTER_H_