| /* |
| * Copyright 2011 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: jmarantz@google.com (Joshua Marantz) |
| |
| #ifndef NET_INSTAWEB_REWRITER_PUBLIC_RESOURCE_SLOT_H_ |
| #define NET_INSTAWEB_REWRITER_PUBLIC_RESOURCE_SLOT_H_ |
| |
| #include <set> |
| #include <vector> |
| |
| #include "net/instaweb/rewriter/public/resource.h" |
| #include "pagespeed/kernel/base/basictypes.h" |
| #include "pagespeed/kernel/base/ref_counted_ptr.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/base/vector_deque.h" |
| #include "pagespeed/kernel/html/html_element.h" |
| #include "pagespeed/kernel/http/google_url.h" |
| |
| namespace net_instaweb { |
| |
| class CachedResults; |
| class HtmlResourceSlot; |
| class ResourceSlot; |
| class RewriteContext; |
| class RewriteDriver; |
| class RewriteOptions; |
| |
| typedef RefCountedPtr<ResourceSlot> ResourceSlotPtr; |
| typedef RefCountedPtr<HtmlResourceSlot> HtmlResourceSlotPtr; |
| typedef std::vector<ResourceSlotPtr> ResourceSlotVector; |
| |
| // A slot is a place in a web-site resource a URL is found, and may be |
| // rewritten. Types of slots include HTML element attributes and CSS |
| // background URLs. In principle they could also include JS ajax |
| // requests, although this is NYI. |
| // |
| // TODO(jmarantz): make this class thread-safe. |
| class ResourceSlot : public RefCounted<ResourceSlot> { |
| public: |
| explicit ResourceSlot(const ResourcePtr& resource) |
| : resource_(resource), |
| preserve_urls_(false), |
| disable_rendering_(false), |
| should_delete_element_(false), |
| disable_further_processing_(false), |
| was_optimized_(false) { |
| } |
| |
| ResourcePtr resource() const { return resource_; } |
| // Return HTML element associated with slot, or NULL if none (CSS, IPRO) |
| virtual HtmlElement* element() const = 0; |
| |
| // Note that while slots can be mutated by multiple threads; they are |
| // implemented with thread-safety in mind -- only mainline render their |
| // results back into the DOM. |
| // |
| // For example, SetResource may be run from a helper-thread, but we |
| // would not want that threaded mutation to propagate instantly back |
| // into the HTML or CSS DOM. We buffer the changes in the ResoureSlot |
| // and then render them in the request thread, synchronous to the |
| // HTML filter execution. |
| // |
| // TODO(jmarantz): Add a lock or that we or an overall protocol |
| // preventing unwanted interference between renderer's reads and |
| // worker writes. |
| void SetResource(const ResourcePtr& resource); |
| |
| // Disables changing the URL of resources (does nothing if slot is not |
| // associated with a URL (for example, InlineResourceSlot). |
| void set_preserve_urls(bool x) { preserve_urls_ = x; } |
| bool preserve_urls() const { return preserve_urls_; } |
| |
| // If disable_rendering is true, this slot will do nothing on rendering, |
| // neither changing the URL or deleting any elements. This is intended for |
| // use of filters which do the entire work in the Context. |
| void set_disable_rendering(bool x) { disable_rendering_ = x; } |
| bool disable_rendering() const { return disable_rendering_; } |
| |
| // Determines whether rendering the slot deletes the HTML Element. |
| // For example, in the CSS combine filter we want the Render to |
| // rewrite the first <link href>, but delete all the other <link>s. |
| // |
| // Calling RequestDeleteElement() also forces |
| // set_disable_further_processing(true); |
| void RequestDeleteElement() { |
| should_delete_element_ = true; |
| disable_further_processing_ = true; |
| } |
| bool should_delete_element() const { return should_delete_element_; } |
| |
| // Returns true if any of the contexts touching this slot optimized it |
| // successfully. This in particular includes the case where a call to |
| // RewriteContext::Rewrite() on a partition containing this slot returned |
| // kRewriteOk. Note in particular that was_optimized() does not tell you |
| // whether *your* filter optimized the slot! For this you should check |
| // output_partition(n)->optimizable(). |
| bool was_optimized() const { return was_optimized_; } |
| |
| // Marks the slot as having been optimized. |
| void set_was_optimized(bool x) { was_optimized_ = x; } |
| |
| // If disable_further_processing is true, no further filter taking this slot |
| // as input will run. Note that this affects only HTML rewriting |
| // (or nested rewrites) since fetch-style rewrites do not share slots |
| // even when more than one filter was involved. For this to persist properly |
| // on cache hits it should be set before RewriteDone is called. |
| // (This also means you should not be using this when partitioning failed). |
| // Only later filters are affected, not the currently running one. |
| void set_disable_further_processing(bool x) { |
| disable_further_processing_ = x; |
| } |
| |
| bool disable_further_processing() const { |
| return disable_further_processing_; |
| } |
| |
| // Render is not thread-safe. This must be called from the thread that |
| // owns the DOM or CSS file. The RewriteContext state machine will only |
| // call ResourceSlot::Render() on slots that were optimized successfully, |
| // and whose partitions are safely url_relocatable(). (Note that this is |
| // different from RewriteContext::Render). |
| virtual void Render() = 0; |
| |
| // Called after all contexts have had a chance to Render. |
| // This is especially useful for cases where Render was never called |
| // but you want something to be done to all slots. |
| virtual void Finished() {} |
| |
| // Update the URL in the slot target without touching the resource. This is |
| // intended for when we're inlining things as data: URLs and also for placing |
| // the rewritten version of the URL in the slot. The method returns true if |
| // it successfully updates the slot target. Resources that are not explicitly |
| // authorized will get rejected at this point. Note that if you |
| // call this you should also call set_disable_rendering(true), or otherwise |
| // the result will be overwritten. Does not alter the URL in any way. Not |
| // supported on all slot types --- presently only slots representing things |
| // within CSS and HTML have this operation (others will DCHECK-fail). Must be |
| // called from within a context's Render() method. |
| virtual bool DirectSetUrl(const StringPiece& url); |
| |
| // Returns true if DirectSetUrl is supported by this slot (html and css right |
| // now). |
| virtual bool CanDirectSetUrl() { return false; } |
| |
| // Return the last context to have been added to this slot. Returns NULL |
| // if no context has been added to the slot so far. |
| RewriteContext* LastContext() const; |
| |
| // Adds a new context to this slot. |
| void AddContext(RewriteContext* context) { contexts_.push_back(context); } |
| |
| // Detaches a context from the slot. This must be the first or last context |
| // that was added. |
| void DetachContext(RewriteContext* context); |
| |
| // Returns a human-readable description of where this slot occurs, for use |
| // in log messages. |
| virtual GoogleString LocationString() const = 0; |
| |
| // Either relativize the URL or pass it through depending on options set. |
| // PRECONDITION: url must parse as a valid GoogleUrl. |
| // TODO(sligocki): Take a GoogleUrl for url? |
| static GoogleString RelativizeOrPassthrough(const RewriteOptions* options, |
| StringPiece url, |
| UrlRelativity url_relativity, |
| const GoogleUrl& base_url); |
| |
| protected: |
| virtual ~ResourceSlot(); |
| REFCOUNT_FRIEND_DECLARATION(ResourceSlot); |
| |
| private: |
| ResourcePtr resource_; |
| bool preserve_urls_; |
| bool disable_rendering_; |
| bool should_delete_element_; |
| bool disable_further_processing_; |
| bool was_optimized_; |
| |
| // We track the RewriteContexts that are atempting to rewrite this |
| // slot, to help us build a dependency graph between ResourceContexts. |
| VectorDeque<RewriteContext*> contexts_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ResourceSlot); |
| }; |
| |
| // A dummy slot used in various cases where Rendering will be performed in |
| // RewriteContext::Render() instead of ResourceSlot::Render(). |
| class NullResourceSlot : public ResourceSlot { |
| public: |
| NullResourceSlot(const ResourcePtr& resource, StringPiece location); |
| virtual HtmlElement* element() const { return NULL; } |
| virtual void Render() {} |
| virtual GoogleString LocationString() const { return location_; } |
| |
| protected: |
| REFCOUNT_FRIEND_DECLARATION(NullResourceSlot); |
| virtual ~NullResourceSlot(); |
| |
| private: |
| GoogleString location_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NullResourceSlot); |
| }; |
| |
| // A resource-slot created for a Fetch has an empty Render method -- Render |
| // should never be called. |
| class FetchResourceSlot : public ResourceSlot { |
| public: |
| explicit FetchResourceSlot(const ResourcePtr& resource) |
| : ResourceSlot(resource) { |
| } |
| virtual HtmlElement* element() const { return NULL; } |
| virtual void Render(); |
| virtual GoogleString LocationString() const; |
| |
| protected: |
| REFCOUNT_FRIEND_DECLARATION(FetchResourceSlot); |
| virtual ~FetchResourceSlot(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(FetchResourceSlot); |
| }; |
| |
| class HtmlResourceSlot : public ResourceSlot { |
| public: |
| HtmlResourceSlot(const ResourcePtr& resource, |
| HtmlElement* element, |
| HtmlElement::Attribute* attribute, |
| RewriteDriver* driver); |
| |
| virtual HtmlElement* element() const { return element_; } |
| HtmlElement::Attribute* attribute() const { return attribute_; } |
| |
| virtual void Render(); |
| virtual GoogleString LocationString() const; |
| virtual bool DirectSetUrl(const StringPiece& url); |
| virtual bool CanDirectSetUrl() { return true; } |
| |
| // How relative the original URL was. If PreserveUrlRelativity is enabled, |
| // Render will try to make the final URL just as relative. |
| UrlRelativity url_relativity() const { return url_relativity_; } |
| |
| protected: |
| REFCOUNT_FRIEND_DECLARATION(HtmlResourceSlot); |
| virtual ~HtmlResourceSlot(); |
| |
| private: |
| HtmlElement* element_; |
| HtmlElement::Attribute* attribute_; |
| RewriteDriver* driver_; |
| UrlRelativity url_relativity_; |
| |
| int begin_line_number_; |
| int end_line_number_; |
| |
| DISALLOW_COPY_AND_ASSIGN(HtmlResourceSlot); |
| }; |
| |
| class HtmlResourceSlotComparator { |
| public: |
| bool operator()(const HtmlResourceSlotPtr& p, |
| const HtmlResourceSlotPtr& q) const; |
| }; |
| |
| typedef std::set<HtmlResourceSlotPtr, |
| HtmlResourceSlotComparator> HtmlResourceSlotSet; |
| |
| } // namespace net_instaweb |
| |
| #endif // NET_INSTAWEB_REWRITER_PUBLIC_RESOURCE_SLOT_H_ |