2
* Copyright 2011 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: jmarantz@google.com (Joshua Marantz)
19
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_RESOURCE_SLOT_H_
20
#define NET_INSTAWEB_REWRITER_PUBLIC_RESOURCE_SLOT_H_
25
#include "net/instaweb/htmlparse/public/html_element.h"
26
#include "net/instaweb/rewriter/public/resource.h"
27
#include "net/instaweb/util/public/basictypes.h"
28
#include "net/instaweb/util/public/ref_counted_ptr.h"
29
#include "net/instaweb/util/public/string.h"
30
#include "net/instaweb/util/public/string_util.h"
31
#include "net/instaweb/util/public/vector_deque.h"
32
#include "pagespeed/kernel/base/ref_counted_ptr.h"
33
#include "pagespeed/kernel/http/google_url.h"
35
namespace net_instaweb {
37
class HtmlResourceSlot;
43
typedef RefCountedPtr<ResourceSlot> ResourceSlotPtr;
44
typedef RefCountedPtr<HtmlResourceSlot> HtmlResourceSlotPtr;
45
typedef std::vector<ResourceSlotPtr> ResourceSlotVector;
47
// A slot is a place in a web-site resource a URL is found, and may be
48
// rewritten. Types of slots include HTML element attributes and CSS
49
// background URLs. In principle they could also include JS ajax
50
// requests, although this is NYI.
52
// TODO(jmarantz): make this class thread-safe.
53
class ResourceSlot : public RefCounted<ResourceSlot> {
55
explicit ResourceSlot(const ResourcePtr& resource)
56
: resource_(resource),
57
disable_rendering_(false),
58
should_delete_element_(false),
59
disable_further_processing_(false),
60
was_optimized_(false) {
63
ResourcePtr resource() const { return resource_; }
64
// Return HTML element associated with slot, or NULL if none (CSS, IPRO)
65
virtual HtmlElement* element() const = 0;
67
// Note that while slots can be mutated by multiple threads; they are
68
// implemented with thread-safety in mind -- only mainline render their
69
// results back into the DOM.
71
// For example, SetResource may be run from a helper-thread, but we
72
// would not want that threaded mutation to propagate instantly back
73
// into the HTML or CSS DOM. We buffer the changes in the ResoureSlot
74
// and then render them in the request thread, synchronous to the
75
// HTML filter execution.
77
// TODO(jmarantz): Add a lock or that we or an overall protocol
78
// preventing unwanted interference between renderer's reads and
80
void SetResource(const ResourcePtr& resource);
82
// If disable_rendering is true, this slot will do nothing on rendering,
83
// neither changing the URL or deleting any elements. This is intended for
84
// use of filters which do the entire work in the Context.
85
void set_disable_rendering(bool x) { disable_rendering_ = x; }
86
bool disable_rendering() const { return disable_rendering_; }
88
// Determines whether rendering the slot deletes the HTML Element.
89
// For example, in the CSS combine filter we want the Render to
90
// rewrite the first <link href>, but delete all the other <link>s.
92
// Calling RequestDeleteElement() also forces
93
// set_disable_further_processing(true);
94
void RequestDeleteElement() {
95
should_delete_element_ = true;
96
disable_further_processing_ = true;
98
bool should_delete_element() const { return should_delete_element_; }
100
// Returns true if any of the contexts touching this slot optimized it
101
// successfully. This in particular includes the case where a call to
102
// RewriteContext::Rewrite() on a partition containing this slot returned
103
// kRewriteOk. Note in particular that was_optimized() does not tell you
104
// whether *your* filter optimized the slot! For this you should check
105
// output_partition(n)->optimizable().
106
bool was_optimized() const { return was_optimized_; }
108
// Marks the slot as having been optimized.
109
void set_was_optimized(bool x) { was_optimized_ = x; }
111
// If disable_further_processing is true, no further filter taking this slot
112
// as input will run. Note that this affects only HTML rewriting
113
// (or nested rewrites) since fetch-style rewrites do not share slots
114
// even when more than one filter was involved. For this to persist properly
115
// on cache hits it should be set before RewriteDone is called.
116
// (This also means you should not be using this when partitioning failed).
117
// Only later filters are affected, not the currently running one.
118
void set_disable_further_processing(bool x) {
119
disable_further_processing_ = x;
122
bool disable_further_processing() const {
123
return disable_further_processing_;
126
// Render is not thread-safe. This must be called from the thread that
127
// owns the DOM or CSS file. The RewriteContext state machine will only
128
// call ResourceSlot::Render() on slots that were optimized successfully,
129
// and whose partitions are safely url_relocatable(). (Note that this is
130
// different from RewriteContext::Render).
131
virtual void Render() = 0;
133
// Called after all contexts have had a chance to Render.
134
// This is especially useful for cases where Render was never called
135
// but you want something to be done to all slots.
136
virtual void Finished() {}
138
// Update the URL in the slot target without touching the resource. This is
139
// intended for when we're inlining things as data: URLs and also for placing
140
// the rewritten version of the URL in the slot. The method returns true if
141
// it successfully updates the slot target. Resources that are not explicitly
142
// authorized will get rejected at this point. Note that if you
143
// call this you should also call set_disable_rendering(true), or otherwise
144
// the result will be overwritten. Does not alter the URL in any way. Not
145
// supported on all slot types --- presently only slots representing things
146
// within CSS and HTML have this operation (others will DCHECK-fail). Must be
147
// called from within a context's Render() method.
148
virtual bool DirectSetUrl(const StringPiece& url);
150
// Returns true if DirectSetUrl is supported by this slot (html and css right
152
virtual bool CanDirectSetUrl() { return false; }
154
// Return the last context to have been added to this slot. Returns NULL
155
// if no context has been added to the slot so far.
156
RewriteContext* LastContext() const;
158
// Adds a new context to this slot.
159
void AddContext(RewriteContext* context) { contexts_.push_back(context); }
161
// Detaches a context from the slot. This must be the first or last context
163
void DetachContext(RewriteContext* context);
165
// Returns a human-readable description of where this slot occurs, for use
167
virtual GoogleString LocationString() = 0;
169
// Either relativize the URL or pass it through depending on options set.
170
// PRECONDITION: url must parse as a valid GoogleUrl.
171
// TODO(sligocki): Take a GoogleUrl for url?
172
static GoogleString RelativizeOrPassthrough(const RewriteOptions* options,
174
UrlRelativity url_relativity,
175
const GoogleUrl& base_url);
178
virtual ~ResourceSlot();
179
REFCOUNT_FRIEND_DECLARATION(ResourceSlot);
182
ResourcePtr resource_;
183
bool disable_rendering_;
184
bool should_delete_element_;
185
bool disable_further_processing_;
188
// We track the RewriteContexts that are atempting to rewrite this
189
// slot, to help us build a dependency graph between ResourceContexts.
190
VectorDeque<RewriteContext*> contexts_;
192
DISALLOW_COPY_AND_ASSIGN(ResourceSlot);
195
// A resource-slot created for a Fetch has an empty Render method -- Render
196
// should never be called.
197
class FetchResourceSlot : public ResourceSlot {
199
explicit FetchResourceSlot(const ResourcePtr& resource)
200
: ResourceSlot(resource) {
202
virtual HtmlElement* element() const { return NULL; }
203
virtual void Render();
204
virtual GoogleString LocationString();
207
REFCOUNT_FRIEND_DECLARATION(FetchResourceSlot);
208
virtual ~FetchResourceSlot();
211
DISALLOW_COPY_AND_ASSIGN(FetchResourceSlot);
214
class HtmlResourceSlot : public ResourceSlot {
216
HtmlResourceSlot(const ResourcePtr& resource,
217
HtmlElement* element,
218
HtmlElement::Attribute* attribute,
219
RewriteDriver* driver);
221
virtual HtmlElement* element() const { return element_; }
222
HtmlElement::Attribute* attribute() const { return attribute_; }
224
virtual void Render();
225
virtual GoogleString LocationString();
226
virtual bool DirectSetUrl(const StringPiece& url);
227
virtual bool CanDirectSetUrl() { return true; }
229
// How relative the original URL was. If PreserveUrlRelativity is enabled,
230
// Render will try to make the final URL just as relative.
231
UrlRelativity url_relativity() const { return url_relativity_; }
234
REFCOUNT_FRIEND_DECLARATION(HtmlResourceSlot);
235
virtual ~HtmlResourceSlot();
238
HtmlElement* element_;
239
HtmlElement::Attribute* attribute_;
240
RewriteDriver* driver_;
241
UrlRelativity url_relativity_;
243
int begin_line_number_;
244
int end_line_number_;
246
DISALLOW_COPY_AND_ASSIGN(HtmlResourceSlot);
249
class HtmlResourceSlotComparator {
251
bool operator()(const HtmlResourceSlotPtr& p,
252
const HtmlResourceSlotPtr& q) const;
255
typedef std::set<HtmlResourceSlotPtr,
256
HtmlResourceSlotComparator> HtmlResourceSlotSet;
258
} // namespace net_instaweb
260
#endif // NET_INSTAWEB_REWRITER_PUBLIC_RESOURCE_SLOT_H_