#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "apr_want.h"
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_log.h"
#include "lookupa.h"
Data Structures | |
struct | xhtml_neg_state |
A per-server configuration state for this module. More... | |
struct | xhtml_dir_config |
A per-directory configuration state for this module. More... | |
struct | accept_rec |
Record of available info on a media type specified by the client. More... | |
struct | extension_rec |
Record the maps a file extension to zero or more content-types. More... | |
Defines | |
#define | APR_WANT_STRFUNC |
#define | CORE_PRIVATE |
#define | DEFAULT_CHARSET_NAME "iso-8859-1" |
The default HTTP character set for most content types. | |
#define | DEFAULT_TEXT_XML_CHARSET "us-ascii" |
The default HTTP character set for text/xml and text/xml-external-entity content types. | |
#define | mod_xhtml_strempty(str) (((str) == NULL) || (*(str) == '\0')) |
Test whether a string is empty without having to do a full scan of the string just to return a length, as per strlen. | |
Enumerations | |
enum | xhtml_neg_active { active_on = 1, active_off = 0, active_dontcare = 2 } |
Enumeration for determining whether processing should be enabled for this module. More... | |
enum | http_caching { caching_on = 1, caching_off = 0, caching_dontcare = 2 } |
Enumeration for determining whether HTTP 1.0 caching should be allowed for negotiated documents. More... | |
Functions | |
static int | mod_xhtml_strlen (const char *str) |
Calculate the length of the given string. | |
static int | mod_xhtml_strcmp (const char *str1, const char *str2) |
Compare one string against another in a case-sensitive manner. | |
static int | mod_xhtml_stricmp (const char *str1, const char *str2) |
Compare one string against another in a case-insensitive manner. | |
static int | mod_xhtml_strncmp (const char *str1, const char *str2, const int len) |
Compare strings up to a specified limit in a case-sensitive manner. | |
static int | mod_xhtml_strnicmp (const char *str1, const char *str2, const int len) |
Compare strings up to a specified limit in a case-insensitive manner. | |
static int | mod_xhtml_strendswith (const char *reference, const char *suffix, const int casecompare) |
Determines if the given string end with the given suffix. | |
static float | mod_xhtml_atoq (const char *string) |
Parse quality value. | |
static const char * | get_default_charset (request_rec *r) |
This naughty function goes digging into the Apache http_core module to find the default character set. | |
static extension_rec * | find_extension (apr_array_header_t *extensions, const char *ext) |
Given an array of extension_rec records, find one with the given file extension. | |
static int | count_stars (const char *content_type) |
Count the number of stars in an Accept content token. | |
static char * | reconstruct_content_type (apr_pool_t *p, accept_rec *content_rec) |
Reconstruct the original content-type, if required due to special "charset" values. | |
static void | make_etag_hashcode (apr_pool_t *p, accept_rec *rec) |
Make a simple hash code for the given accept_rec structure. | |
static accept_rec * | make_default_accept (apr_pool_t *p, accept_rec *rec, const char *default_charset) |
Make an accept_rec with an explicit charset. | |
static char * | merge_validators (apr_pool_t *p, char *old_variant, char *new_variant) |
Merge vlist_validators from different modules. | |
static extension_rec * | get_extension_for_filename (apr_array_header_t *extensions, const char *filename) |
For a given filename, scan through an array of extension_rec records until we find a match. | |
static const char * | get_entry (apr_pool_t *p, accept_rec *result, const char *accept_line) |
Get a single mime type entry --- one media type and parameters; enter the values we recognize into the argument accept_rec. | |
static apr_array_header_t * | do_accept_line (apr_pool_t *p, const char *accept_line) |
Parse and tokenise Accept header lines. | |
static apr_array_header_t * | do_accept_charset_line (apr_pool_t *p, const char *accept_charset_line) |
Parse and tokenise Accept-Charset headers. | |
static float | charsets_match (apr_array_header_t *accept_charsets, const char *content_charset) |
Look for a matching charset within the given array of accept_recs. | |
static float | types_match (accept_rec *content_type, accept_rec *content_accept, apr_array_header_t *accept_charsets, const char *default_charset) |
Determine if a given content_type record matches the criteria of the given content_accept record. | |
static accept_rec * | best_match (apr_array_header_t *accept_type, apr_array_header_t *content_type, apr_array_header_t *accept_charset, const char *default_charset, int stars_to_match, xhtml_neg_state *xns, apr_pool_t *p) |
Implements the best match algorithm for a given Accept header, possible content-type headers and an optional default content-type in the event of a star-slash-star match. | |
static void | set_vary_header (request_rec *r) |
For HTTP 1.1 responses, where the content has been modified based on HTTP request headers, need to set the Vary header to name the headers that the variation was based on. | |
int | xhtml_negotiate (request_rec *r) |
The main routine for the content-negotiation phase of this module goes here. | |
static const char * | set_xhtml_active (cmd_parms *cmd, void *in_dir_config, int active) |
Is this module active for the given directory. | |
static const char * | set_xhtml_cache_negotiated (cmd_parms *cmd, void *dummy, int cache) |
Set whether HTTP 1.0 caching should be allowed. | |
static const char * | add_xhtml_type (cmd_parms *cmd, void *in_dir_config, const char *ext, const char *type) |
Add content types for the given file extension. | |
static const char * | add_xhtml_ignore (cmd_parms *cmd, void *in_dir_config, const char *stars) |
Set the minimun number of stars in an Accept token that should be ignored when performing negotiation. | |
static const char * | add_xhtml_log (cmd_parms *cmd, void *dummy, const char *logfile) |
Set the log file name for this module. | |
static void * | make_xhtml_neg_state (apr_pool_t *p, server_rec *s) |
Create a default XHTML negotiation module configuration record. | |
static void * | create_xhtml_dir_config (apr_pool_t *p, char *dummy) |
Create a default directory configuration module. | |
static void * | merge_xhtml_dir_configs (apr_pool_t *p, void *basev, void *addv) |
Merge configuration info from different directories. | |
static int | init_xhtml_log (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) |
Initialize the log file, if one is specified. | |
static void | xhtml_register_hooks (apr_pool_t *p) |
Register specific hooks during request processing. | |
Variables | |
static int | xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE) |
Read/write flags used when opening the log file. | |
static apr_fileperms_t | xfer_perms = APR_OS_DEFAULT |
Permission flags used when opening the log file. | |
module AP_MODULE_DECLARE_DATA | xhtml_neg_module |
command_rec | config_xhtml_cmds [] |
Record for registering commands with the Apache 2.0.x server. | |
module AP_MODULE_DECLARE_DATA | xhtml_neg_module |
Module declaration for registering hooks into the Apache 2.0.x server. |
This file implements the module for Apache 2.x servers.
#define DEFAULT_CHARSET_NAME "iso-8859-1" |
The default HTTP character set for most content types.
#define DEFAULT_TEXT_XML_CHARSET "us-ascii" |
The default HTTP character set for text/xml and text/xml-external-entity content types.
#define mod_xhtml_strempty | ( | str | ) | (((str) == NULL) || (*(str) == '\0')) |
Test whether a string is empty without having to do a full scan of the string just to return a length, as per strlen.
str | a string pointer, possibly NULL, to be tested |
enum xhtml_neg_active |
Enumeration for determining whether processing should be enabled for this module.
By default, we set the directory config state to active_dontcare, meaning the value hasn't been explicitly set. When it is set by XhtmlNegActive, the directory config will be set to either active_on or active_off.
enum http_caching |
Enumeration for determining whether HTTP 1.0 caching should be allowed for negotiated documents.
By default, we set the server config state to caching_dontcare, meaning the value hasn't been explicitly set. When it set by the XhtmlNegCache parameter, the server config will be set to either caching_on or caching_off.
static int mod_xhtml_strlen | ( | const char * | str | ) | [static] |
Calculate the length of the given string.
The pointer may be NULL.
str | a string pointer, possibly NULL, to be tested |
static int mod_xhtml_strcmp | ( | const char * | str1, | |
const char * | str2 | |||
) | [static] |
Compare one string against another in a case-sensitive manner.
Will correctly deal with either pointer being NULL.
str1 | the first string pointer to be compared | |
str2 | the second string pointer to be compared |
static int mod_xhtml_stricmp | ( | const char * | str1, | |
const char * | str2 | |||
) | [static] |
Compare one string against another in a case-insensitive manner.
Will correctly deal with either pointer being NULL.
str1 | the first string pointer to be compared | |
str2 | the second string pointer to be compared |
static int mod_xhtml_strncmp | ( | const char * | str1, | |
const char * | str2, | |||
const int | len | |||
) | [static] |
Compare strings up to a specified limit in a case-sensitive manner.
If a NULL byte is encountered, finish comparing at that character. Will correctly deal with either pointer being NULL.
str1 | the first string pointer to be compared | |
str2 | the second string pointer to be compared | |
len | the maximum number of characters to be compared |
static int mod_xhtml_strnicmp | ( | const char * | str1, | |
const char * | str2, | |||
const int | len | |||
) | [static] |
Compare strings up to a specified limit in a case-insensitive manner.
If a NULL byte is encountered, finish comparing at that character. Will correctly deal with either pointer being NULL.
str1 | the first string pointer to be compared | |
str2 | the second string pointer to be compared | |
len | the maximum number of characters to be compared |
static int mod_xhtml_strendswith | ( | const char * | reference, | |
const char * | suffix, | |||
const int | casecompare | |||
) | [static] |
Determines if the given string end with the given suffix.
Case matching can be enabled or disabled.
reference | the reference string to be tested, possibly NULL | |
suffix | the suffix to test against, possibly NULL | |
casecompare | non-zero if a case sensitive compare is wanted, otherwise zero for a case insensitive compare |
Is the reference string at least as long as the suffix?
static float mod_xhtml_atoq | ( | const char * | string | ) | [static] |
Parse quality value.
atof(3) is not globally usable here, because it depends on the locale (argh).
However, RFC 2616 states:
3.9 Quality Values
[...] HTTP/1.1 applications MUST NOT generate more than three digits after the decimal point. User configuration of these values SHOULD also be limited in this fashion.
qvalue = ( "0" [ "." 0*3DIGIT ] ) | ( "1" [ "." 0*3("0") ] )
This is quite easy. If the supplied string doesn't match the above definition (loosely), we simply return 1 (same as if there's no q-value)
string | a string containing a q-value to be parsed |
static const char* get_default_charset | ( | request_rec * | r | ) | [static] |
This naughty function goes digging into the Apache http_core module to find the default character set.
r | the current HTTP request from which we can determine the configuration of the Apache core |
static extension_rec* find_extension | ( | apr_array_header_t * | extensions, | |
const char * | ext | |||
) | [static] |
Given an array of extension_rec records, find one with the given file extension.
If a match is found, return the extension_rec, otherwise return NULL.
extensions | an array of extension_rec elements to be scanned | |
ext | the file extension to match |
static int count_stars | ( | const char * | content_type | ) | [static] |
Count the number of stars in an Accept content token.
This helps determine priority in case of a tie in q-value priorities.
content_type | the content token that we're interested in, possibly NULL |
static char* reconstruct_content_type | ( | apr_pool_t * | p, | |
accept_rec * | content_rec | |||
) | [static] |
Reconstruct the original content-type, if required due to special "charset" values.
Normally the content-type will be a plain string without charset encoding. In these cases, just return the content-type without modification. In the case where we also have a charset entry, have to create the full content-type string.
p | a memory pool from which we can allocate temporary memory for this request | |
content_rec | the accept_rec that matched the content negotiation |
static void make_etag_hashcode | ( | apr_pool_t * | p, | |
accept_rec * | rec | |||
) | [static] |
Make a simple hash code for the given accept_rec structure.
This allows us to generate unique Etags for accepted content-types. The Etag consists of a hash of each character. This is then represented as a zero padded hexadecimal number.
The data that we use to generate the hash is the content-type and charset, concatenated as one long string.
The hash function is a hash in the public domain by By Bob Jenkins. See lookupa.c or http://burtleburtle.net/bob/hash/doobs.html for details.
p | a memory pool from which we can allocate temporary memory for this request | |
rec | the accept_rec that matched the content negotiation; the hash value will be added to this structure |
static accept_rec* make_default_accept | ( | apr_pool_t * | p, | |
accept_rec * | rec, | |||
const char * | default_charset | |||
) | [static] |
Make an accept_rec with an explicit charset.
If the record already contains a charset parameter, it is returned as-is. Otherwise, the parameter default_charset is used.
p | a memory pool from which we can allocate temporary memory for this request | |
rec | the accept_rec that matched the content negotiation | |
default_charset | the default character set as configured in the Apache core |
static char* merge_validators | ( | apr_pool_t * | p, | |
char * | old_variant, | |||
char * | new_variant | |||
) | [static] |
Merge vlist_validators from different modules.
This code is adapted from code in http_protocol.c in the Apache 1.3 core.
p | a memory pool from which we can allocate temporary memory for this request | |
old_variant | an Etag variant taken from the vlist_validator parameter of the current request | |
new_variant | an Etag variant as supplied by make_etag_hashcode |
static extension_rec* get_extension_for_filename | ( | apr_array_header_t * | extensions, | |
const char * | filename | |||
) | [static] |
For a given filename, scan through an array of extension_rec records until we find a match.
The first match wins. If no match is found, NULL is returned.
extensions | an array of extension_rec elements containing filename suffixes to be matched | |
filename | the filename we want to match |
static const char* get_entry | ( | apr_pool_t * | p, | |
accept_rec * | result, | |||
const char * | accept_line | |||
) | [static] |
Get a single mime type entry --- one media type and parameters; enter the values we recognize into the argument accept_rec.
p | a memory pool from which we can allocate temporary memory for this request | |
result | the accept_rec to be populated by parsing the accept_line | |
accept_line | a string containing the accept token to be parsed |
static apr_array_header_t* do_accept_line | ( | apr_pool_t * | p, | |
const char * | accept_line | |||
) | [static] |
Parse and tokenise Accept header lines.
The Accept request header is handled by do_accept_line() - it has the basic structure of a list of items of the format:
name; q=N; charset=TEXT; profile="URI"
Since this header is very similar in structure to the Accept-Charset request header, we can reuse the parsing in get_entry.
The profile parameter was added to handle section 8 of RFC 3236. These probably won't appear at an origin server, but we handle them explicitly if they do.
p | a memory pool from which we can allocate temporary memory for this request | |
accept_line | the HTTP Accept request value to be parsed |
static apr_array_header_t* do_accept_charset_line | ( | apr_pool_t * | p, | |
const char * | accept_charset_line | |||
) | [static] |
Parse and tokenise Accept-Charset headers.
There is an extra record inserted when neither "*" nor "ISO-8859-1" are mentioned.
p | a memory pool from which we can allocate temporary memory for this request | |
accept_charset_line | the HTTP Accept-Charset request value to be parsed |
Merge new file extensions into new array
static float charsets_match | ( | apr_array_header_t * | accept_charsets, | |
const char * | content_charset | |||
) | [static] |
Look for a matching charset within the given array of accept_recs.
If we find a match, return the corresponding q value, otherwise return 0.0.
accept_charsets | an array of accept_rec items containing Accept-Charset tokens to be matched | |
content_charset | the target charset parameter to match |
static float types_match | ( | accept_rec * | content_type, | |
accept_rec * | content_accept, | |||
apr_array_header_t * | accept_charsets, | |||
const char * | default_charset | |||
) | [static] |
Determine if a given content_type record matches the criteria of the given content_accept record.
Returns a quality value for the given variables.
First, check whether names match, depending on whether any stars are present in the content_accept record. If the first character is a star, then we assume its a total wildcard match. Otherwise, look for the major content-type only.
Once we match based on names, check whether a charset is present in the content_accept record. If so, need to match charsets exactly. Otherwise, no further check is needed, and we can return true immediately.
The quality value returned is a straight multiplication of all the q-values the went into determining the result: the q value from the config file (if any was specified), the q value of the Accept content-type header, and the q value of the Accept-Charset header. Where no q-value is specified, the value "1.0" is used.
content_type | the content-type token to match | |
content_accept | the accept token to be matched | |
accept_charsets | an array of accept_rec items containing Accept-Charset tokens to be matched | |
default_charset | the default charset value as configured in the Apache core |
static accept_rec* best_match | ( | apr_array_header_t * | accept_type, | |
apr_array_header_t * | content_type, | |||
apr_array_header_t * | accept_charset, | |||
const char * | default_charset, | |||
int | stars_to_match, | |||
xhtml_neg_state * | xns, | |||
apr_pool_t * | p | |||
) | [static] |
Implements the best match algorithm for a given Accept header, possible content-type headers and an optional default content-type in the event of a star-slash-star match.
accept_type | an array of accept_rec items containing Accept tokens | |
content_type | an array of accept_rec items containing possible content-type tokens to be matched | |
accept_charset | an array of accept_rec items containing Accept-Charset tokens | |
default_charset | the default character set as configured in the Apache core | |
stars_to_match | the number of '*' tokens at which we start ignoring the Accept token | |
xns | the configuration state of the module in case we need to write to the log file | |
p | a memory pool from which we can allocate temporary memory for this request |
static void set_vary_header | ( | request_rec * | r | ) | [static] |
For HTTP 1.1 responses, where the content has been modified based on HTTP request headers, need to set the Vary header to name the headers that the variation was based on.
For some requests, this cannot be determined by headers alone, and a "*" needs to be sent instead.
Here we first check any existing Vary header for the presence of a "*". If "Vary: *" exists, return it unaltered. Otherwise, we need to merge two new tokens: "Accept" and "Accept-Charset".
r | the current HTTP request to which we merge Vary tokens |
int xhtml_negotiate | ( | request_rec * | r | ) |
The main routine for the content-negotiation phase of this module goes here.
This is mainly setup, control flow and logging going on here.
r | the current HTTP request |
static const char* set_xhtml_active | ( | cmd_parms * | cmd, | |
void * | in_dir_config, | |||
int | active | |||
) | [static] |
Is this module active for the given directory.
in_dir_config | the configuration information for this directory | |
active | a yes/no flag indicating whether the module should be active |
static const char* set_xhtml_cache_negotiated | ( | cmd_parms * | cmd, | |
void * | dummy, | |||
int | cache | |||
) | [static] |
Set whether HTTP 1.0 caching should be allowed.
Default to "no" unless specifically overridden.
cmd | the configuration information for this module on a per-server basis | |
cache | a flag indicating whether HTTP 1.0 caching should be enabled |
static const char* add_xhtml_type | ( | cmd_parms * | cmd, | |
void * | in_dir_config, | |||
const char * | ext, | |||
const char * | type | |||
) | [static] |
Add content types for the given file extension.
in_dir_config | the configuration information for this directory | |
ext | the file extension we're configuring | |
type | the content type to be added for this file extension |
static const char* add_xhtml_ignore | ( | cmd_parms * | cmd, | |
void * | in_dir_config, | |||
const char * | stars | |||
) | [static] |
Set the minimun number of stars in an Accept token that should be ignored when performing negotiation.
in_dir_config | the configuration information for this directory | |
stars | the number of '*' tokens at which we start ignoring any Accept tokens |
static const char* add_xhtml_log | ( | cmd_parms * | cmd, | |
void * | dummy, | |||
const char * | logfile | |||
) | [static] |
Set the log file name for this module.
cmd | the configuration information for this module on a per-server basis | |
logfile | the name of the log file to which the module should write |
static void* make_xhtml_neg_state | ( | apr_pool_t * | p, | |
server_rec * | s | |||
) | [static] |
Create a default XHTML negotiation module configuration record.
p | a memory pool from which we can allocate memory that can later be recycled |
static void* create_xhtml_dir_config | ( | apr_pool_t * | p, | |
char * | dummy | |||
) | [static] |
Create a default directory configuration module.
p | a memory pool from which we can allocate memory that can later be recycled |
static void* merge_xhtml_dir_configs | ( | apr_pool_t * | p, | |
void * | basev, | |||
void * | addv | |||
) | [static] |
Merge configuration info from different directories.
p | a memory pool from which we can allocate memory that can later be recycled | |
basev | the base directory configuration to be merged | |
addv | the additional directory configuration to be merged |
Merge new file extensions into new array
static int init_xhtml_log | ( | apr_pool_t * | pconf, | |
apr_pool_t * | plog, | |||
apr_pool_t * | ptemp, | |||
server_rec * | s | |||
) | [static] |
Initialize the log file, if one is specified.
s | the server configuration from which we derive the state of this module | |
p | a memory pool from which we can allocate memory that can later be recycled |
static void xhtml_register_hooks | ( | apr_pool_t * | p | ) | [static] |
Register specific hooks during request processing.
int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE) [static] |
Read/write flags used when opening the log file.
apr_fileperms_t xfer_perms = APR_OS_DEFAULT [static] |
Permission flags used when opening the log file.
command_rec config_xhtml_cmds[] |
Initial value:
{ AP_INIT_FLAG("XhtmlNegActive", set_xhtml_active, NULL, OR_INDEXES, "Is this module enabled? Defaults to no"), AP_INIT_TAKE1("XhtmlNegLog", add_xhtml_log, NULL, RSRC_CONF, "A file name for an output log file"), AP_INIT_ITERATE2("XhtmlNegTypes", add_xhtml_type, NULL, OR_INDEXES, "A file extension followed by one or more matching " "content-type strings"), AP_INIT_TAKE1("XhtmlNegStarsIgnore", add_xhtml_ignore, NULL, OR_INDEXES, "The number of stars in an Accept header which should be " "ignored if we match them"), AP_INIT_FLAG("XhtmlNegCache", set_xhtml_cache_negotiated, NULL, RSRC_CONF, "Should negotiated HTTP 1.0 requests be cacheable? " "Defaults to no"), { NULL } }
module AP_MODULE_DECLARE_DATA xhtml_neg_module |
Initial value:
{ STANDARD20_MODULE_STUFF, create_xhtml_dir_config, merge_xhtml_dir_configs, make_xhtml_neg_state, NULL, config_xhtml_cmds, xhtml_register_hooks, }