| /* |
| * 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: piatek@google.com (Michael Piatek) |
| |
| #ifndef PAGESPEED_OPT_HTTP_REQUEST_CONTEXT_H_ |
| #define PAGESPEED_OPT_HTTP_REQUEST_CONTEXT_H_ |
| |
| #include <set> |
| |
| #include "base/logging.h" |
| #include "pagespeed/kernel/base/basictypes.h" |
| #include "pagespeed/kernel/base/ref_counted_ptr.h" |
| #include "pagespeed/kernel/base/scoped_ptr.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/http/http_options.h" |
| #include "pagespeed/opt/logging/request_timing_info.h" |
| |
| namespace net_instaweb { |
| |
| class AbstractLogRecord; |
| class AbstractMutex; |
| class RequestContext; |
| class RequestTrace; |
| class ThreadSystem; |
| class Timer; |
| |
| typedef RefCountedPtr<RequestContext> RequestContextPtr; |
| |
| // A class which wraps state associated with a request. |
| // |
| // This object should be reference counted, wrapped in a RequestContextPtr. We |
| // use reference counting because, depending on the timing of asynchronous |
| // rewrites, RPC calls, and so on, a RequestContext may outlive the original |
| // HTTP request serving, or not. Reference counting avoids the complexity of |
| // explicit transfer of ownership in these cases. |
| class RequestContext : public RefCounted<RequestContext> { |
| public: |
| // Types of split html request. |
| enum SplitRequestType { |
| SPLIT_FULL, |
| SPLIT_ABOVE_THE_FOLD, |
| SPLIT_BELOW_THE_FOLD, |
| }; |
| |
| // |logging_mutex| will be passed to the request context's AbstractLogRecord, |
| // which will take ownership of it. If you will be doing logging in a real |
| // (threaded) environment, pass in a real mutex. If not, a NullMutex is fine. |
| // |timer| will be passed to the RequestTimingInfo, which will *not* take |
| // ownership. Passing NULL for |timer| is allowed. |
| RequestContext(const HttpOptions& options, AbstractMutex* logging_mutex, |
| Timer* timer); |
| // If you use this constructor, you MUST set_options() later. |
| RequestContext(AbstractMutex* logging_mutex, Timer* timer); |
| |
| // TODO(marq): Move this test context factory to a test-specific file. |
| // Makes a request context for running tests. |
| // Note: Test RequestContexts do not pay attention to options. |
| static RequestContextPtr NewTestRequestContext(ThreadSystem* thread_system) { |
| return NewTestRequestContextWithTimer(thread_system, NULL); |
| } |
| static RequestContextPtr NewTestRequestContextWithTimer( |
| ThreadSystem* thread_system, Timer* timer); |
| static RequestContextPtr NewTestRequestContext(AbstractLogRecord* log_record); |
| |
| // Creates a new, unowned AbstractLogRecord, for use by some subordinate |
| // action. Also useful in case of background activity where logging is |
| // required after the response is written out, e.g., blink flow. |
| virtual AbstractLogRecord* NewSubordinateLogRecord( |
| AbstractMutex* logging_mutex); |
| |
| // The root trace context is associated with the user request which we |
| // are attempting to serve. If this is a request with constituent resources |
| // that we rewrite, there may be several dependent fetches synthesized |
| // by PSOL during rewrites. Those are traced separately. |
| RequestTrace* root_trace_context() { return root_trace_context_.get(); } |
| // Takes ownership of the given context. |
| void set_root_trace_context(RequestTrace* x); |
| |
| // Creates a new RequestTrace associated with a request depending on the |
| // root user request; e.g., a subresource fetch for an HTML page. |
| // |
| // This implementation is a no-op. Subclasses should customize this based |
| // on their underlying tracing system. A few interface notes: |
| // - The caller is not responsible for releasing memory or managing the |
| // lifecycle of the RequestTrace. |
| // - A call to CreateDependentTraceContext() need not be matched by a call |
| // to ReleaseDependentTraceContext(). Cleanup should be automatic and |
| // managed by RequestContext subclass implementations. |
| virtual RequestTrace* CreateDependentTraceContext(const StringPiece& label) { |
| return NULL; |
| } |
| |
| // Releases this object's reference to the given context and frees memory. |
| // Calls to CreateDependentTraceContext need not be matched by |
| // calls to this function. If a dependent trace span is not released when |
| // the request context reference count drops to zero, this object will clean |
| // all dependent traces. |
| // |
| // Note that automatic cleanup of dependent traces is provided for safety. |
| // To provide meaningful performance statistics, cleanup should be |
| // coupled with the completion of the event being traced. |
| // |
| // Subclasses should customize this based on their underlying tracing system. |
| virtual void ReleaseDependentTraceContext(RequestTrace* t); |
| |
| // The log record for the this request, created when the request context is. |
| virtual AbstractLogRecord* log_record(); |
| |
| // Determines whether this request is using the SPDY protocol. |
| bool using_spdy() const { return using_spdy_; } |
| void set_using_spdy(bool x) { using_spdy_ = x; } |
| |
| // The minimal private suffix for the hostname specified in this request. |
| // This should be calculated from the hostname by considering the list of |
| // public suffixes and including one additional component. So if a host is |
| // "a.b.c.d.e.f.g" and "e.f.g" is on the public suffix list then the minimal |
| // private suffix is "d.e.f.g". |
| // |
| // There are two ways of specifying the host -- with the Host header, or on |
| // the initial request line. The caller should make sure to look in both |
| // places. |
| // |
| // If a system doesn't want to fragment the cache by minimal private suffix, |
| // it may set value to the empty string. |
| const GoogleString& minimal_private_suffix() const { |
| return minimal_private_suffix_; |
| } |
| void set_minimal_private_suffix(StringPiece minimal_private_suffix) { |
| minimal_private_suffix.CopyToString(&minimal_private_suffix_); |
| } |
| |
| // Indicates whether the request-headers tell us that a browser can |
| // render webp images. |
| void SetAcceptsWebp(bool x); |
| bool accepts_webp() const { return accepts_webp_; } |
| |
| // Indicates whether the request-headers tell us that a browser can extract |
| // gzip compressed data. |
| void SetAcceptsGzip(bool x); |
| bool accepts_gzip() const { return accepts_gzip_; } |
| |
| // Indicates the type of split html request. |
| SplitRequestType split_request_type() const { |
| return split_request_type_; |
| } |
| void set_split_request_type(SplitRequestType type) { |
| split_request_type_ = type; |
| } |
| |
| int64 request_id() const { |
| return request_id_; |
| } |
| void set_request_id(int64 x) { |
| request_id_ = x; |
| } |
| |
| const GoogleString& sticky_query_parameters_token() const { |
| return sticky_query_parameters_token_; |
| } |
| void set_sticky_query_parameters_token(StringPiece x) { |
| x.CopyToString(&sticky_query_parameters_token_); |
| } |
| |
| // Authorized a particular external domain to be fetched from. The caller of |
| // this method MUST ensure that the domain is not some internal site within |
| // the firewall/LAN hosting the server. Note that this doesn't affect |
| // rewriting at all. |
| // TODO(morlovich): It's not clearly this is the appropriate mechanism |
| // for all the authorizations --- we may want to scope this to a request |
| // only. |
| void AddSessionAuthorizedFetchOrigin(const GoogleString& origin) { |
| session_authorized_fetch_origins_.insert(origin); |
| } |
| |
| // Returns true for exactly the origins that were authorized for this |
| // particular session by calls to AddSessionAuthorizedFetchOrigin() |
| bool IsSessionAuthorizedFetchOrigin(const GoogleString& origin) const { |
| return session_authorized_fetch_origins_.find(origin) |
| != session_authorized_fetch_origins_.end(); |
| } |
| |
| // Prepare the AbstractLogRecord for a subsequent call to WriteLog. This |
| // might include propagating information collected in the RequestContext, |
| // RequestTimingInfo for example, to the underlying logging infrastructure. |
| void PrepareLogRecordForOutput(); |
| |
| // Write the log for background rewriting into disk. |
| void WriteBackgroundRewriteLog(); |
| |
| // Return the log record for background rewrites. If it doesn't exist, create |
| // a new one. |
| AbstractLogRecord* GetBackgroundRewriteLog( |
| ThreadSystem* thread_system, |
| bool log_urls, |
| bool log_url_indices, |
| int max_rewrite_info_log_size); |
| |
| const RequestTimingInfo& timing_info() const { return timing_info_; } |
| RequestTimingInfo* mutable_timing_info() { return &timing_info_; } |
| |
| void set_options(const HttpOptions& options) { |
| DCHECK(!options_set_); |
| options_set_ = true; |
| options_ = options; |
| } |
| // This allows changing options already set. |
| // TODO(sligocki): It would be nice if we could make sure options are only |
| // set once. Is it worth the complexity to force that to be true? |
| void ResetOptions(const HttpOptions& options) { |
| options_set_ = true; |
| options_ = options; |
| } |
| const HttpOptions& options() const { |
| DCHECK(options_set_); |
| return options_; |
| } |
| |
| void Freeze() { frozen_ = true; } |
| bool frozen() const { return frozen_; } |
| |
| protected: |
| // TODO(gee): Fix this, it sucks. |
| // The default constructor will not create a LogRecord. Subclass constructors |
| // must do this explicitly. |
| RequestContext(const HttpOptions& options, AbstractMutex* mutex, |
| Timer* timer, AbstractLogRecord* log_record); |
| // Destructors in refcounted classes should be protected. |
| virtual ~RequestContext(); |
| REFCOUNT_FRIEND_DECLARATION(RequestContext); |
| |
| private: |
| // Set default values of accepts webp, accepts gzip, and uses spdy. |
| void Init(); |
| |
| // Always non-NULL. |
| scoped_ptr<AbstractLogRecord> log_record_; |
| |
| RequestTimingInfo timing_info_; |
| |
| // Logs tracing events associated with the root request. |
| scoped_ptr<RequestTrace> root_trace_context_; |
| |
| // Log for recording background rewritings. |
| scoped_ptr<AbstractLogRecord> background_rewrite_log_record_; |
| |
| StringSet session_authorized_fetch_origins_; |
| |
| bool using_spdy_; |
| bool accepts_webp_; |
| bool accepts_gzip_; |
| bool frozen_; |
| GoogleString minimal_private_suffix_; |
| |
| SplitRequestType split_request_type_; |
| int64 request_id_; |
| |
| // The token specified by query parameter or header that must match the |
| // configured value for options to be converted to cookies. |
| GoogleString sticky_query_parameters_token_; |
| |
| bool options_set_; |
| HttpOptions options_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RequestContext); |
| }; |
| |
| } // namespace net_instaweb |
| |
| #endif // PAGESPEED_OPT_HTTP_REQUEST_CONTEXT_H_ |