| #include "pagespeed/apache/mock_apache.h" |
| |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/http/http_names.h" |
| |
| #include "httpd.h" // NOLINT |
| #include "util_filter.h" // NOLINT |
| |
| namespace { |
| |
| net_instaweb::StringVector* recorded_actions = NULL; |
| bool apr_initialized = false; |
| |
| } // namespace |
| |
| namespace net_instaweb { |
| |
| void MockApache::Initialize() { |
| CHECK(recorded_actions == NULL); |
| recorded_actions = new StringVector(); |
| if (!apr_initialized) { |
| apr_initialize(); |
| atexit(apr_terminate); |
| apr_initialized = true; |
| } |
| } |
| |
| void MockApache::Terminate() { |
| CHECK(recorded_actions != NULL); |
| if (!recorded_actions->empty()) { |
| LOG(FATAL) << "MockApache: unprocessed actions: " |
| << ActionsSinceLastCall(); |
| } |
| delete recorded_actions; |
| recorded_actions = NULL; |
| } |
| |
| void MockApache::PrepareRequest(request_rec* request) { |
| apr_pool_create(&request->pool, NULL); |
| request->headers_in = apr_table_make(request->pool, 10); |
| request->headers_out = apr_table_make(request->pool, 10); |
| request->subprocess_env = apr_table_make(request->pool, 10); |
| |
| // Create three fake downstream filters so we can make sure the right ones are |
| // removed. |
| int n_fake_filters = 3; |
| ap_filter_t** filter = &request->output_filters; |
| for (int i = 0; |
| i < n_fake_filters; |
| ++i, filter = &(*filter)->next) { |
| *filter = static_cast<ap_filter_t*>( |
| apr_palloc(request->pool, sizeof(ap_filter_t))); |
| (*filter)->frec = static_cast<ap_filter_rec_t*>( |
| apr_palloc(request->pool, sizeof(ap_filter_rec_t))); |
| const char* filter_name; |
| switch (i) { |
| case 0: |
| filter_name = "MOD_EXPIRES"; |
| break; |
| case 1: |
| filter_name = "FIXUP_HEADERS_OUT"; |
| break; |
| case 2: |
| filter_name = "OTHER_FILTER"; |
| break; |
| default: |
| LOG(FATAL) << "There should only be three fake filters."; |
| } |
| (*filter)->frec->name = filter_name; |
| } |
| *filter = NULL; // Terminate the linked list. |
| } |
| |
| void MockApache::CleanupRequest(request_rec* request) { |
| apr_pool_destroy(request->pool); |
| } |
| |
| GoogleString MockApache::ActionsSinceLastCall() { |
| CHECK(recorded_actions != NULL) << |
| "Must call MockApache::Initialize() first"; |
| GoogleString response = JoinCollection(*recorded_actions, " "); |
| recorded_actions->clear(); |
| return response; |
| } |
| |
| } // namespace net_instaweb |
| |
| namespace { |
| |
| void log_action(StringPiece action) { |
| CHECK(recorded_actions != NULL) << |
| "Must call MockApache::Initialize() first"; |
| recorded_actions->push_back(action.as_string()); |
| } |
| |
| void log_fatal(StringPiece function) { |
| LOG(FATAL) << function << " should not be called"; |
| } |
| |
| } // namespace |
| |
| extern "C" { |
| |
| int ap_rwrite(const void *buf, int nbyte, request_rec *r) { |
| log_action(net_instaweb::StrCat( |
| "ap_rwrite(", StringPiece(static_cast<const char*>(buf), nbyte), ")")); |
| return 1; |
| } |
| |
| int ap_rflush(request_rec* r) { |
| log_action("ap_rflush()"); |
| return 1; |
| } |
| |
| void ap_set_content_length(request_rec* r, apr_off_t length) { |
| log_action(net_instaweb::StrCat( |
| "ap_set_content_length(", net_instaweb::IntegerToString(length), ")")); |
| } |
| |
| void ap_set_content_type(request_rec* r, const char* ct) { |
| log_action(net_instaweb::StrCat( |
| "ap_set_content_type(", StringPiece(ct), ")")); |
| // Incomplete implementation, but enough to be testing. |
| apr_table_set( |
| r->headers_out, net_instaweb::HttpAttributes::kContentType, ct); |
| } |
| |
| void ap_remove_output_filter(ap_filter_t* filter) { |
| CHECK(filter != NULL); |
| CHECK(filter->frec != NULL); |
| log_action(net_instaweb::StrCat( |
| "ap_remove_output_filter(", filter->frec->name, ")")); |
| } |
| |
| ap_filter_t* ap_add_output_filter(const char*, void*, request_rec*, conn_rec*) { |
| log_fatal("ap_add_output_filter"); |
| return NULL; |
| } |
| |
| apr_status_t ap_get_brigade(ap_filter_t*, apr_bucket_brigade*, |
| ap_input_mode_t, apr_read_type_e, apr_off_t) { |
| log_fatal("ap_get_brigade"); |
| return 0; |
| } |
| |
| apr_status_t ap_pass_brigade(ap_filter_t*, apr_bucket_brigade*) { |
| log_fatal("ap_pass_brigade"); |
| return 0; |
| } |
| |
| ap_filter_rec_t* ap_register_output_filter( |
| const char*, ap_out_filter_func, ap_init_filter_func, ap_filter_type) { |
| log_fatal("ap_register_output_filter"); |
| return NULL; |
| } |
| |
| ap_filter_rec_t* ap_register_input_filter(const char*, ap_in_filter_func, |
| ap_init_filter_func, ap_filter_type) { |
| log_fatal("ap_register_input_filter"); |
| return NULL; |
| } |
| |
| #define IMPLEMENT_AS_LOG_FATAL(AP_X) \ |
| void AP_X() { log_fatal(#AP_X); } |
| |
| IMPLEMENT_AS_LOG_FATAL(ap_build_cont_config) |
| IMPLEMENT_AS_LOG_FATAL(ap_check_cmd_context) |
| IMPLEMENT_AS_LOG_FATAL(ap_construct_url) |
| IMPLEMENT_AS_LOG_FATAL(ap_directory_walk) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_child_init) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_handler) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_log_transaction) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_map_to_storage) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_optional_fn_retrieve) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_post_config) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_post_read_request) |
| IMPLEMENT_AS_LOG_FATAL(ap_hook_translate_name) |
| IMPLEMENT_AS_LOG_FATAL(ap_log_error) |
| IMPLEMENT_AS_LOG_FATAL(ap_log_rerror) |
| IMPLEMENT_AS_LOG_FATAL(ap_mpm_query) |
| IMPLEMENT_AS_LOG_FATAL(ap_send_error_response) |
| |
| // We need to define the unixd_config symbol to avoid link errors. This is |
| // completely the wrong type, but our tests that use MockApache don't actually |
| // need unixd_config at all. |
| int unixd_config = 0; |
| |
| } // extern "C" |