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

📄 mod_negotiation.c

📁 apache简化版
💻 C
📖 第 1 页 / 共 5 页
字号:
     *     * For each check, we have three possible outcomes:     *   This variant is worse than current best: return 0     *   This variant is better than the current best:     *          assign this variant's q to *p_bestq, and return 1     *   This variant is just as desirable as the current best:     *          drop through to the next test.     *     * This code is written in this long-winded way to allow future     * customisation, either by the addition of additional     * checks, or to allow the order of the checks to be determined     * by configuration options (e.g. we might prefer to check     * language quality _before_ content type).     */    /* First though, eliminate this variant if it is not     * acceptable by type, charset, encoding or language.     */    if (variant->encoding_quality == 0 ||        variant->lang_quality == 0 ||        variant->type_quality == 0 ||        variant->charset_quality == 0 ||        variant->accept_type_quality == 0) {        return 0;               /* don't consider unacceptables */    }    q = variant->accept_type_quality * variant->type_quality;    if (q == 0.0 || q < bestq) {        return 0;    }    if (q > bestq || !best) {        *p_bestq = q;        return 1;    }    /* language */    if (variant->lang_quality < best->lang_quality) {        return 0;    }    if (variant->lang_quality > best->lang_quality) {        *p_bestq = q;        return 1;    }    /* if language qualities were equal, try the LanguagePriority     * stuff */    if (best->lang_index != -1 && variant->lang_index > best->lang_index) {        return 0;    }    if (variant->lang_index != -1 &&        (variant->lang_index < best->lang_index || best->lang_index == -1)) {        *p_bestq = q;        return 1;    }    /* content-type level (text/html only?) */    levcmp = level_cmp(variant, best);    if (levcmp == -1) {        return 0;    }    if (levcmp == 1) {        *p_bestq = q;        return 1;    }    /* encoding -- can only be 1 or 0, and if 0 we eliminated this     * variant at the start of this function. However we      * prefer variants with no encoding over those with encoding */    if (best->content_encoding == NULL && variant->content_encoding) {        return 0;    }    if (best->content_encoding && variant->content_encoding == NULL) {        *p_bestq = q;        return 1;    }    /* charset */    if (variant->charset_quality < best->charset_quality) {        return 0;    }    /* If the best variant's charset is ISO-8859-1 and this variant has     * the same charset quality, then we prefer this variant     */    if (variant->charset_quality > best->charset_quality ||        ((variant->content_charset != NULL &&          *variant->content_charset != '\0' &&          strcmp(variant->content_charset, "iso-8859-1") != 0) &&         (best->content_charset == NULL ||          *best->content_charset == '\0' ||          strcmp(best->content_charset, "iso-8859-1") == 0))) {        *p_bestq = q;        return 1;    }    /* content length if all else equal */    if (find_content_length(neg, variant) >= find_content_length(neg, best)) {        return 0;    }    /* ok, to get here means every thing turned out equal, except     * we have a shorter content length, so use this variant */    *p_bestq = q;    return 1;}static int best_match(negotiation_state *neg, var_rec **pbest){    int j;    var_rec *best = NULL;    float bestq = 0.0f;    enum algorithm_results algorithm_result = na_not_applied;    var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;    set_default_lang_quality(neg);    /*     * Find the 'best' variant     */    for (j = 0; j < neg->avail_vars->nelts; ++j) {        var_rec *variant = &avail_recs[j];        /* Find all the relevant 'quality' values from the         * Accept... headers, and store in the variant         */        set_accept_quality(neg, variant);        set_language_quality(neg, variant);        set_encoding_quality(neg, variant);        set_charset_quality(neg, variant);        /* Now find out if this variant is better than the current         * best, either using the network algorithm, or Apache's         * internal server-driven algorithm. Presumably other         * server-driven algorithms are possible, and could be         * implemented here.         */        if (neg->use_transparent_neg) {            if (is_variant_better_na(neg, variant, best, &bestq)) {                best = variant;            }        }        else {            if (is_variant_better(neg, variant, best, &bestq)) {                best = variant;            }        }    }    /* We now either have a best variant, or no best variant      */    if (neg->use_transparent_neg) {        if (neg->short_accept_headers) {            algorithm_result = na_list;        }        else {            /* From Holtman, result is:             *   If variant & URI are not neigbors, list_ua or list_os             *   Else             *     If UA can do trans neg             *        IF best is definite && best q > 0, choice_ua              *        ELSE                               list_ua             *     ELSE             *        IF best q > 0, choose_os             *        ELSE           list_os (or forward_os on proxy)             */            /* assume variant and URI are neigbors (since URI in             * var map must be in same directory) */            if (neg->use_transparent_neg) {                algorithm_result = (best && best->definite) && (bestq > 0)                    ? na_choice : na_list;            }            else {                algorithm_result = bestq > 0 ? na_choice : na_list;            }        }    }    *pbest = best;    return algorithm_result;}/* * Sets the Alternates and Vary headers, used if we are going to * return 406 Not Acceptable status, a 300 Multiple Choice status, * or a Choice response. * * 'type' is the result of the network algorithm, if applied. * We do different things if the network algorithm was not applied * (type == na_not_applied): no Alternates header, and Vary: * does not include 'negotiate'. * * We should also add a max-age lifetime for the Alternates header, * but how long we we give it? Presumably this should be * configurable in the map file. */static void set_neg_headers(request_rec *r, negotiation_state *neg,                            int na_result){    int j;    var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;    char *sample_type = NULL;    char *sample_language = NULL;    const char *sample_encoding = NULL;    char *sample_charset = NULL;    int vary_by_type = 0;    int vary_by_language = 0;    int vary_by_charset = 0;    int vary_by_encoding = 0;    table *hdrs;    /* Put headers into err_headers_out, new send_http_header()     * outputs both headers_out and err_headers_out */    hdrs = r->err_headers_out;    for (j = 0; j < neg->avail_vars->nelts; ++j) {        var_rec *variant = &avail_recs[j];        char *rec;        char qstr[6];        long len;        char lenstr[22];        /* enough for 2^64 */        ap_snprintf(qstr, sizeof(qstr), "%1.3f", variant->type_quality);        /* Strip trailing zeros (saves those valuable network bytes) */        if (qstr[4] == '0') {            qstr[4] = '\0';            if (qstr[3] == '0') {                qstr[3] = '\0';                if (qstr[2] == '0') {                    qstr[1] = '\0';                }            }        }        rec = ap_pstrcat(r->pool, "{\"", variant->file_name, "\" ", qstr, NULL);        if (variant->type_name) {            if (*variant->type_name) {                rec = ap_pstrcat(r->pool, rec, " {type ",                              variant->type_name, "}", NULL);            }            if (!sample_type) {                sample_type = variant->type_name;            }            else if (strcmp(sample_type, variant->type_name)) {                vary_by_type = 1;            }        }        if (variant->content_languages && variant->content_languages->nelts) {            char *langs = merge_string_array(r->pool,                                           variant->content_languages, ",");            rec = ap_pstrcat(r->pool, rec, " {language ", langs, "}", NULL);            if (!sample_language) {                sample_language = langs;            }            else if (strcmp(sample_language, langs)) {                vary_by_language = 1;            }        }        if (variant->content_encoding) {            if (!sample_encoding) {                sample_encoding = variant->content_encoding;            }            else if (strcmp(sample_encoding, variant->content_encoding)) {                vary_by_encoding = 1;            }        }        if (variant->content_charset) {            if (*variant->content_charset) {                rec = ap_pstrcat(r->pool, rec, " {charset ",                              variant->content_charset, "}", NULL);            }            if (!sample_charset) {                sample_charset = variant->content_charset;            }            else if (strcmp(sample_charset, variant->content_charset)) {                vary_by_charset = 1;            }        }        if ((len = find_content_length(neg, variant)) != 0) {            ap_snprintf(lenstr, sizeof(lenstr), "%ld", len);            rec = ap_pstrcat(r->pool, rec, " {length ", lenstr, "}", NULL);        }        rec = ap_pstrcat(r->pool, rec, "}", NULL);        if (na_result != na_not_applied) {            ap_table_mergen(hdrs, "Alternates", rec);        }    }    if (na_result != na_not_applied) {        ap_table_mergen(hdrs, "Vary", "negotiate");    }    if (vary_by_type) {        ap_table_mergen(hdrs, "Vary", "accept");    }    if (vary_by_language) {        ap_table_mergen(hdrs, "Vary", "accept-language");    }    if (vary_by_charset) {        ap_table_mergen(hdrs, "Vary", "accept-charset");    }    if (vary_by_encoding && na_result == na_not_applied) {        ap_table_mergen(hdrs, "Vary", "accept-encoding");    }}/********************************************************************** * * Return an HTML list of variants. This is output as part of the * 300 or 406 status body. *//* XXX: this is disgusting, this has O(n^2) behaviour! -djg */static char *make_variant_list(request_rec *r, negotiation_state *neg){    int i;    char *t;    t = ap_pstrdup(r->pool, "Available variants:\n<ul>\n");    for (i = 0; i < neg->avail_vars->nelts; ++i) {        var_rec *variant = &((var_rec *) neg->avail_vars->elts)[i];        char *filename = variant->file_name ? variant->file_name : "";        array_header *languages = variant->content_languages;        char *description = variant->description ? variant->description : "";        /* The format isn't very neat, and it would be nice to make         * the tags human readable (eg replace 'language en' with         * 'English'). */        t = ap_pstrcat(r->pool, t, "<li><a href=\"", filename, "\">",                    filename, "</a> ", description, NULL);        if (variant->type_name && *variant->type_name) {            t = ap_pstrcat(r->pool, t, ", type ", variant->type_name, NULL);        }        if (languages && languages->nelts) {            t = ap_pstrcat(r->pool, t, ", language ",                        merge_string_array(r->pool, languages, ", "),                        NULL);        }        if (variant->content_charset && *variant->content_charset) {            t = ap_pstrcat(r->pool, t, ", charset ", variant->content_charset,                        NULL);        }        t = ap_pstrcat(r->pool, t, "\n", NULL);    }    t = ap_pstrcat(r->pool, t, "</ul>\n", NULL);    return t;}static void store_variant_list(request_rec *r, negotiation_state *neg){    if (r->main == NULL) {        ap_table_setn(r->notes, "variant-list", make_variant_list(r, neg));    }    else {        ap_table_setn(r->main->notes, "variant-list",                  make_variant_list(r->main, neg));    }}/* Called if we got a "Choice" response from the network algorithm. * It checks the result of the chosen variant to see if it * is itself negotiated (if so, return error VARIANT_ALSO_VARIES). * Otherwise, add the appropriate headers to the current response. */static int setup_choice_response(request_rec *r, negotiation_state *neg, var_rec *variant){    request_rec *sub_req;    const char *sub_vary;    if (!variant->sub_req) {        int status;        sub_req = ap_sub_req_lookup_file(variant->file_name, r);        status = sub_req->status;        if (status != HTTP_OK && status != HTTP_MULTIPLE_CHOICES) {            ap_destroy_sub_req(sub_req);            return status;        }        variant->sub_req = sub_req;    }    else {        sub_req = variant->sub_req;    }    /* The network algorithm told us to return a "Choice"     * response. This is the normal v

⌨️ 快捷键说明

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