Skip to content

Instantly share code, notes, and snippets.

@ppearson
Created August 13, 2009 09:26
Show Gist options
  • Save ppearson/167061 to your computer and use it in GitHub Desktop.
Save ppearson/167061 to your computer and use it in GitHub Desktop.
apache module
#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