blob: fd111da6fc87748ff3a7f88feb2ab4555f9d700c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef PAGESPEED_APACHE_INSTAWEB_CONTEXT_H_
#define PAGESPEED_APACHE_INSTAWEB_CONTEXT_H_
#include "net/instaweb/http/public/request_context.h"
#include "pagespeed/automatic/html_detector.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_writer.h"
#include "pagespeed/kernel/http/content_type.h"
// The httpd header must be after the
// apache_rewrite_driver_factory.h. Otherwise, the compiler will
// complain "strtoul_is_not_a_portable_function_use_strtol_instead".
#include "apr_pools.h"
#include "pagespeed/apache/apache_httpd_includes.h"
namespace net_instaweb {
class ApacheServerContext;
class GzipInflater;
class QueryParams;
class RequestHeaders;
class ResponseHeaders;
class RewriteDriver;
class RewriteOptions;
const char kPagespeedOriginalUrl[] = "mod_pagespeed_original_url";
// Generic deleter meant to be used with apr_pool_cleanup_register().
template <class T>
apr_status_t apache_cleanup(void* object) {
T* resolved = static_cast<T*>(object);
delete resolved;
return APR_SUCCESS;
}
// Context for an HTML rewrite.
//
// One is created for responses that appear to be HTML (although there is
// a basic sanity check that the first non-space char is '<').
//
// The rewriter will put the rewritten content into the output string when
// flushed or finished. We call Flush when we see the FLUSH bucket, and
// call Finish when we see the EOS bucket.
//
// TODO(sligocki): Factor out similarities between this and ProxyFetch.
class InstawebContext {
public:
enum ContentEncoding { kNone, kGzip, kDeflate, kOther };
enum ContentDetectionState { kStart, kHtml, kNotHtml };
// Takes ownership of request_headers.
InstawebContext(request_rec* request, RequestHeaders* request_headers,
const ContentType& content_type,
ApacheServerContext* server_context,
const GoogleString& base_url,
const RequestContextPtr& request_context,
const QueryParams& pagespeed_query_params,
const QueryParams& pagespeed_option_cookies,
bool use_custom_options, const RewriteOptions& options);
~InstawebContext();
void Rewrite(const char* input, int size);
void Flush();
void Finish();
apr_bucket_brigade* bucket_brigade() const { return bucket_brigade_; }
ContentEncoding content_encoding() const { return content_encoding_; }
ApacheServerContext* apache_server_context() { return server_context_; }
const GoogleString& output() { return output_; }
bool empty() const { return output_.empty(); }
void clear() { output_.clear(); } // TODO(jmarantz): needed?
ResponseHeaders* response_headers() { return response_headers_.get(); }
bool sent_headers() { return sent_headers_; }
void set_sent_headers(bool sent) { sent_headers_ = sent; }
// Populated response_headers_ with the request's headers_out table.
void PopulateHeaders(request_rec* request);
// Looks up the apache server context from the server rec.
// TODO(jmarantz): Is there a better place to put this? It needs to
// be used by both mod_instaweb.cc and instaweb_handler.cc.
static ApacheServerContext* ServerContextFromServerRec(server_rec* server);
// Returns a fetchable URI from a request, using the request pool.
static const char* MakeRequestUrl(const RewriteOptions& global_options,
request_rec* request);
private:
void ComputeContentEncoding(request_rec* request);
void BlockingPropertyCacheLookup();
void ProcessBytes(const char* input, int size);
// Checks to see if there was an experiment cookie sent with the request.
// If there was not, set one, and add a Set-Cookie header to the
// response headers.
// If there was one, make sure to set the options state appropriately.
void SetExperimentStateAndCookie(request_rec* request,
RewriteOptions* options);
GoogleString output_; // content after instaweb rewritten.
apr_bucket_brigade* bucket_brigade_;
ContentEncoding content_encoding_;
const ContentType content_type_;
ApacheServerContext* server_context_;
RewriteDriver* rewrite_driver_;
StringWriter string_writer_;
std::unique_ptr<GzipInflater> inflater_;
HtmlDetector html_detector_;
GoogleString absolute_url_;
std::unique_ptr<RequestHeaders> request_headers_;
std::unique_ptr<ResponseHeaders> response_headers_;
bool started_parse_;
bool sent_headers_;
bool populated_headers_;
DISALLOW_COPY_AND_ASSIGN(InstawebContext);
};
} // namespace net_instaweb
#endif // PAGESPEED_APACHE_INSTAWEB_CONTEXT_H_