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,

Reply via email to