Created
August 13, 2009 09:26
-
-
Save ppearson/167061 to your computer and use it in GitHub Desktop.
apache module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include "apr.h" | |
#include "apr_file_io.h" | |
#include "apr_strings.h" | |
#include "apr_lib.h" | |
#define APR_WANT_STRFUNC | |
#include "apr_want.h" | |
#include "httpd.h" | |
#include "http_core.h" | |
#include "http_config.h" | |
#include "http_request.h" | |
#include "http_log.h" | |
module AP_MODULE_DECLARE_DATA mod_font; | |
typedef struct { | |
int enabled; | |
} modfontconfig; | |
/* | |
* Create a configuration specific to this module for a server or directory | |
* location, and fill it with the default settings. | |
* | |
* The API says that in the absence of a merge function, the record for the | |
* closest ancestor is used exclusively. That's what we want, so we don't | |
* bother to have such a function. | |
*/ | |
static void *mkconfig(apr_pool_t *p) | |
{ | |
modfontconfig *cfg = apr_pcalloc(p, sizeof(modfontconfig)); | |
cfg->enabled = 0; | |
return cfg; | |
} | |
/* | |
* Respond to a callback to create configuration record for a server or | |
* vhost environment. | |
*/ | |
static void *create_mconfig_for_server(apr_pool_t *p, server_rec *s) | |
{ | |
return mkconfig(p); | |
} | |
/* | |
* Respond to a callback to create a config record for a specific directory. | |
*/ | |
static void *create_mconfig_for_directory(apr_pool_t *p, char *dir) | |
{ | |
return mkconfig(p); | |
} | |
static const char *set_modfont(cmd_parms *cmd, void *mconfig, int arg) | |
{ | |
modfontconfig *cfg = (modfontconfig *) mconfig; | |
cfg->enabled = arg; | |
return NULL; | |
} | |
/* | |
* Define the directives specific to this module. This structure is referenced | |
* later by the 'module' structure. | |
*/ | |
static const command_rec modfont_cmds[] = | |
{ | |
AP_INIT_FLAG("modfont", set_modfont, NULL, OR_OPTIONS, | |
"whether or not to convert TTFs to EOTs for IE requests"), | |
{ NULL } | |
}; | |
static int check_font(request_rec *r) | |
{ | |
modfontconfig *cfg; | |
char *good, *bad, *postgood, *url; | |
apr_finfo_t dirent; | |
int filoc, dotloc, urlen, pglen; | |
apr_dir_t *dir; | |
cfg = ap_get_module_config(r->per_dir_config, &mod_font); | |
if (!cfg->enabled) | |
{ | |
return DECLINED; | |
} | |
/* We only want to worry about GETs */ | |
if (r->method_number != M_GET) | |
{ | |
return DECLINED; | |
} | |
/* If browser is not IE, bug out */ | |
const char *user_agent; | |
user_agent = apr_table_get(r->headers_in, "User-Agent"); | |
if (strstr(user_agent, "MSIE") == 0) | |
{ | |
return DECLINED; | |
} | |
/* We've already got a file of some kind or another */ | |
/* if (r->proxyreq || (r->finfo.filetype != 0)) { | |
return DECLINED; | |
} | |
*/ | |
/* This is a sub request - don't mess with it */ | |
/* if (r->main) { | |
return DECLINED; | |
} | |
*/ | |
filoc = ap_rind(r->filename, '/'); | |
/* | |
* Don't do anything if the request doesn't contain a slash, or | |
* requests "/" | |
*/ | |
if (filoc == -1 || strcmp(r->uri, "/") == 0) | |
{ | |
return DECLINED; | |
} | |
/* good = /correct-file */ | |
good = apr_pstrndup(r->pool, r->filename, filoc); | |
/* bad = mispelling */ | |
bad = apr_pstrdup(r->pool, r->filename + filoc + 1); | |
/* postgood = mispelling/more */ | |
postgood = apr_pstrcat(r->pool, bad, r->path_info, NULL); | |
urlen = strlen(r->uri); | |
pglen = strlen(postgood); | |
/* Check to see if the URL pieces add up */ | |
if (strcmp(postgood, r->uri + (urlen - pglen))) | |
{ | |
return DECLINED; | |
} | |
/* url = /correct-url */ | |
url = apr_pstrndup(r->pool, r->uri, (urlen - pglen)); | |
/* Now open the directory and do ourselves a check... */ | |
if (apr_dir_open(&dir, good, r->pool) != APR_SUCCESS) | |
{ | |
/* Oops, not a directory... */ | |
return DECLINED; | |
} | |
dotloc = ap_ind(bad, '.'); | |
if (dotloc == -1) | |
{ | |
dotloc = strlen(bad); | |
} | |
while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dir) == APR_SUCCESS) | |
{ | |
/* | |
* If we end up with a "fixed" URL which is identical to the | |
* requested one, we must have found a broken symlink or some such. | |
* Do _not_ try to redirect this, it causes a loop! | |
*/ | |
if (strcmp(bad, dirent.name) == 0) | |
{ | |
apr_dir_close(dir); | |
return OK; | |
} | |
int entloc = ap_ind(dirent.name, '.'); | |
if (entloc == -1) | |
{ | |
entloc = strlen(dirent.name); | |
} | |
if ((dotloc == entloc) && !strncasecmp(bad, dirent.name, dotloc)) | |
{ | |
char *new_url = apr_pstrdup(r->pool, dirent.name); | |
char *nuri; | |
const char *ref; | |
ref = apr_table_get(r->headers_in, "Referer"); | |
nuri = ap_escape_uri(r->pool, apr_pstrcat(r->pool, url, new_url, r->path_info, NULL)); | |
if (r->parsed_uri.query) | |
nuri = apr_pstrcat(r->pool, nuri, "?", r->parsed_uri.query, NULL); | |
apr_table_setn(r->headers_out, "Location", | |
ap_construct_url(r->pool, nuri, r)); | |
ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, | |
r, | |
ref ? "Redirected font: %s to %s from %s" | |
: "Redirected font: %s to %s", | |
r->uri, nuri, ref); | |
return HTTP_MOVED_PERMANENTLY; | |
} | |
} | |
apr_dir_close(dir); | |
return OK; | |
} | |
static void register_hooks(apr_pool_t *p) | |
{ | |
ap_hook_fixups(check_font, NULL, NULL, APR_HOOK_LAST); | |
} | |
module AP_MODULE_DECLARE_DATA font_module = | |
{ | |
STANDARD20_MODULE_STUFF, | |
NULL, /* create per-dir config */ | |
NULL, /* merge per-dir config */ | |
NULL, /* server config */ | |
NULL, /* merge server config */ | |
modfont_cmds, /* command apr_table_t */ | |
register_hooks /* register hooks */ | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment