📄 mod_speling.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */#include "apr.h"#include "apr_file_io.h"#include "apr_strings.h"#include "apr_lib.h"#define APR_WANT_STRFUNC#include "apr_want.h"#define WANT_BASENAME_MATCH#include "httpd.h"#include "http_core.h"#include "http_config.h"#include "http_request.h"#include "http_log.h"/* mod_speling.c - by Alexei Kosut <akosut@organic.com> June, 1996 * * This module is transparent, and simple. It attempts to correct * misspellings of URLs that users might have entered, namely by checking * capitalizations. If it finds a match, it sends a redirect. * * Sep-1999 Hugo Haas <hugo@w3.org> * o Added a CheckCaseOnly option to check only miscapitalized words. * * 08-Aug-1997 <Martin.Kraemer@Mch.SNI.De> * o Upgraded module interface to apache_1.3a2-dev API (more NULL's in * speling_module). * o Integrated tcsh's "spelling correction" routine which allows one * misspelling (character insertion/omission/typo/transposition). * Rewrote it to ignore case as well. This ought to catch the majority * of misspelled requests. * o Commented out the second pass where files' suffixes are stripped. * Given the better hit rate of the first pass, this rather ugly * (request index.html, receive index.db ?!?!) solution can be * omitted. * o wrote a "kind of" html page for mod_speling * * Activate it with "CheckSpelling On" */module AP_MODULE_DECLARE_DATA speling_module;typedef struct { int enabled; int case_only;} spconfig;/* * 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){ spconfig *cfg = apr_pcalloc(p, sizeof(spconfig)); cfg->enabled = 0; cfg->case_only = 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);}/* * Define the directives specific to this module. This structure is referenced * later by the 'module' structure. */static const command_rec speling_cmds[] ={ AP_INIT_FLAG("CheckSpelling", ap_set_flag_slot, (void*)APR_OFFSETOF(spconfig, enabled), OR_OPTIONS, "whether or not to fix miscapitalized/misspelled requests"), AP_INIT_FLAG("CheckCaseOnly", ap_set_flag_slot, (void*)APR_OFFSETOF(spconfig, case_only), OR_OPTIONS, "whether or not to fix only miscapitalized requests"), { NULL }};typedef enum { SP_IDENTICAL = 0, SP_MISCAPITALIZED = 1, SP_TRANSPOSITION = 2, SP_MISSINGCHAR = 3, SP_EXTRACHAR = 4, SP_SIMPLETYPO = 5, SP_VERYDIFFERENT = 6} sp_reason;static const char *sp_reason_str[] ={ "identical", "miscapitalized", "transposed characters", "character missing", "extra character", "mistyped character", "common basename",};typedef struct { const char *name; sp_reason quality;} misspelled_file;/* * spdist() is taken from Kernighan & Pike, * _The_UNIX_Programming_Environment_ * and adapted somewhat to correspond better to psychological reality. * (Note the changes to the return values) * * According to Pollock and Zamora, CACM April 1984 (V. 27, No. 4), * page 363, the correct order for this is: * OMISSION = TRANSPOSITION > INSERTION > SUBSTITUTION * thus, it was exactly backwards in the old version. -- PWP * * This routine was taken out of tcsh's spelling correction code * (tcsh-6.07.04) and re-converted to apache data types ("char" type * instead of tcsh's NLS'ed "Char"). Plus it now ignores the case * during comparisons, so is a "approximate strcasecmp()". * NOTE that is still allows only _one_ real "typo", * it does NOT try to correct multiple errors. */static sp_reason spdist(const char *s, const char *t){ for (; apr_tolower(*s) == apr_tolower(*t); t++, s++) { if (*t == '\0') { return SP_MISCAPITALIZED; /* exact match (sans case) */ } } if (*s) { if (*t) { if (s[1] && t[1] && apr_tolower(*s) == apr_tolower(t[1]) && apr_tolower(*t) == apr_tolower(s[1]) && strcasecmp(s + 2, t + 2) == 0) { return SP_TRANSPOSITION; /* transposition */ } if (strcasecmp(s + 1, t + 1) == 0) { return SP_SIMPLETYPO; /* 1 char mismatch */ } } if (strcasecmp(s + 1, t) == 0) { return SP_EXTRACHAR; /* extra character */ } } if (*t && strcasecmp(s, t + 1) == 0) { return SP_MISSINGCHAR; /* missing character */ } return SP_VERYDIFFERENT; /* distance too large to fix. */}static int sort_by_quality(const void *left, const void *rite){ return (int) (((misspelled_file *) left)->quality) - (int) (((misspelled_file *) rite)->quality);}static int check_speling(request_rec *r){ spconfig *cfg; char *good, *bad, *postgood, *url; apr_finfo_t dirent; int filoc, dotloc, urlen, pglen; apr_array_header_t *candidates = NULL; apr_dir_t *dir; cfg = ap_get_module_config(r->per_dir_config, &speling_module); if (!cfg->enabled) { return DECLINED; } /* We only want to worry about GETs */ if (r->method_number != M_GET) { return DECLINED; } /* We've already got a file of some kind or another */ if (r->finfo.filetype != 0) { return DECLINED; } /* Not a file request */ if (r->proxyreq || !r->filename) { return DECLINED; } /* This is a sub request - don't mess with it */ if (r->main) { return DECLINED; } /* * The request should end up looking like this: * r->uri: /correct-url/mispelling/more * r->filename: /correct-file/mispelling r->path_info: /more * * So we do this in steps. First break r->filename into two pieces */ 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -