View | Details | Raw Unified | Return to bug 63288
Collapse All | Expand All

(-)modules/cache/cache_storage.c (-7 / +8 lines)
Lines 275-287 int cache_select(cache_request_rec *cache, request Link Here
275
             *
275
             *
276
             * RFC2616 13.6 and 14.44 describe the Vary mechanism.
276
             * RFC2616 13.6 and 14.44 describe the Vary mechanism.
277
             */
277
             */
278
            vary = cache_strqtok(
278
            for (rv = cache_strqtok(apr_pstrdup(r->pool,
279
                    apr_pstrdup(r->pool,
279
                                                cache_table_getm(r->pool,
280
                            cache_table_getm(r->pool, h->resp_hdrs, "Vary")),
280
                                                                 h->resp_hdrs,
281
                    CACHE_SEPARATOR, &last);
281
                                                                 "Vary")),
282
            while (vary) {
282
                                    &vary, NULL, &last);
283
                 rv == APR_SUCCESS;
284
                 rv = cache_strqtok(NULL, &vary, NULL, &last))
285
            {
283
                const char *h1, *h2;
286
                const char *h1, *h2;
284
285
                /*
287
                /*
286
                 * is this header in the request and the header in the cached
288
                 * is this header in the request and the header in the cached
287
                 * request identical? If not, we give up and do a straight get
289
                 * request identical? If not, we give up and do a straight get
Lines 301-307 int cache_select(cache_request_rec *cache, request Link Here
301
                    mismatch = 1;
303
                    mismatch = 1;
302
                    break;
304
                    break;
303
                }
305
                }
304
                vary = cache_strqtok(NULL, CACHE_SEPARATOR, &last);
305
            }
306
            }
306
307
307
            /* no vary match, try next provider */
308
            /* no vary match, try next provider */
(-)modules/cache/cache_util.c (-119 / +141 lines)
Lines 19-24 Link Here
19
#include "cache_util.h"
19
#include "cache_util.h"
20
#include <ap_provider.h>
20
#include <ap_provider.h>
21
21
22
#include "test_char.h"
23
22
APLOG_USE_MODULE(cache);
24
APLOG_USE_MODULE(cache);
23
25
24
/* -------------------------------------------------------------- */
26
/* -------------------------------------------------------------- */
Lines 923-997 CACHE_DECLARE(char *)ap_cache_generate_name(apr_po Link Here
923
}
925
}
924
926
925
/**
927
/**
926
 * String tokenizer that ignores separator characters within quoted strings
928
 * String tokenizer per RFC 7234 section 5.2 (1#token[=["]arg["]]).
927
 * and escaped characters, as per RFC2616 section 2.2.
929
 * If any (and arg not NULL), the argument is also returned (unquoted).
928
 */
930
 */
929
char *cache_strqtok(char *str, const char *sep, char **last)
931
apr_status_t cache_strqtok(char *str, char **token, char **arg, char **last)
930
{
932
{
931
    char *token;
933
#define CACHE_TOKEN_SEPS "\t ,"
932
    int quoted = 0;
934
    apr_status_t rv = APR_SUCCESS;
935
    enum {
936
        IN_TOKEN,
937
        IN_BETWEEN,
938
        IN_ARGUMENT,
939
        IN_QUOTES
940
    } state = IN_TOKEN;
941
    char *wpos;
933
942
934
    if (!str) {         /* subsequent call */
943
    if (!str) {         /* subsequent call */
935
        str = *last;    /* start where we left off */
944
        str = *last;    /* start where we left off */
936
    }
945
    }
937
938
    if (!str) {         /* no more tokens */
946
    if (!str) {         /* no more tokens */
939
        return NULL;
947
        return APR_EOF;
940
    }
948
    }
941
949
942
    /* skip characters in sep (will terminate at '\0') */
950
    /* skip separators (will terminate at '\0') */
943
    while (*str && ap_strchr_c(sep, *str)) {
951
    while (*str && TEST_CHAR(*str, T_HTTP_TOKEN_STOP)) {
952
        if (!ap_strchr_c(CACHE_TOKEN_SEPS, *str)) {
953
            return APR_EINVAL;
954
        }
944
        ++str;
955
        ++str;
945
    }
956
    }
946
947
    if (!*str) {        /* no more tokens */
957
    if (!*str) {        /* no more tokens */
948
        return NULL;
958
        return APR_EOF;
949
    }
959
    }
950
960
951
    token = str;
961
    *token = str;
962
    if (arg) {
963
        *arg = NULL;
964
    }
952
965
953
    /* skip valid token characters to terminate token and
966
    /* skip valid token characters to terminate token and
954
     * prepare for the next call (will terminate at '\0)
967
     * prepare for the next call (will terminate at '\0)
955
     * on the way, ignore all quoted strings, and within
968
     * on the way, handle quoted strings, and within
956
     * quoted strings, escaped characters.
969
     * quoted strings, escaped characters.
957
     */
970
     */
958
    *last = token;
971
    for (wpos = str; *str; ++str) {
959
    while (**last) {
972
        switch (state) {
960
        if (!quoted) {
973
        case IN_TOKEN:
961
            if (**last == '\"' && !ap_strchr_c(sep, '\"')) {
974
            if (*str == '=') {
962
                quoted = 1;
975
                state = IN_BETWEEN;
963
                ++*last;
976
                *wpos++ = '\0';
977
                *arg = wpos;
978
                continue;
964
            }
979
            }
965
            else if (!ap_strchr_c(sep, **last)) {
980
            break;
966
                ++*last;
981
982
        case IN_BETWEEN:
983
            if (*str == '"') {
984
                state = IN_QUOTES;
985
                continue;
967
            }
986
            }
968
            else {
987
            /* fall through */
969
                break;
988
            state = IN_ARGUMENT;
989
        case IN_ARGUMENT:
990
            if (TEST_CHAR(*str, T_HTTP_TOKEN_STOP)) {
991
                goto end;
970
            }
992
            }
971
        }
993
            break;
972
        else {
994
973
            if (**last == '\"') {
995
        default:
974
                quoted = 0;
996
            AP_DEBUG_ASSERT(state == IN_QUOTES);
975
                ++*last;
997
            if (*str == '"') {
998
                ++str;
999
                goto end;
976
            }
1000
            }
977
            else if (**last == '\\') {
1001
            if (*str == '\\' && *(str + 1)) {
978
                ++*last;
1002
                ++str;
979
                if (**last) {
980
                    ++*last;
981
                }
982
            }
1003
            }
983
            else {
1004
            break;
984
                ++*last;
985
            }
986
        }
1005
        }
1006
        *wpos++ = *str;
987
    }
1007
    }
988
1008
end:
989
    if (**last) {
1009
    /* anything after should be trailing OWS or comma */
990
        **last = '\0';
1010
    for (; *str; ++str) {
991
        ++*last;
1011
        if (*str == ',') {
1012
            ++str;
1013
            break;
1014
        }
1015
        if (*str != '\t' && *str != ' ') {
1016
            rv = APR_EINVAL;
1017
            break;
1018
        }
992
    }
1019
    }
993
1020
994
    return token;
1021
    *wpos = '\0';
1022
    *last = str;
1023
    return rv;
995
}
1024
}
996
1025
997
/**
1026
/**
Lines 1003-1008 int ap_cache_control(request_rec *r, cache_control Link Here
1003
        const char *cc_header, const char *pragma_header, apr_table_t *headers)
1032
        const char *cc_header, const char *pragma_header, apr_table_t *headers)
1004
{
1033
{
1005
    char *last;
1034
    char *last;
1035
    apr_status_t rv;
1006
1036
1007
    if (cc->parsed) {
1037
    if (cc->parsed) {
1008
        return cc->cache_control || cc->pragma;
1038
        return cc->cache_control || cc->pragma;
Lines 1015-1047 int ap_cache_control(request_rec *r, cache_control Link Here
1015
    cc->s_maxage_value = -1;
1045
    cc->s_maxage_value = -1;
1016
1046
1017
    if (pragma_header) {
1047
    if (pragma_header) {
1018
        char *header = apr_pstrdup(r->pool, pragma_header);
1048
        char *header = apr_pstrdup(r->pool, pragma_header), *token;
1019
        const char *token = cache_strqtok(header, CACHE_SEPARATOR, &last);
1049
        for (rv = cache_strqtok(header, &token, NULL, &last);
1020
        while (token) {
1050
             rv == APR_SUCCESS;
1051
             rv = cache_strqtok(NULL, &token, NULL, &last)) {
1021
            if (!ap_cstr_casecmp(token, "no-cache")) {
1052
            if (!ap_cstr_casecmp(token, "no-cache")) {
1022
                cc->no_cache = 1;
1053
                cc->no_cache = 1;
1023
            }
1054
            }
1024
            token = cache_strqtok(NULL, CACHE_SEPARATOR, &last);
1025
        }
1055
        }
1026
        cc->pragma = 1;
1056
        cc->pragma = 1;
1027
    }
1057
    }
1028
1058
1029
    if (cc_header) {
1059
    if (cc_header) {
1030
        char *endp;
1060
        char *header = apr_pstrdup(r->pool, cc_header), *token, *arg;
1031
        apr_off_t offt;
1061
        for (rv = cache_strqtok(header, &token, &arg, &last);
1032
        char *header = apr_pstrdup(r->pool, cc_header);
1062
             rv == APR_SUCCESS;
1033
        const char *token = cache_strqtok(header, CACHE_SEPARATOR, &last);
1063
             rv = cache_strqtok(NULL, &token, &arg, &last)) {
1034
        while (token) {
1064
            char *endp;
1065
            apr_off_t offt;
1066
1035
            switch (token[0]) {
1067
            switch (token[0]) {
1036
            case 'n':
1068
            case 'n':
1037
            case 'N': {
1069
            case 'N':
1038
                if (!ap_cstr_casecmpn(token, "no-cache", 8)) {
1070
                if (!ap_cstr_casecmp(token, "no-cache")) {
1039
                    if (token[8] == '=') {
1071
                    if (!arg) {
1072
                        cc->no_cache = 1;
1073
                    }
1074
                    else {
1040
                        cc->no_cache_header = 1;
1075
                        cc->no_cache_header = 1;
1041
                    }
1076
                    }
1042
                    else if (!token[8]) {
1043
                        cc->no_cache = 1;
1044
                    }
1045
                }
1077
                }
1046
                else if (!ap_cstr_casecmp(token, "no-store")) {
1078
                else if (!ap_cstr_casecmp(token, "no-store")) {
1047
                    cc->no_store = 1;
1079
                    cc->no_store = 1;
Lines 1050-1062 int ap_cache_control(request_rec *r, cache_control Link Here
1050
                    cc->no_transform = 1;
1082
                    cc->no_transform = 1;
1051
                }
1083
                }
1052
                break;
1084
                break;
1053
            }
1085
1054
            case 'm':
1086
            case 'm':
1055
            case 'M': {
1087
            case 'M':
1056
                if (!ap_cstr_casecmpn(token, "max-age", 7)) {
1088
                if (arg && !ap_cstr_casecmp(token, "max-age")) {
1057
                    if (token[7] == '='
1089
                    if (!apr_strtoff(&offt, arg, &endp, 10)
1058
                            && !apr_strtoff(&offt, token + 8, &endp, 10)
1090
                            && endp > arg && !*endp) {
1059
                            && endp > token + 8 && !*endp) {
1060
                        cc->max_age = 1;
1091
                        cc->max_age = 1;
1061
                        cc->max_age_value = offt;
1092
                        cc->max_age_value = offt;
1062
                    }
1093
                    }
Lines 1064-1122 int ap_cache_control(request_rec *r, cache_control Link Here
1064
                else if (!ap_cstr_casecmp(token, "must-revalidate")) {
1095
                else if (!ap_cstr_casecmp(token, "must-revalidate")) {
1065
                    cc->must_revalidate = 1;
1096
                    cc->must_revalidate = 1;
1066
                }
1097
                }
1067
                else if (!ap_cstr_casecmpn(token, "max-stale", 9)) {
1098
                else if (!ap_cstr_casecmp(token, "max-stale")) {
1068
                    if (token[9] == '='
1099
                    if (!arg) {
1069
                            && !apr_strtoff(&offt, token + 10, &endp, 10)
1070
                            && endp > token + 10 && !*endp) {
1071
                        cc->max_stale = 1;
1100
                        cc->max_stale = 1;
1072
                        cc->max_stale_value = offt;
1101
                        cc->max_stale_value = -1;
1073
                    }
1102
                    }
1074
                    else if (!token[9]) {
1103
                    else if (!apr_strtoff(&offt, arg, &endp, 10)
1104
                             && endp > arg && !*endp) {
1075
                        cc->max_stale = 1;
1105
                        cc->max_stale = 1;
1076
                        cc->max_stale_value = -1;
1106
                        cc->max_stale_value = offt;
1077
                    }
1107
                    }
1078
                }
1108
                }
1079
                else if (!ap_cstr_casecmpn(token, "min-fresh", 9)) {
1109
                else if (arg && !ap_cstr_casecmp(token, "min-fresh")) {
1080
                    if (token[9] == '='
1110
                    if (!apr_strtoff(&offt, arg, &endp, 10)
1081
                            && !apr_strtoff(&offt, token + 10, &endp, 10)
1111
                            && endp > arg && !*endp) {
1082
                            && endp > token + 10 && !*endp) {
1083
                        cc->min_fresh = 1;
1112
                        cc->min_fresh = 1;
1084
                        cc->min_fresh_value = offt;
1113
                        cc->min_fresh_value = offt;
1085
                    }
1114
                    }
1086
                }
1115
                }
1087
                break;
1116
                break;
1088
            }
1117
1089
            case 'o':
1118
            case 'o':
1090
            case 'O': {
1119
            case 'O':
1091
                if (!ap_cstr_casecmp(token, "only-if-cached")) {
1120
                if (!ap_cstr_casecmp(token, "only-if-cached")) {
1092
                    cc->only_if_cached = 1;
1121
                    cc->only_if_cached = 1;
1093
                }
1122
                }
1094
                break;
1123
                break;
1095
            }
1124
1096
            case 'p':
1125
            case 'p':
1097
            case 'P': {
1126
            case 'P':
1098
                if (!ap_cstr_casecmp(token, "public")) {
1127
                if (!ap_cstr_casecmp(token, "public")) {
1099
                    cc->public = 1;
1128
                    cc->public = 1;
1100
                }
1129
                }
1101
                else if (!ap_cstr_casecmpn(token, "private", 7)) {
1130
                else if (!ap_cstr_casecmp(token, "private")) {
1102
                    if (token[7] == '=') {
1131
                    if (!arg) {
1132
                        cc->private = 1;
1133
                    }
1134
                    else {
1103
                        cc->private_header = 1;
1135
                        cc->private_header = 1;
1104
                    }
1136
                    }
1105
                    else if (!token[7]) {
1106
                        cc->private = 1;
1107
                    }
1108
                }
1137
                }
1109
                else if (!ap_cstr_casecmp(token, "proxy-revalidate")) {
1138
                else if (!ap_cstr_casecmp(token, "proxy-revalidate")) {
1110
                    cc->proxy_revalidate = 1;
1139
                    cc->proxy_revalidate = 1;
1111
                }
1140
                }
1112
                break;
1141
                break;
1113
            }
1142
1114
            case 's':
1143
            case 's':
1115
            case 'S': {
1144
            case 'S':
1116
                if (!ap_cstr_casecmpn(token, "s-maxage", 8)) {
1145
                if (arg && !ap_cstr_casecmp(token, "s-maxage")) {
1117
                    if (token[8] == '='
1146
                    if (!apr_strtoff(&offt, arg, &endp, 10)
1118
                            && !apr_strtoff(&offt, token + 9, &endp, 10)
1147
                            && endp > arg && !*endp) {
1119
                            && endp > token + 9 && !*endp) {
1120
                        cc->s_maxage = 1;
1148
                        cc->s_maxage = 1;
1121
                        cc->s_maxage_value = offt;
1149
                        cc->s_maxage_value = offt;
1122
                    }
1150
                    }
Lines 1123-1130 int ap_cache_control(request_rec *r, cache_control Link Here
1123
                }
1151
                }
1124
                break;
1152
                break;
1125
            }
1153
            }
1126
            }
1127
            token = cache_strqtok(NULL, CACHE_SEPARATOR, &last);
1128
        }
1154
        }
1129
        cc->cache_control = 1;
1155
        cc->cache_control = 1;
1130
    }
1156
    }
Lines 1139-1186 int ap_cache_control(request_rec *r, cache_control Link Here
1139
static int cache_control_remove(request_rec *r, const char *cc_header,
1165
static int cache_control_remove(request_rec *r, const char *cc_header,
1140
        apr_table_t *headers)
1166
        apr_table_t *headers)
1141
{
1167
{
1142
    char *last, *slast;
1168
    char *last, *slast, *sheader;
1143
    int found = 0;
1169
    int found = 0;
1144
1170
1145
    if (cc_header) {
1171
    if (cc_header) {
1146
        char *header = apr_pstrdup(r->pool, cc_header);
1172
        apr_status_t rv;
1147
        char *token = cache_strqtok(header, CACHE_SEPARATOR, &last);
1173
        char *header = apr_pstrdup(r->pool, cc_header), *token, *arg;
1148
        while (token) {
1174
        for (rv = cache_strqtok(header, &token, &arg, &last);
1175
             rv == APR_SUCCESS;
1176
             rv = cache_strqtok(NULL, &token, &arg, &last)) {
1177
            if (!arg) {
1178
                continue;
1179
            }
1180
1149
            switch (token[0]) {
1181
            switch (token[0]) {
1150
            case 'n':
1182
            case 'n':
1151
            case 'N': {
1183
            case 'N':
1152
                if (!ap_cstr_casecmpn(token, "no-cache", 8)) {
1184
                if (!ap_cstr_casecmp(token, "no-cache")) {
1153
                    if (token[8] == '=') {
1185
                    for (rv = cache_strqtok(arg, &sheader, NULL, &slast);
1154
                        const char *header = cache_strqtok(token + 9,
1186
                         rv == APR_SUCCESS;
1155
                                CACHE_SEPARATOR "\"", &slast);
1187
                         rv = cache_strqtok(NULL, &sheader, NULL, &slast)) {
1156
                        while (header) {
1188
                        apr_table_unset(headers, sheader);
1157
                            apr_table_unset(headers, header);
1158
                            header = cache_strqtok(NULL, CACHE_SEPARATOR "\"",
1159
                                    &slast);
1160
                        }
1161
                        found = 1;
1162
                    }
1189
                    }
1190
                    found = 1;
1163
                }
1191
                }
1164
                break;
1192
                break;
1165
            }
1193
1166
            case 'p':
1194
            case 'p':
1167
            case 'P': {
1195
            case 'P':
1168
                if (!ap_cstr_casecmpn(token, "private", 7)) {
1196
                if (!ap_cstr_casecmp(token, "private")) {
1169
                    if (token[7] == '=') {
1197
                    for (rv = cache_strqtok(arg, &sheader, NULL, &slast);
1170
                        const char *header = cache_strqtok(token + 8,
1198
                         rv == APR_SUCCESS;
1171
                                CACHE_SEPARATOR "\"", &slast);
1199
                         rv = cache_strqtok(NULL, &sheader, NULL, &slast)) {
1172
                        while (header) {
1200
                        apr_table_unset(headers, sheader);
1173
                            apr_table_unset(headers, header);
1174
                            header = cache_strqtok(NULL, CACHE_SEPARATOR "\"",
1175
                                    &slast);
1176
                        }
1177
                        found = 1;
1178
                    }
1201
                    }
1202
                    found = 1;
1179
                }
1203
                }
1180
                break;
1204
                break;
1181
            }
1205
            }
1182
            }
1183
            token = cache_strqtok(NULL, CACHE_SEPARATOR, &last);
1184
        }
1206
        }
1185
    }
1207
    }
1186
1208
(-)modules/cache/cache_util.h (-4 / +3 lines)
Lines 99-105 extern "C" { Link Here
99
#define CACHE_LOCKNAME_KEY "mod_cache-lockname"
99
#define CACHE_LOCKNAME_KEY "mod_cache-lockname"
100
#define CACHE_LOCKFILE_KEY "mod_cache-lockfile"
100
#define CACHE_LOCKFILE_KEY "mod_cache-lockfile"
101
#define CACHE_CTX_KEY "mod_cache-ctx"
101
#define CACHE_CTX_KEY "mod_cache-ctx"
102
#define CACHE_SEPARATOR ", \t"
103
102
104
/**
103
/**
105
 * cache_util.c
104
 * cache_util.c
Lines 316-325 const char *cache_table_getm(apr_pool_t *p, const Link Here
316
        const char *key);
315
        const char *key);
317
316
318
/**
317
/**
319
 * String tokenizer that ignores separator characters within quoted strings
318
 * String tokenizer per RFC 7234 section 5.2 (1#token[=["]arg["]]).
320
 * and escaped characters, as per RFC2616 section 2.2.
319
 * If any (and arg not NULL), the argument is also returned (unquoted).
321
 */
320
 */
322
char *cache_strqtok(char *str, const char *sep, char **last);
321
apr_status_t cache_strqtok(char *str, char **token, char **arg, char **last);
323
322
324
/**
323
/**
325
 * Merge err_headers_out into headers_out and add request's Content-Type and
324
 * Merge err_headers_out into headers_out and add request's Content-Type and
(-)modules/loggers/mod_log_forensic.c (-2 / +2 lines)
Lines 123-129 static char *log_escape(char *q, const char *e, co Link Here
123
{
123
{
124
    for ( ; *p ; ++p) {
124
    for ( ; *p ; ++p) {
125
        ap_assert(q < e);
125
        ap_assert(q < e);
126
        if (test_char_table[*(unsigned char *)p]&T_ESCAPE_FORENSIC) {
126
        if (TEST_CHAR(*p, T_ESCAPE_FORENSIC)) {
127
            ap_assert(q+2 < e);
127
            ap_assert(q+2 < e);
128
            *q++ = '%';
128
            *q++ = '%';
129
            ap_bin2hex(p, 1, q);
129
            ap_bin2hex(p, 1, q);
Lines 151-157 static int count_string(const char *p) Link Here
151
    int n;
151
    int n;
152
152
153
    for (n = 0 ; *p ; ++p, ++n)
153
    for (n = 0 ; *p ; ++p, ++n)
154
        if (test_char_table[*(unsigned char *)p]&T_ESCAPE_FORENSIC)
154
        if (TEST_CHAR(*p, T_ESCAPE_FORENSIC))
155
            n += 2;
155
            n += 2;
156
    return n;
156
    return n;
157
}
157
}
(-)server/gen_test_char.c (-1 / +10 lines)
Lines 167-173 int main(int argc, char *argv[]) Link Here
167
        printf("0x%03x%c", flags, (c < 255) ? ',' : ' ');
167
        printf("0x%03x%c", flags, (c < 255) ? ',' : ' ');
168
    }
168
    }
169
169
170
    printf("\n};\n");
170
    printf("\n};\n\n");
171
171
172
    printf(
173
      "/* we assume the folks using this ensure 0 <= c < 256... which means\n"
174
      " * you need a cast to (unsigned char) first, you can't just plug a\n"
175
      " * char in here and get it to work, because if char is signed then it\n"
176
      " * will first be sign extended.\n"
177
      " */\n"
178
      "#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))\n"
179
    );
180
172
    return 0;
181
    return 0;
173
}
182
}
(-)server/util.c (-7 lines)
Lines 74-86 Link Here
74
 */
74
 */
75
#include "test_char.h"
75
#include "test_char.h"
76
76
77
/* we assume the folks using this ensure 0 <= c < 256... which means
78
 * you need a cast to (unsigned char) first, you can't just plug a
79
 * char in here and get it to work, because if char is signed then it
80
 * will first be sign extended.
81
 */
82
#define TEST_CHAR(c, f)        (test_char_table[(unsigned char)(c)] & (f))
83
84
/* Win32/NetWare/OS2 need to check for both forward and back slashes
77
/* Win32/NetWare/OS2 need to check for both forward and back slashes
85
 * in ap_getparents() and ap_escape_url.
78
 * in ap_getparents() and ap_escape_url.
86
 */
79
 */

Return to bug 63288