On Sat, Sep 1, 2018 at 1:06 AM Graham Leggett <minf...@sharp.fm> wrote: > > In the case of the apr_table.h API, keys are case insensitive, meaning that > if we use apr_tables.h in turn apr_json.h will in turn no longer be RFC > compliant (object keys will fail comparisons), and therefore neither will any > of the JOSE code.
Ah yes, right, I miised that. > > As a result, we cannot use the apr_tables.h API for this and remain compliant. So how about the attached patch too, allowing for case sensitive apr_tables? :p apr_json could then use apr_table_make_ex()... Regards, Yann.
Index: include/apr_tables.h =================================================================== --- include/apr_tables.h (revision 1839763) +++ include/apr_tables.h (working copy) @@ -222,13 +222,26 @@ APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t * const apr_array_header_t *arr, const char sep); +#define APR_TABLE_CASELESS 0x1 /** ignore keys' case */ + /** * Make a new table. * @param p The pool to allocate the pool out of * @param nelts The number of elements in the initial table. + * @param flags Bitmask of APR_TABLE_* flags. * @return The new table. * @warning This table can only store text data */ +APR_DECLARE(apr_table_t *) apr_table_make_ex(apr_pool_t *p, int nelts, + int flags); + +/** + * Make a new table, ignoring keys' case. + * @param p The pool to allocate the pool out of + * @param nelts The number of elements in the initial table. + * @return The new table. + * @warning This table can only store text data + */ APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts); /** Index: tables/apr_tables.c =================================================================== --- tables/apr_tables.c (revision 1839763) +++ tables/apr_tables.c (working copy) @@ -303,9 +303,9 @@ APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t * * 4 bytes, normalized for case-insensitivity and packed into * an int...this checksum allows us to do a single integer * comparison as a fast check to determine whether we can - * skip a strcasecmp + * skip a str[case]cmp */ -#define COMPUTE_KEY_CHECKSUM(key, checksum) \ +#define COMPUTE_KEY_CHECKSUM(key, checksum, nc)\ { \ const char *k = (key); \ apr_uint32_t c = (apr_uint32_t)*k; \ @@ -325,7 +325,9 @@ APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t * c = (apr_uint32_t)*++k; \ checksum |= c; \ } \ - checksum &= CASE_MASK; \ + if ((nc)) { \ + checksum &= CASE_MASK; \ + } \ } /** The opaque string-content table type */ @@ -341,6 +343,10 @@ struct apr_table_t { /** Who created the array. */ void *creator; #endif + /** The compare function (str[case]cmp) */ + int (*cmp)(const char*, const char*); + /** Bitmask of APR_TABLE_* flags */ + int flags; /* An index to speed up table lookups. The way this works is: * - Hash the key into the index: * - index_first[TABLE_HASH(key)] is the offset within @@ -397,7 +403,8 @@ APR_DECLARE(int) apr_is_empty_table(const apr_tabl return ((t == NULL) || (t->a.nelts == 0)); } -APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts) +APR_DECLARE(apr_table_t *) apr_table_make_ex(apr_pool_t *p, int nelts, + int flags) { apr_table_t *t = apr_palloc(p, sizeof(apr_table_t)); @@ -406,9 +413,21 @@ APR_DECLARE(int) apr_is_empty_table(const apr_tabl t->creator = __builtin_return_address(0); #endif t->index_initialized = 0; + if (flags & APR_TABLE_CASELESS) { + t->cmp = strcasecmp; + } + else { + t->cmp = strcmp; + } + t->flags = flags; return t; } +APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts) +{ + return apr_table_make_ex(p, nelts, APR_TABLE_CASELESS); +} + APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool_t *p, const apr_table_t *t) { apr_table_t *new = apr_palloc(p, sizeof(apr_table_t)); @@ -428,6 +447,8 @@ APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool memcpy(new->index_first, t->index_first, sizeof(int) * TABLE_HASH_SIZE); memcpy(new->index_last, t->index_last, sizeof(int) * TABLE_HASH_SIZE); new->index_initialized = t->index_initialized; + new->flags = t->flags; + new->cmp = t->cmp; return new; } @@ -438,6 +459,9 @@ APR_DECLARE(apr_table_t *) apr_table_clone(apr_poo apr_table_t *new = apr_table_make(p, array->nelts); int i; + new->flags = t->flags; + new->cmp = t->cmp; + for (i = 0; i < array->nelts; i++) { apr_table_add(new, elts[i].key, elts[i].val); } @@ -483,13 +507,13 @@ APR_DECLARE(const char *) apr_table_get(const apr_ if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { return NULL; } - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash];; end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; for (; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { return next_elt->val; } } @@ -506,7 +530,7 @@ APR_DECLARE(void) apr_table_set(apr_table_t *t, co apr_uint32_t checksum; int hash; - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); hash = TABLE_HASH(key); if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { t->index_first[hash] = t->a.nelts; @@ -519,7 +543,7 @@ APR_DECLARE(void) apr_table_set(apr_table_t *t, co for (; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { /* Found an existing entry with the same key, so overwrite it */ @@ -531,7 +555,7 @@ APR_DECLARE(void) apr_table_set(apr_table_t *t, co /* Remove any other instances of this key */ for (next_elt++; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { t->a.nelts--; if (!dst_elt) { dst_elt = next_elt; @@ -578,7 +602,7 @@ APR_DECLARE(void) apr_table_setn(apr_table_t *t, c apr_uint32_t checksum; int hash; - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); hash = TABLE_HASH(key); if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { t->index_first[hash] = t->a.nelts; @@ -591,7 +615,7 @@ APR_DECLARE(void) apr_table_setn(apr_table_t *t, c for (; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { /* Found an existing entry with the same key, so overwrite it */ @@ -603,7 +627,7 @@ APR_DECLARE(void) apr_table_setn(apr_table_t *t, c /* Remove any other instances of this key */ for (next_elt++; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { t->a.nelts--; if (!dst_elt) { dst_elt = next_elt; @@ -654,13 +678,13 @@ APR_DECLARE(void) apr_table_unset(apr_table_t *t, if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { return; } - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash]; end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; must_reindex = 0; for (; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { /* Found a match: remove this entry, plus any additional * matches for the same key that might follow @@ -671,7 +695,7 @@ APR_DECLARE(void) apr_table_unset(apr_table_t *t, dst_elt = next_elt; for (next_elt++; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { t->a.nelts--; } else { @@ -703,7 +727,7 @@ APR_DECLARE(void) apr_table_merge(apr_table_t *t, apr_uint32_t checksum; int hash; - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); hash = TABLE_HASH(key); if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { t->index_first[hash] = t->a.nelts; @@ -715,7 +739,7 @@ APR_DECLARE(void) apr_table_merge(apr_table_t *t, for (; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { /* Found an existing entry with the same key, so merge with it */ next_elt->val = apr_pstrcat(t->a.pool, next_elt->val, ", ", @@ -758,7 +782,7 @@ APR_DECLARE(void) apr_table_mergen(apr_table_t *t, } #endif - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); hash = TABLE_HASH(key); if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { t->index_first[hash] = t->a.nelts; @@ -770,7 +794,7 @@ APR_DECLARE(void) apr_table_mergen(apr_table_t *t, for (; next_elt <= end_elt; next_elt++) { if ((checksum == next_elt->key_checksum) && - !strcasecmp(next_elt->key, key)) { + !t->cmp(next_elt->key, key)) { /* Found an existing entry with the same key, so merge with it */ next_elt->val = apr_pstrcat(t->a.pool, next_elt->val, ", ", @@ -800,7 +824,7 @@ APR_DECLARE(void) apr_table_add(apr_table_t *t, co t->index_first[hash] = t->a.nelts; TABLE_SET_INDEX_INITIALIZED(t, hash); } - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); elts = (apr_table_entry_t *) table_push(t); elts->key = apr_pstrdup(t->a.pool, key); elts->val = apr_pstrdup(t->a.pool, val); @@ -833,7 +857,7 @@ APR_DECLARE(void) apr_table_addn(apr_table_t *t, c t->index_first[hash] = t->a.nelts; TABLE_SET_INDEX_INITIALIZED(t, hash); } - COMPUTE_KEY_CHECKSUM(key, checksum); + COMPUTE_KEY_CHECKSUM(key, checksum, t->flags & APR_TABLE_CASELESS); elts = (apr_table_entry_t *) table_push(t); elts->key = (char *)key; elts->val = (char *)val; @@ -963,6 +987,7 @@ APR_DECLARE(int) apr_table_vdo(apr_table_do_callba { char *argp; apr_table_entry_t *elts = (apr_table_entry_t *) t->a.elts; + int nc = t->flags & APR_TABLE_CASELESS; int vdorv = 1; argp = va_arg(vp, char *); @@ -973,11 +998,11 @@ APR_DECLARE(int) apr_table_vdo(apr_table_do_callba int hash = TABLE_HASH(argp); if (TABLE_INDEX_IS_INITIALIZED(t, hash)) { apr_uint32_t checksum; - COMPUTE_KEY_CHECKSUM(argp, checksum); + COMPUTE_KEY_CHECKSUM(argp, checksum, nc); for (i = t->index_first[hash]; rv && (i <= t->index_last[hash]); ++i) { if (elts[i].key && (checksum == elts[i].key_checksum) && - !strcasecmp(elts[i].key, argp)) { + !t->cmp(elts[i].key, argp)) { rv = (*comp) (rec, elts[i].key, elts[i].val); } } @@ -999,21 +1024,21 @@ APR_DECLARE(int) apr_table_vdo(apr_table_do_callba return vdorv; } -static apr_table_entry_t **table_mergesort(apr_pool_t *pool, - apr_table_entry_t **values, - apr_size_t n) +static apr_table_entry_t **table_mergesort(apr_table_t *t, + apr_table_entry_t **values) { /* Bottom-up mergesort, based on design in Sedgewick's "Algorithms * in C," chapter 8 */ + apr_pool_t *pool = t->a.pool; + apr_size_t n = t->a.nelts, i; apr_table_entry_t **values_tmp = (apr_table_entry_t **)apr_palloc(pool, n * sizeof(apr_table_entry_t*)); - apr_size_t i; apr_size_t blocksize; /* First pass: sort pairs of elements (blocksize=1) */ for (i = 0; i + 1 < n; i += 2) { - if (strcasecmp(values[i]->key, values[i + 1]->key) > 0) { + if (t->cmp(values[i]->key, values[i + 1]->key) > 0) { apr_table_entry_t *swap = values[i]; values[i] = values[i + 1]; values[i + 1] = swap; @@ -1063,7 +1088,7 @@ APR_DECLARE(int) apr_table_vdo(apr_table_do_callba } break; } - if (strcasecmp(values[block1_start]->key, + if (t->cmp(values[block1_start]->key, values[block2_start]->key) > 0) { *dst++ = values[block2_start++]; } @@ -1129,7 +1154,7 @@ APR_DECLARE(void) apr_table_compress(apr_table_t * * time regardless of its inputs (quicksort is quadratic in * the worst case) */ - sort_array = table_mergesort(t->a.pool, sort_array, t->a.nelts); + sort_array = table_mergesort(t, sort_array); /* Process any duplicate keys */ dups_found = 0; @@ -1138,12 +1163,12 @@ APR_DECLARE(void) apr_table_compress(apr_table_t * last = sort_next++; while (sort_next < sort_end) { if (((*sort_next)->key_checksum == (*last)->key_checksum) && - !strcasecmp((*sort_next)->key, (*last)->key)) { + !t->cmp((*sort_next)->key, (*last)->key)) { apr_table_entry_t **dup_last = sort_next + 1; dups_found = 1; while ((dup_last < sort_end) && ((*dup_last)->key_checksum == (*last)->key_checksum) && - !strcasecmp((*dup_last)->key, (*last)->key)) { + !t->cmp((*dup_last)->key, (*last)->key)) { dup_last++; } dup_last--; /* Elements from last through dup_last, inclusive,