blob: 7387cafa02cca1d28af715a592bc2459ecab738c [file] [log] [blame]
// Copyright 2010 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)
#include "net/instaweb/apache/header_util.h"
#include "net/instaweb/apache/apr_timer.h"
#include "net/instaweb/apache/instaweb_context.h"
#include "net/instaweb/rewriter/public/resource_manager.h"
#include "net/instaweb/http/public/headers.h"
#include "net/instaweb/http/public/request_headers.h"
#include "net/instaweb/http/public/response_headers.h"
#include "net/instaweb/util/public/time_util.h"
#include "apr_strings.h"
#include "http_core.h"
#include "http_protocol.h"
namespace net_instaweb {
namespace {
int AddAttributeCallback(void *rec, const char *key, const char *value) {
RequestHeaders* request_headers = static_cast<RequestHeaders*>(rec);
request_headers->Add(key, value);
return 1;
}
int AddResponseAttributeCallback(void *rec, const char *key,
const char *value) {
ResponseHeaders* response_headers = static_cast<ResponseHeaders*>(rec);
response_headers->Add(key, value);
return 1;
}
} // namespace
void ApacheRequestToRequestHeaders(const request_rec& request,
RequestHeaders* request_headers) {
if (request.proto_num >= 1000) {
// proto_num is the version number of protocol; 1.1 = 1001
request_headers->set_major_version(request.proto_num / 1000);
request_headers->set_minor_version(request.proto_num % 1000);
}
apr_table_do(AddAttributeCallback, request_headers, request.headers_in, NULL);
}
void ApacheRequestToResponseHeaders(const request_rec& request,
ResponseHeaders* response_headers) {
apr_table_do(AddResponseAttributeCallback, response_headers,
request.headers_out, NULL);
}
void ResponseHeadersToApacheRequest(const ResponseHeaders& response_headers,
request_rec* request) {
request->status = response_headers.status_code();
// proto_num is the version number of protocol; 1.1 = 1001
request->proto_num =
(response_headers.major_version() * 1000) +
response_headers.minor_version();
AddResponseHeadersToRequest(response_headers, request);
}
void AddResponseHeadersToRequest(const ResponseHeaders& response_headers,
request_rec* request) {
for (int i = 0, n = response_headers.NumAttributes(); i < n; ++i) {
const GoogleString& name = response_headers.Name(i);
const GoogleString& value = response_headers.Value(i);
if (StringCaseEqual(name, HttpAttributes::kContentType)) {
// ap_set_content_type does not make a copy of the string, we need
// to duplicate it.
char* ptr = apr_pstrdup(request->pool, value.c_str());
ap_set_content_type(request, ptr);
} else {
if (StringCaseEqual(name, HttpAttributes::kCacheControl)) {
DisableDownstreamHeaderFilters(request);
}
// apr_table_add makes copies of both head key and value, so we do not
// have to duplicate them.
apr_table_add(request->headers_out, name.c_str(), value.c_str());
}
}
}
void DisableDownstreamHeaderFilters(request_rec* request) {
// Prevent downstream filters from corrupting our headers.
ap_filter_t* filter = request->output_filters;
while (filter != NULL) {
ap_filter_t* next = filter->next;
if ((StringCaseEqual(filter->frec->name, "MOD_EXPIRES")) ||
(StringCaseEqual(filter->frec->name, "FIXUP_HEADERS_OUT"))) {
ap_remove_output_filter(filter);
}
filter = next;
}
}
int PrintAttributeCallback(void *rec, const char *key, const char *value) {
fprintf(stdout, " %s: %s\n", key, value);
return 1;
}
// This routine is intended for debugging so fprintf to stdout is the way
// to get instant feedback.
void PrintHeaders(request_rec* request) {
fprintf(stdout, "Input headers:\n");
apr_table_do(PrintAttributeCallback, NULL, request->headers_in, NULL);
fprintf(stdout, "Output headers:\n");
apr_table_do(PrintAttributeCallback, NULL, request->headers_out, NULL);
fflush(stdout);
}
} // namespace net_instaweb