⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_negotiation.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 5 页
字号:
                }            }        }        return (float)i / 1000.0f;    }    return 0.0f;}/* * Get a single mime type entry --- one media type and parameters; * enter the values we recognize into the argument accept_rec */static const char *get_entry(apr_pool_t *p, accept_rec *result,                             const char *accept_line){    result->quality = 1.0f;    result->level = 0.0f;    result->charset = "";    /*     * Note that this handles what I gather is the "old format",     *     *    Accept: text/html text/plain moo/zot     *     * without any compatibility kludges --- if the token after the     * MIME type begins with a semicolon, we know we're looking at parms,     * otherwise, we know we aren't.  (So why all the pissing and moaning     * in the CERN server code?  I must be missing something).     */    result->name = ap_get_token(p, &accept_line, 0);    ap_str_tolower(result->name);     /* You want case insensitive,                                       * you'll *get* case insensitive.                                       */    /* KLUDGE!!! Default HTML to level 2.0 unless the browser     * *explicitly* says something else.     */    if (!strcmp(result->name, "text/html") && (result->level == 0.0)) {        result->level = 2.0f;    }    else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE)) {        result->level = 2.0f;    }    else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE3)) {        result->level = 3.0f;    }    while (*accept_line == ';') {        /* Parameters ... */        char *parm;        char *cp;        char *end;        ++accept_line;        parm = ap_get_token(p, &accept_line, 1);        /* Look for 'var = value' --- and make sure the var is in lcase. */        for (cp = parm; (*cp && !apr_isspace(*cp) && *cp != '='); ++cp) {            *cp = apr_tolower(*cp);        }        if (!*cp) {            continue;           /* No '='; just ignore it. */        }        *cp++ = '\0';           /* Delimit var */        while (*cp && (apr_isspace(*cp) || *cp == '=')) {            ++cp;        }        if (*cp == '"') {            ++cp;            for (end = cp;                 (*end && *end != '\n' && *end != '\r' && *end != '\"');                 end++);        }        else {            for (end = cp; (*end && !apr_isspace(*end)); end++);        }        if (*end) {            *end = '\0';        /* strip ending quote or return */        }        ap_str_tolower(cp);        if (parm[0] == 'q'            && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) {            result->quality = atoq(cp);        }        else if (parm[0] == 'l' && !strcmp(&parm[1], "evel")) {            result->level = (float)atoi(cp);        }        else if (!strcmp(parm, "charset")) {            result->charset = cp;        }    }    if (*accept_line == ',') {        ++accept_line;    }    return accept_line;}/***************************************************************** * * Dealing with header lines ... * * Accept, Accept-Charset, Accept-Language and Accept-Encoding * are handled by do_header_line() - they all have the same * basic structure of a list of items of the format *    name; q=N; charset=TEXT * * where charset is only valid in Accept. */static apr_array_header_t *do_header_line(apr_pool_t *p,                                          const char *accept_line){    apr_array_header_t *accept_recs;    if (!accept_line) {        return NULL;    }    accept_recs = apr_array_make(p, 40, sizeof(accept_rec));    while (*accept_line) {        accept_rec *new = (accept_rec *) apr_array_push(accept_recs);        accept_line = get_entry(p, new, accept_line);    }    return accept_recs;}/* Given the text of the Content-Languages: line from the var map file, * return an array containing the languages of this variant */static apr_array_header_t *do_languages_line(apr_pool_t *p,                                             const char **lang_line){    apr_array_header_t *lang_recs = apr_array_make(p, 2, sizeof(char *));    if (!lang_line) {        return lang_recs;    }    while (**lang_line) {        char **new = (char **) apr_array_push(lang_recs);        *new = ap_get_token(p, lang_line, 0);        ap_str_tolower(*new);        if (**lang_line == ',' || **lang_line == ';') {            ++(*lang_line);        }    }    return lang_recs;}/***************************************************************** * * Handling header lines from clients... */static negotiation_state *parse_accept_headers(request_rec *r){    negotiation_state *new =        (negotiation_state *) apr_pcalloc(r->pool, sizeof(negotiation_state));    accept_rec *elts;    apr_table_t *hdrs = r->headers_in;    int i;    new->pool = r->pool;    new->r = r;    new->conf = (neg_dir_config *)ap_get_module_config(r->per_dir_config,                                                       &negotiation_module);    new->dir_name = ap_make_dirstr_parent(r->pool, r->filename);    new->accepts = do_header_line(r->pool, apr_table_get(hdrs, "Accept"));    /* calculate new->accept_q value */    if (new->accepts) {        elts = (accept_rec *) new->accepts->elts;        for (i = 0; i < new->accepts->nelts; ++i) {            if (elts[i].quality < 1.0) {                new->accept_q = 1;            }        }    }    new->accept_encodings =        do_header_line(r->pool, apr_table_get(hdrs, "Accept-Encoding"));    new->accept_langs =        do_header_line(r->pool, apr_table_get(hdrs, "Accept-Language"));    new->accept_charsets =        do_header_line(r->pool, apr_table_get(hdrs, "Accept-Charset"));    /* This is possibly overkill for some servers, heck, we have     * only 33 index.html variants in docs/docroot (today).     * Make this configurable?     */    new->avail_vars = apr_array_make(r->pool, 40, sizeof(var_rec));    return new;}static void parse_negotiate_header(request_rec *r, negotiation_state *neg){    const char *negotiate = apr_table_get(r->headers_in, "Negotiate");    char *tok;    /* First, default to no TCN, no Alternates, and the original Apache     * negotiation algorithm with fiddles for broken browser configs.     *     * To save network bandwidth, we do not configure to send an     * Alternates header to the user agent by default.  User     * agents that want an Alternates header for agent-driven     * negotiation will have to request it by sending an     * appropriate Negotiate header.     */    neg->ua_supports_trans   = 0;    neg->send_alternates     = 0;    neg->may_choose          = 1;    neg->use_rvsa            = 0;    neg->dont_fiddle_headers = 0;    if (!negotiate)        return;    if (strcmp(negotiate, "trans") == 0) {        /* Lynx 2.7 and 2.8 send 'negotiate: trans' even though they         * do not support transparent content negotiation, so for Lynx we         * ignore the negotiate header when its contents are exactly "trans".         * If future versions of Lynx ever need to say 'negotiate: trans',         * they can send the equivalent 'negotiate: trans, trans' instead         * to avoid triggering the workaround below.         */        const char *ua = apr_table_get(r->headers_in, "User-Agent");        if (ua && (strncmp(ua, "Lynx", 4) == 0))            return;    }    neg->may_choose = 0;  /* An empty Negotiate would require 300 response */    while ((tok = ap_get_list_item(neg->pool, &negotiate)) != NULL) {        if (strcmp(tok, "trans") == 0 ||            strcmp(tok, "vlist") == 0 ||            strcmp(tok, "guess-small") == 0 ||            apr_isdigit(tok[0]) ||            strcmp(tok, "*") == 0) {            /* The user agent supports transparent negotiation */            neg->ua_supports_trans = 1;            /* Send-alternates could be configurable, but note             * that it must be 1 if we have 'vlist' in the             * negotiate header.             */            neg->send_alternates = 1;            if (strcmp(tok, "1.0") == 0) {                /* we may use the RVSA/1.0 algorithm, configure for it */                neg->may_choose = 1;                neg->use_rvsa = 1;                neg->dont_fiddle_headers = 1;            }            else if (tok[0] == '*') {                /* we may use any variant selection algorithm, configure                 * to use the Apache algorithm                 */                neg->may_choose = 1;                /* We disable header fiddles on the assumption that a                 * client sending Negotiate knows how to send correct                 * headers which don't need fiddling.                 */                neg->dont_fiddle_headers = 1;            }        }    }#ifdef NEG_DEBUG    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,            "dont_fiddle_headers=%d use_rvsa=%d ua_supports_trans=%d "            "send_alternates=%d, may_choose=%d",            neg->dont_fiddle_headers, neg->use_rvsa,            neg->ua_supports_trans, neg->send_alternates, neg->may_choose);#endif}/* Sometimes clients will give us no Accept info at all; this routine sets * up the standard default for that case, and also arranges for us to be * willing to run a CGI script if we find one.  (In fact, we set up to * dramatically prefer CGI scripts in cases where that's appropriate, * e.g., POST or when URI includes query args or extra path info). */static void maybe_add_default_accepts(negotiation_state *neg,                                      int prefer_scripts){    accept_rec *new_accept;    if (!neg->accepts) {        neg->accepts = apr_array_make(neg->pool, 4, sizeof(accept_rec));        new_accept = (accept_rec *) apr_array_push(neg->accepts);        new_accept->name = "*/*";        new_accept->quality = 1.0f;        new_accept->level = 0.0f;    }    new_accept = (accept_rec *) apr_array_push(neg->accepts);    new_accept->name = CGI_MAGIC_TYPE;    if (neg->use_rvsa) {        new_accept->quality = 0;    }    else {        new_accept->quality = prefer_scripts ? 2.0f : 0.001f;    }    new_accept->level = 0.0f;}/***************************************************************** * * Parsing type-map files, in Roy's meta/http format augmented with * #-comments. *//* Reading RFC822-style header lines, ignoring #-comments and * handling continuations. */enum header_state {    header_eof, header_seen, header_sep};static enum header_state get_header_line(char *buffer, int len, apr_file_t *map){    char *buf_end = buffer + len;    char *cp;    char c;    /* Get a noncommented line */    do {        if (apr_file_gets(buffer, MAX_STRING_LEN, map) != APR_SUCCESS) {            return header_eof;        }    } while (buffer[0] == '#');    /* If blank, just return it --- this ends information on this variant */    for (cp = buffer; (*cp && apr_isspace(*cp)); ++cp) {        continue;    }    if (*cp == '\0') {        return header_sep;    }    /* If non-blank, go looking for header lines, but note that we still     * have to treat comments specially...     */    cp += strlen(cp);    /* We need to shortcut the rest of this block following the Body:     * tag - we will not look for continutation after this line.     */    if (!strncasecmp(buffer, "Body:", 5))        return header_seen;    while (apr_file_getc(&c, map) != APR_EOF) {        if (c == '#') {            /* Comment line */            while (apr_file_getc(&c, map) != APR_EOF && c != '\n') {                continue;            }        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -