Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

mod_xhtml_neg.c File Reference

The main source file for the mod_xhtml_neg module. More...

#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 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. More...


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

int mod_xhtml_strlen (const char *str)
 Calculate the length of the given string. More...

int mod_xhtml_strcmp (const char *str1, const char *str2)
 Compare one string against another in a case-sensitive manner. More...

int mod_xhtml_stricmp (const char *str1, const char *str2)
 Compare one string against another in a case-insensitive manner. More...

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. More...

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. More...

int mod_xhtml_strendswith (const char *reference, const char *suffix, const int casecompare)
 Determines if the given string end with the given suffix. More...

float mod_xhtml_atoq (const char *string)
 Parse quality value. More...

char * get_default_charset (request_rec *r)
 This naughty function goes digging into the Apache http_core module to find the default character set. More...

extension_recfind_extension (array_header *extensions, const char *ext)
 Given an array of extension_rec records, find one with the given file extension. More...

int count_stars (const char *content_type)
 Count the number of stars in an Accept content token. More...

char * reconstruct_content_type (pool *p, accept_rec *content_rec)
 Reconstruct the original content-type, if required due to special "charset" values. More...

void make_etag_hashcode (pool *p, accept_rec *rec)
 Make a simple hash code for the given accept_rec structure. More...

accept_recmake_default_accept (pool *p, accept_rec *rec, char *default_charset)
 Make an accept_rec with an explicit charset. More...

char * merge_validators (pool *p, char *old_variant, char *new_variant)
 Merge vlist_validators from different modules. More...

extension_recget_extension_for_filename (array_header *extensions, const char *filename)
 For a given filename, scan through an array of extension_rec records until we find a match. More...

const char * get_entry (pool *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. More...

array_header * do_accept_line (pool *p, const char *accept_line)
 Parse and tokenise Accept header lines. More...

array_header * do_accept_charset_line (pool *p, const char *accept_charset_line)
 Parse and tokenise Accept-Charset headers. More...

float charsets_match (array_header *accept_charsets, const char *content_charset)
 Look for a matching charset within the given array of accept_recs. More...

float types_match (accept_rec *content_type, accept_rec *content_accept, array_header *accept_charsets, const char *default_charset)
 Determine if a given content_type record matches the criteria of the given content_accept record. More...

accept_recbest_match (array_header *accept_type, array_header *content_type, array_header *accept_charset, char *default_charset, int stars_to_match, xhtml_neg_state *xns, pool *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. More...

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. More...

int xhtml_negotiate (request_rec *r)
 The main routine for the content-negotiation phase of this module goes here. More...

const char * set_xhtml_active (cmd_parms *cmd, xhtml_dir_config *dir_config, int active)
 Is this module active for the given directory. More...

const char * set_xhtml_cache_negotiated (cmd_parms *cmd, void *dummy, int cache)
 Set whether HTTP 1.0 caching should be allowed. More...

const char * add_xhtml_type (cmd_parms *cmd, xhtml_dir_config *dir_config, char *ext, char *type)
 Add content types for the given file extension. More...

const char * add_xhtml_ignore (cmd_parms *cmd, xhtml_dir_config *dir_config, char *stars)
 Set the minimun number of stars in an Accept token that should be ignored when performing negotiation. More...

const char * add_xhtml_log (cmd_parms *cmd, void *dummy, char *logfile)
 Set the log file name for this module. More...

void * make_xhtml_neg_state (pool *p, server_rec *s)
 Create a default XHTML negotiation module configuration record. More...

void * create_xhtml_dir_config (pool *p, char *dummy)
 Create a default directory configuration module. More...

void * merge_xhtml_dir_configs (pool *p, void *basev, void *addv)
 Merge configuration info from different directories. More...

void init_xhtml_log (server_rec *s, pool *p)
 Initialize the log file, if one is specified. More...


Variables

int xfer_flags = (O_WRONLY | O_APPEND | O_CREAT)
 Read/write flags used when opening the log file.

mode_t xfer_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
 Permission flags used when opening the log file.

module MODULE_VAR_EXPORT xhtml_neg_module
 Module declaration for registering hooks into the Apache 1.3.x server. More...

command_rec config_xhtml_cmds []
 Record for registering commands with the Apache 1.3.x server. More...


Detailed Description

The main source file for the mod_xhtml_neg module.

This file implements the module for Apache 1.3.x servers.


Define Documentation

#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.

Parameters:
str  a string pointer, possibly NULL, to be tested
Returns:
a true value if the pointer is NULL, or points to a zero-length string, otherwise a false value


Enumeration Type Documentation

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.

Enumeration values:
active_on  processing should be active.
active_off  processing should not be active.
active_dontcare  default processing state (not active).

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.

Enumeration values:
caching_on  HTTP 1.0 caching should be active.
caching_off  HTTP 1.0 caching should not be active.
caching_dontcare  default processing state (not active).


Function Documentation

int mod_xhtml_strlen const char *    str [static]
 

Calculate the length of the given string.

The pointer may be NULL.

Parameters:
str  a string pointer, possibly NULL, to be tested
Returns:
the length of the string if the pointer is non-NULL, otherwise zero

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.

Parameters:
str1  the first string pointer to be compared
str2  the second string pointer to be compared
Returns:
zero if the strings are identical, less than zero if the first string is less than the second, or greater than zero if the first string is greater than the second

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.

Parameters:
str1  the first string pointer to be compared
str2  the second string pointer to be compared
Returns:
zero if the strings are identical, less than zero if the first string is less than the second, or greater than zero if the first string is greater than the second

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.

Parameters:
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
Returns:
zero if the substrings are identical, less than zero if the first substring is less than the second, or greater than zero if the first substring is greater than the second

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.

Parameters:
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
Returns:
zero if the substrings are identical, less than zero if the first substring is less than the second, or greater than zero if the first substring is greater than the second

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.

Parameters:
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
Returns:
non-zero if the suffix matches, otherwise zero

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)

Parameters:
string  a string containing a q-value to be parsed
Returns:
the parsed q-value, truncated to three decimal places if necessary

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.

Parameters:
r  the current HTTP request from which we can determine the configuration of the Apache core
Returns:
the default character set as configured in the Apache core, or NULL if no value is configured
Todo:
Is there a cleaner way to find the default charset information?

extension_rec* find_extension array_header *    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.

Parameters:
extensions  an array of extension_rec elements to be scanned
ext  the file extension to match
Returns:
the matching extension_rec item if one was found, otherwise NULL

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.

Parameters:
content_type  the content token that we're interested in, possibly NULL
Returns:
the number of '*' characters in the string, or 0 if the string is NULL

char* reconstruct_content_type pool *    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.

Parameters:
p  a memory pool from which we can allocate temporary memory for this request
content_rec  the accept_rec that matched the content negotiation
Returns:
a string that contains a correctly formatted content-type value, or NULL if there is no valid record
Todo:
should we send the "profile" parameter as well?

void make_etag_hashcode pool *    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.

Note:
Since we're only using this algorithm for Etag uniqueness rather than for a hashtable lookup, DoS attacks such as those described in http://www.cs.rice.edu/~scrosby/hash/ are not an issue here, especially since our hash keys come from data in either httpd.conf or .htaccess files.
Parameters:
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
Todo:
If the content-type returned ever includes the "profile" parameter, include it as part of the hash code.

accept_rec* make_default_accept pool *    p,
accept_rec   rec,
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.

Note:
default_charset can be NULL, in which case charset will be set to the empty string.
Parameters:
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
Returns:
the original accept_rec if it already contains a charset parameter, otherwise a new accept_rec containing the same information and the default charset parameter

char* merge_validators pool *    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.

Parameters:
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
Returns:
a correctly merged Etag variant, taking into account whether either variant has a weak validator attached, or whether either variant is NULL

extension_rec* get_extension_for_filename array_header *    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.

Parameters:
extensions  an array of extension_rec elements containing filename suffixes to be matched
filename  the filename we want to match
Returns:
the matching extension_rec item if one exists, otherwise NULL

const char* get_entry pool *    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.

Parameters:
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
Returns:
any remaining accept_line string left to be parsed

array_header* do_accept_line pool *    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.

Parameters:
p  a memory pool from which we can allocate temporary memory for this request
accept_line  the HTTP Accept request value to be parsed
Returns:
an array of accept_rec items containing the parsed Accept tokens

array_header* do_accept_charset_line pool *    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.

Parameters:
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
Returns:
an array of accept_rec items containing the parsed Accept-Charset tokens

float charsets_match array_header *    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.

Parameters:
accept_charsets  an array of accept_rec items containing Accept-Charset tokens to be matched
content_charset  the target charset parameter to match
Returns:
the q value of the best match, or 0.0f if no match was found

float types_match accept_rec   content_type,
accept_rec   content_accept,
array_header *    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.

Parameters:
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
Returns:
the q value of the best matching content-type and charset combination, or 0.0f if no match was found

accept_rec* best_match array_header *    accept_type,
array_header *    content_type,
array_header *    accept_charset,
char *    default_charset,
int    stars_to_match,
xhtml_neg_state   xns,
pool *    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.

Parameters:
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
Returns:
an accept_rec structure containing the best match we could find for the current request, or NULL if we couldn't find a match

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".

Parameters:
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.

Parameters:
r  the current HTTP request
Returns:
OK, to indicate the request was succesfully handled by this module

const char* set_xhtml_active cmd_parms *    cmd,
xhtml_dir_config   dir_config,
int    active
[static]
 

Is this module active for the given directory.

Parameters:
dir_config  the configuration information for this directory
active  a yes/no flag indicating whether the module should be active
Returns:
NULL to indicate that processing was successful

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.

Parameters:
cmd  the configuration information for this module on a per-server basis
cache  a flag indicating whether HTTP 1.0 caching should be enabled
Returns:
NULL to indicate that processing was successful

const char* add_xhtml_type cmd_parms *    cmd,
xhtml_dir_config   dir_config,
char *    ext,
char *    type
[static]
 

Add content types for the given file extension.

Parameters:
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
Returns:
NULL to indicate that processing was successful

const char* add_xhtml_ignore cmd_parms *    cmd,
xhtml_dir_config   dir_config,
char *    stars
[static]
 

Set the minimun number of stars in an Accept token that should be ignored when performing negotiation.

Parameters:
dir_config  the configuration information for this directory
stars  the number of '*' tokens at which we start ignoring any Accept tokens
Returns:
NULL to indicate that processing was successful

const char* add_xhtml_log cmd_parms *    cmd,
void *    dummy,
char *    logfile
[static]
 

Set the log file name for this module.

Parameters:
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
Returns:
NULL to indicate that processing was successful

void* make_xhtml_neg_state pool *    p,
server_rec *    s
[static]
 

Create a default XHTML negotiation module configuration record.

Parameters:
p  a memory pool from which we can allocate memory that can later be recycled
Returns:
a new per-server configuration structure for this module

void* create_xhtml_dir_config pool *    p,
char *    dummy
[static]
 

Create a default directory configuration module.

Parameters:
p  a memory pool from which we can allocate memory that can later be recycled
Returns:
a new per-directory configuration structure for this module

void* merge_xhtml_dir_configs pool *    p,
void *    basev,
void *    addv
[static]
 

Merge configuration info from different directories.

Parameters:
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
Returns:
a merged per-directory configuration structure for this module

void init_xhtml_log server_rec *    s,
pool *    p
[static]
 

Initialize the log file, if one is specified.

Parameters:
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


Variable Documentation

module MODULE_VAR_EXPORT xhtml_neg_module
 

Initial value:

{
    STANDARD_MODULE_STUFF,
    init_xhtml_log,             
    create_xhtml_dir_config,    
    merge_xhtml_dir_configs,    
    make_xhtml_neg_state,       
    NULL,                       
    config_xhtml_cmds,          
    NULL,                       
    NULL,                       
    NULL,                       
    NULL,                       
    NULL,                       
    NULL,                       
    xhtml_negotiate,            
    NULL,                       
    NULL,                       
    NULL,                       
    NULL,                       
    NULL                        
}
Module declaration for registering hooks into the Apache 1.3.x server.

command_rec config_xhtml_cmds[]
 

Initial value:

 {
    {"XhtmlNegActive", set_xhtml_active, NULL, OR_INDEXES, FLAG,
     "Is this module enabled? Defaults to no"},
    {"XhtmlNegLog", add_xhtml_log, NULL, RSRC_CONF, TAKE1,
     "A file name for an output log file"},
    {"XhtmlNegTypes", add_xhtml_type, NULL, OR_INDEXES, ITERATE2,
     "A file extension followed by one or more matching "
     "content-type strings"},
    {"XhtmlNegStarsIgnore", add_xhtml_ignore, NULL, OR_INDEXES, TAKE1,
     "The number of stars in an Accept header which should be ignored if we "
     "match them"},
    {"XhtmlNegCache", set_xhtml_cache_negotiated, NULL, RSRC_CONF, FLAG,
     "Should negotiated HTTP 1.0 requests be cacheable? Defaults to no"},
    { NULL }
}
Record for registering commands with the Apache 1.3.x server.


Generated on Fri Jun 11 22:28:22 2004 for XHTML Negotiation Module by doxygen1.2.15