/* * 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: jefftk@google.com (Jeff Kaufman) // Manage configuration for pagespeed. Compare to ApacheConfig. #ifndef NGX_REWRITE_OPTIONS_H_ #define NGX_REWRITE_OPTIONS_H_ extern "C" { #include #include #include } #include #include "ngx_rewrite_driver_factory.h" #include "net/instaweb/rewriter/public/rewrite_options.h" #include "pagespeed/kernel/base/message_handler.h" #include "pagespeed/kernel/base/ref_counted_ptr.h" #include "pagespeed/kernel/base/stl_util.h" // for STLDeleteElements #include "pagespeed/system/system_rewrite_options.h" #define NGX_PAGESPEED_MAX_ARGS 10 namespace net_instaweb { class NgxRewriteDriverFactory; class ScriptArgIndex { public: explicit ScriptArgIndex(ngx_http_script_compile_t* script, int index) : script_(script), index_(index) { CHECK(script != NULL); CHECK(index > 0 && index < NGX_PAGESPEED_MAX_ARGS); } virtual ~ScriptArgIndex() {} ngx_http_script_compile_t* script() { return script_; } int index() { return index_; } private: // Not owned. ngx_http_script_compile_t* script_; int index_; }; // Refcounted, because the ScriptArgIndexes inside data_ can be shared between // different rewriteoptions. class ScriptLine : public RefCounted { public: explicit ScriptLine(StringPiece* args, int n_args, RewriteOptions::OptionScope scope) : n_args_(n_args), scope_(scope) { for (int i = 0; i < n_args; i++) { args_[i] = args[i]; } } virtual ~ScriptLine() { STLDeleteElements(&data_); data_.clear(); } void AddScriptAndArgIndex(ngx_http_script_compile_t* script, int script_index) { CHECK(script != NULL); CHECK(script_index < NGX_PAGESPEED_MAX_ARGS); data_.push_back(new ScriptArgIndex(script, script_index)); } int n_args() { return n_args_;} StringPiece* args() { return args_;} RewriteOptions::OptionScope scope() { return scope_; } std::vector& data() { return data_; } private: StringPiece args_[NGX_PAGESPEED_MAX_ARGS]; int n_args_; RewriteOptions::OptionScope scope_; std::vector data_; DISALLOW_COPY_AND_ASSIGN(ScriptLine); }; class NgxRewriteOptions : public SystemRewriteOptions { public: // See rewrite_options::Initialize and ::Terminate static void Initialize(); static void Terminate(); NgxRewriteOptions(const StringPiece& description, ThreadSystem* thread_system); explicit NgxRewriteOptions(ThreadSystem* thread_system); virtual ~NgxRewriteOptions() { } // args is an array of n_args StringPieces together representing a directive. // For example: // ["RewriteLevel", "PassThrough"] // or // ["EnableFilters", "combine_css,extend_cache,rewrite_images"] // or // ["ShardDomain", "example.com", "s1.example.com,s2.example.com"] // Apply the directive, returning NGX_CONF_OK on success or an error message // on failure. // // pool is a memory pool for allocating error strings. // cf is only required when compile_scripts is true // when compile_scripts is true, the rewrite_options will be prepared // for replacing any script $variables encountered in args. when false, // script variables will be substituted using the prepared rewrite options. const char* ParseAndSetOptions( StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler, NgxRewriteDriverFactory* driver_factory, OptionScope scope, ngx_conf_t* cf, ProcessScriptVariablesMode script_mode); bool ExecuteScriptVariables( ngx_http_request_t* r, MessageHandler* handler, NgxRewriteDriverFactory* driver_factory); void CopyScriptLinesTo(NgxRewriteOptions* destination) const; void AppendScriptLinesTo(NgxRewriteOptions* destination) const; // Make an identical copy of these options and return it. virtual NgxRewriteOptions* Clone() const; // Returns a suitably down cast version of 'instance' if it is an instance // of this class, NULL if not. static const NgxRewriteOptions* DynamicCast(const RewriteOptions* instance); static NgxRewriteOptions* DynamicCast(RewriteOptions* instance); const GoogleString& statistics_path() const { return statistics_path_.value(); } const GoogleString& global_statistics_path() const { return global_statistics_path_.value(); } const GoogleString& console_path() const { return console_path_.value(); } const GoogleString& messages_path() const { return messages_path_.value(); } const GoogleString& admin_path() const { return admin_path_.value(); } const GoogleString& global_admin_path() const { return global_admin_path_.value(); } const std::vector >& script_lines() const { return script_lines_; } const bool& clear_inherited_scripts() const { return clear_inherited_scripts_; } private: // Helper methods for ParseAndSetOptions(). Each can: // - return kOptionNameUnknown and not set msg: // - directive not handled; continue on with other possible // interpretations. // - return kOptionOk and not set msg: // - directive handled, all's well. // - return kOptionValueInvalid and set msg: // - directive handled with an error; return the error to the user. // // msg will be shown to the user on kOptionValueInvalid. While it would be // nice to always use msg and never use the MessageHandler, some option // parsing code in RewriteOptions expects to write to a MessageHandler. If // that happens we put a summary on msg so the user sees something, and the // detailed message goes to their log via handler. OptionSettingResult ParseAndSetOptions0( StringPiece directive, GoogleString* msg, MessageHandler* handler); virtual OptionSettingResult ParseAndSetOptionFromName1( StringPiece name, StringPiece arg, GoogleString* msg, MessageHandler* handler); // We may want to override 2- and 3-argument versions as well in the future, // but they are not needed yet. // Keeps the properties added by this subclass. These are merged into // RewriteOptions::all_properties_ during Initialize(). // // RewriteOptions uses static initialization to reduce memory usage and // construction time. All NgxRewriteOptions instances will have the same // Properties, so we can build the list when we initialize the first one. static Properties* ngx_properties_; static void AddProperties(); void Init(); // Add an option to ngx_properties_ template static void add_ngx_option(typename OptionClass::ValueType default_value, OptionClass NgxRewriteOptions::*offset, const char* id, StringPiece option_name, OptionScope scope, const char* help, bool safe_to_print) { AddProperty(default_value, offset, id, option_name, scope, help, safe_to_print, ngx_properties_); } Option statistics_path_; Option global_statistics_path_; Option console_path_; Option messages_path_; Option admin_path_; Option global_admin_path_; bool clear_inherited_scripts_; std::vector > script_lines_; // Helper for ParseAndSetOptions. Returns whether the two directives equal, // ignoring case. bool IsDirective(StringPiece config_directive, StringPiece compare_directive); // Returns a given option's scope. RewriteOptions::OptionScope GetOptionScope(StringPiece option_name); // TODO(jefftk): support fetch proxy in server and location blocks. DISALLOW_COPY_AND_ASSIGN(NgxRewriteOptions); }; } // namespace net_instaweb #endif // NGX_REWRITE_OPTIONS_H_