On Sat, Sep 1, 2018 at 1:06 AM Graham Leggett <[email protected]> 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,