Author: brane Date: Thu Jun 26 03:01:58 2025 New Revision: 1926729 URL: http://svn.apache.org/viewvc?rev=1926729&view=rev Log: On the user-defined-authn branch: Detect and parse authn parameters that are a single (possibly base-64) token.
* serf.h (serf_authn_get_realm_func_t): Update docstring for the single-token case. * serf_private.h (serf__parse_authn_parameters): Likewise. * src/genctype.py: Generate token68 bits. * src/syntax.c: Include apr.h, for apr_uint32_t. (CT_WHITESPACE): Rename from CT_HTTP_SPACE, change value. (CT_TOKEN): Rename from CT_HTTP_TOKEN, also change value. (CT_TOKEN68): New; for punctuation that's allowed in a token68. (char_table): Change type to apr_uint32_t and update contents. (ct_istoken): Update the bit mask. (ct_istoken68, skip_token68): New. (serf__parse_authn_parameters): Detect a single token68 parameter. Detect when two parameters are not separated by a comma. * test/test_internal.c (test_parse_bad_parameters): Remove the "unexpected" result, and the one case that now passes as a token68 parameter. (test_parse_single_token_parameters): New, test cases for token68. (test_internal): Register the new test. Modified: serf/branches/user-defined-authn/serf.h serf/branches/user-defined-authn/serf_private.h serf/branches/user-defined-authn/src/genctype.py serf/branches/user-defined-authn/src/syntax.c serf/branches/user-defined-authn/test/test_internal.c Modified: serf/branches/user-defined-authn/serf.h URL: http://svn.apache.org/viewvc/serf/branches/user-defined-authn/serf.h?rev=1926729&r1=1926728&r2=1926729&view=diff ============================================================================== --- serf/branches/user-defined-authn/serf.h (original) +++ serf/branches/user-defined-authn/serf.h Thu Jun 26 03:01:58 2025 @@ -1032,10 +1032,14 @@ typedef apr_status_t * * @a authn_header and @a authn_parameters come from the authentication header * (WWW-Authenticate or Proxy-Authenticate) recevied in a server response. + * * @a authn_header is the header value, i.e., "scheme <parameters>"; + * * @a authn_parameters is a dictionary of the authentication parameters * and their values, e.g., `realm="Wonderland"`. The keys are always folded - * to lower case. + * to lower case. If the parameter is a single token, it is returned in the + * dictionary as the value of the empty string key (""). + * @see https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2 * * If the scheme flag @a SERF_AUTHN_FLAG_PIPE is *not* set, pipelining will be * disabled on the connection after this callback succeeds. Modified: serf/branches/user-defined-authn/serf_private.h URL: http://svn.apache.org/viewvc/serf/branches/user-defined-authn/serf_private.h?rev=1926729&r1=1926728&r2=1926729&view=diff ============================================================================== --- serf/branches/user-defined-authn/serf_private.h (original) +++ serf/branches/user-defined-authn/serf_private.h Thu Jun 26 03:01:58 2025 @@ -750,11 +750,12 @@ serf__authn_info_t *serf__get_authn_info /* Parse authentication scheme parameters from a WWW-Authenticate or Proxy-Authenticate header. Splits the comma-separated token=value - or token="quoted \" value" pairs into a dictionary. + or token="quoted \" value" pairs into a dictionary. If the parameters + are a single token, it's stored as the value of the empty string key. The keys in the dictionary will be folded to lowercase. - See: https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6 */ + See: https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2 */ apr_hash_t *serf__parse_authn_parameters(const char *attrs, apr_pool_t *pool); /* Fold ASCII uppercase letters to lowercase, in place, using the same Modified: serf/branches/user-defined-authn/src/genctype.py URL: http://svn.apache.org/viewvc/serf/branches/user-defined-authn/src/genctype.py?rev=1926729&r1=1926728&r2=1926729&view=diff ============================================================================== --- serf/branches/user-defined-authn/src/genctype.py (original) +++ serf/branches/user-defined-authn/src/genctype.py Thu Jun 26 03:01:58 2025 @@ -51,10 +51,13 @@ utf8_invalid = frozenset((0xE0, 0xF0, 0x # HTTP classes: whitespace and token punctuation http_space = (9, 32) -http_token_punct = frozenset(( +token_punct = frozenset(( 33, 35, 36, 37, 38, 39, 42, 43, 45, 46, 94, 95, 96, 124, 126)) # ! # $ % & ' * + - . ^ _ ` | ~ +token68_punct = frozenset((43, 45, 46, 47, 95, 126)) +# + - . / _ ~ + print(' /* **** DO NOT EDIT! ****') print(' This table was generated by genctype.py, make changes there. */') @@ -78,7 +81,7 @@ for c in range(256): if c in whitespace: bits.append('CT_SPACE') if c in http_space: - bits.append('CT_HTTP_SPACE') + bits.append('CT_WHITESPACE') # Punctuation marks if c >= 33 and c < 48 \ @@ -86,18 +89,14 @@ for c in range(256): or c >= 91 and c < 97 \ or c >= 123 and c < 127: bits.append('CT_PUNCT') - if c in http_token_punct: - bits.append('CT_HTTP_TOKEN') # Decimal digits elif c >= 48 and c < 58: bits.append('CT_DIGIT') - bits.append('CT_HTTP_TOKEN') # Uppercase letters elif c >= 65 and c < 91: bits.append('CT_UPPER') - bits.append('CT_HTTP_TOKEN') # Hexadecimal digits if c <= 70: bits.append('CT_XALPHA') @@ -105,11 +104,16 @@ for c in range(256): # Lowercase letters elif c >= 97 and c < 123: bits.append('CT_LOWER') - bits.append('CT_HTTP_TOKEN') # Hexadecimal digits if c <= 102: bits.append('CT_XALPHA') + # token and token68 + if c in token_punct: + bits.append('CT_TOKEN') + if c in token68_punct: + bits.append('CT_TOKEN68') + # UTF-8 multibyte sequences else: name = hex(c)[1:] Modified: serf/branches/user-defined-authn/src/syntax.c URL: http://svn.apache.org/viewvc/serf/branches/user-defined-authn/src/syntax.c?rev=1926729&r1=1926728&r2=1926729&view=diff ============================================================================== --- serf/branches/user-defined-authn/src/syntax.c (original) +++ serf/branches/user-defined-authn/src/syntax.c Thu Jun 26 03:01:58 2025 @@ -18,6 +18,7 @@ * ==================================================================== */ +#include <apr.h> #include <apr_pools.h> #include <apr_hash.h> @@ -26,32 +27,42 @@ /* Character classes */ -#define CT_ASCII 0x0001 -#define CT_CNTRL 0x0002 -#define CT_SPACE 0x0004 -#define CT_PUNCT 0x0008 -#define CT_DIGIT 0x0010 -#define CT_UPPER 0x0020 -#define CT_LOWER 0x0040 -#define CT_XALPHA 0x0080 -#define CT_UTF8_CONT 0x0100 -#define CT_UTF8_LEAD 0x0200 +#define CT_ASCII 0x0001 +#define CT_CNTRL 0x0002 +#define CT_SPACE 0x0004 +#define CT_PUNCT 0x0008 +#define CT_DIGIT 0x0010 +#define CT_UPPER 0x0020 +#define CT_LOWER 0x0040 +#define CT_XALPHA 0x0080 +#define CT_UTF8_CONT 0x0100 +#define CT_UTF8_LEAD 0x0200 /* Only space and the horizontal tab are treated as whitespace. */ -#define CT_HTTP_SPACE 0x1000 +#define CT_WHITESPACE 0x010000 -/* Characters that are allowed in tokens, accorting to RFC 9110, are the - ASCII digits, lowercase and uppercase letters, and the following - punctiation marks: +/* A `token` is a sequence of ASCII digits, lowercase and uppercase letters, + and the following punctiation marks: ! # $ % & ' * + - . ^ _ ` | ~ - Whitespace and all other printable ASCII characters are delimiters. */ -#define CT_HTTP_TOKEN 0x2000 + See: https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.2 +*/ +#define CT_TOKEN 0x020000 + +/* A `token68` is a sequence of ASCII digits, lowercase and uppercase letters, + and the following punctiation marks: + + - . _ ~ + / + + followed by zero or more `=` signs. + See: https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2 +*/ +#define CT_TOKEN68 0x040000 /* ASCII + UTF-8 character table, stolen wholesale from Subversion. */ -static const unsigned short char_table[256] = +static const apr_uint32_t char_table[256] = { /* **** DO NOT EDIT! **** This table was generated by genctype.py, make changes there. */ @@ -64,7 +75,7 @@ static const unsigned short char_table[2 /* ack */ CT_ASCII | CT_CNTRL, /* bel */ CT_ASCII | CT_CNTRL, /* bs */ CT_ASCII | CT_CNTRL, - /* ht */ CT_ASCII | CT_CNTRL | CT_SPACE | CT_HTTP_SPACE, + /* ht */ CT_ASCII | CT_CNTRL | CT_SPACE | CT_WHITESPACE, /* nl */ CT_ASCII | CT_CNTRL | CT_SPACE, /* vt */ CT_ASCII | CT_CNTRL | CT_SPACE, /* np */ CT_ASCII | CT_CNTRL | CT_SPACE, @@ -87,32 +98,32 @@ static const unsigned short char_table[2 /* gs */ CT_ASCII | CT_CNTRL, /* rs */ CT_ASCII | CT_CNTRL, /* us */ CT_ASCII | CT_CNTRL, - /* sp */ CT_ASCII | CT_SPACE | CT_HTTP_SPACE, - /* ! */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, + /* sp */ CT_ASCII | CT_SPACE | CT_WHITESPACE, + /* ! */ CT_ASCII | CT_PUNCT | CT_TOKEN, /* " */ CT_ASCII | CT_PUNCT, - /* # */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* $ */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* % */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* & */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* ' */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, + /* # */ CT_ASCII | CT_PUNCT | CT_TOKEN, + /* $ */ CT_ASCII | CT_PUNCT | CT_TOKEN, + /* % */ CT_ASCII | CT_PUNCT | CT_TOKEN, + /* & */ CT_ASCII | CT_PUNCT | CT_TOKEN, + /* ' */ CT_ASCII | CT_PUNCT | CT_TOKEN, /* ( */ CT_ASCII | CT_PUNCT, /* ) */ CT_ASCII | CT_PUNCT, - /* * */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* + */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, + /* * */ CT_ASCII | CT_PUNCT | CT_TOKEN, + /* + */ CT_ASCII | CT_PUNCT | CT_TOKEN | CT_TOKEN68, /* , */ CT_ASCII | CT_PUNCT, - /* - */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* . */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* / */ CT_ASCII | CT_PUNCT, - /* 0 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 1 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 2 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 3 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 4 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 5 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 6 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 7 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 8 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, - /* 9 */ CT_ASCII | CT_DIGIT | CT_HTTP_TOKEN, + /* - */ CT_ASCII | CT_PUNCT | CT_TOKEN | CT_TOKEN68, + /* . */ CT_ASCII | CT_PUNCT | CT_TOKEN | CT_TOKEN68, + /* / */ CT_ASCII | CT_PUNCT | CT_TOKEN68, + /* 0 */ CT_ASCII | CT_DIGIT, + /* 1 */ CT_ASCII | CT_DIGIT, + /* 2 */ CT_ASCII | CT_DIGIT, + /* 3 */ CT_ASCII | CT_DIGIT, + /* 4 */ CT_ASCII | CT_DIGIT, + /* 5 */ CT_ASCII | CT_DIGIT, + /* 6 */ CT_ASCII | CT_DIGIT, + /* 7 */ CT_ASCII | CT_DIGIT, + /* 8 */ CT_ASCII | CT_DIGIT, + /* 9 */ CT_ASCII | CT_DIGIT, /* : */ CT_ASCII | CT_PUNCT, /* ; */ CT_ASCII | CT_PUNCT, /* < */ CT_ASCII | CT_PUNCT, @@ -120,68 +131,68 @@ static const unsigned short char_table[2 /* > */ CT_ASCII | CT_PUNCT, /* ? */ CT_ASCII | CT_PUNCT, /* @ */ CT_ASCII | CT_PUNCT, - /* A */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN | CT_XALPHA, - /* B */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN | CT_XALPHA, - /* C */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN | CT_XALPHA, - /* D */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN | CT_XALPHA, - /* E */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN | CT_XALPHA, - /* F */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN | CT_XALPHA, - /* G */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* H */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* I */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* J */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* K */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* L */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* M */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* N */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* O */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* P */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* Q */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* R */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* S */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* T */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* U */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* V */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* W */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* X */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* Y */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, - /* Z */ CT_ASCII | CT_UPPER | CT_HTTP_TOKEN, + /* A */ CT_ASCII | CT_UPPER | CT_XALPHA, + /* B */ CT_ASCII | CT_UPPER | CT_XALPHA, + /* C */ CT_ASCII | CT_UPPER | CT_XALPHA, + /* D */ CT_ASCII | CT_UPPER | CT_XALPHA, + /* E */ CT_ASCII | CT_UPPER | CT_XALPHA, + /* F */ CT_ASCII | CT_UPPER | CT_XALPHA, + /* G */ CT_ASCII | CT_UPPER, + /* H */ CT_ASCII | CT_UPPER, + /* I */ CT_ASCII | CT_UPPER, + /* J */ CT_ASCII | CT_UPPER, + /* K */ CT_ASCII | CT_UPPER, + /* L */ CT_ASCII | CT_UPPER, + /* M */ CT_ASCII | CT_UPPER, + /* N */ CT_ASCII | CT_UPPER, + /* O */ CT_ASCII | CT_UPPER, + /* P */ CT_ASCII | CT_UPPER, + /* Q */ CT_ASCII | CT_UPPER, + /* R */ CT_ASCII | CT_UPPER, + /* S */ CT_ASCII | CT_UPPER, + /* T */ CT_ASCII | CT_UPPER, + /* U */ CT_ASCII | CT_UPPER, + /* V */ CT_ASCII | CT_UPPER, + /* W */ CT_ASCII | CT_UPPER, + /* X */ CT_ASCII | CT_UPPER, + /* Y */ CT_ASCII | CT_UPPER, + /* Z */ CT_ASCII | CT_UPPER, /* [ */ CT_ASCII | CT_PUNCT, /* \ */ CT_ASCII | CT_PUNCT, /* ] */ CT_ASCII | CT_PUNCT, - /* ^ */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* _ */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* ` */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, - /* a */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN | CT_XALPHA, - /* b */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN | CT_XALPHA, - /* c */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN | CT_XALPHA, - /* d */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN | CT_XALPHA, - /* e */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN | CT_XALPHA, - /* f */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN | CT_XALPHA, - /* g */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* h */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* i */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* j */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* k */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* l */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* m */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* n */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* o */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* p */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* q */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* r */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* s */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* t */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* u */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* v */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* w */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* x */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* y */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, - /* z */ CT_ASCII | CT_LOWER | CT_HTTP_TOKEN, + /* ^ */ CT_ASCII | CT_PUNCT | CT_TOKEN, + /* _ */ CT_ASCII | CT_PUNCT | CT_TOKEN | CT_TOKEN68, + /* ` */ CT_ASCII | CT_PUNCT | CT_TOKEN, + /* a */ CT_ASCII | CT_LOWER | CT_XALPHA, + /* b */ CT_ASCII | CT_LOWER | CT_XALPHA, + /* c */ CT_ASCII | CT_LOWER | CT_XALPHA, + /* d */ CT_ASCII | CT_LOWER | CT_XALPHA, + /* e */ CT_ASCII | CT_LOWER | CT_XALPHA, + /* f */ CT_ASCII | CT_LOWER | CT_XALPHA, + /* g */ CT_ASCII | CT_LOWER, + /* h */ CT_ASCII | CT_LOWER, + /* i */ CT_ASCII | CT_LOWER, + /* j */ CT_ASCII | CT_LOWER, + /* k */ CT_ASCII | CT_LOWER, + /* l */ CT_ASCII | CT_LOWER, + /* m */ CT_ASCII | CT_LOWER, + /* n */ CT_ASCII | CT_LOWER, + /* o */ CT_ASCII | CT_LOWER, + /* p */ CT_ASCII | CT_LOWER, + /* q */ CT_ASCII | CT_LOWER, + /* r */ CT_ASCII | CT_LOWER, + /* s */ CT_ASCII | CT_LOWER, + /* t */ CT_ASCII | CT_LOWER, + /* u */ CT_ASCII | CT_LOWER, + /* v */ CT_ASCII | CT_LOWER, + /* w */ CT_ASCII | CT_LOWER, + /* x */ CT_ASCII | CT_LOWER, + /* y */ CT_ASCII | CT_LOWER, + /* z */ CT_ASCII | CT_LOWER, /* { */ CT_ASCII | CT_PUNCT, - /* | */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, + /* | */ CT_ASCII | CT_PUNCT | CT_TOKEN, /* } */ CT_ASCII | CT_PUNCT, - /* ~ */ CT_ASCII | CT_PUNCT | CT_HTTP_TOKEN, + /* ~ */ CT_ASCII | CT_PUNCT | CT_TOKEN | CT_TOKEN68, /* del */ CT_ASCII | CT_CNTRL, /* x80 */ CT_UTF8_CONT, /* x81 */ CT_UTF8_CONT, @@ -245,13 +256,6 @@ static const unsigned short char_table[2 /* xbb */ CT_UTF8_CONT, /* xbc */ CT_UTF8_CONT, /* xbd */ CT_UTF8_CONT, - /* xbe */ CT_UTF8_CONT, - /* xbf */ CT_UTF8_CONT, - /* xc0 */ 0, - /* xc1 */ CT_UTF8_LEAD, - /* xc2 */ CT_UTF8_LEAD, - /* xc3 */ CT_UTF8_LEAD, - /* xc4 */ CT_UTF8_LEAD, /* xc5 */ CT_UTF8_LEAD, /* xc6 */ CT_UTF8_LEAD, /* xc7 */ CT_UTF8_LEAD, @@ -316,12 +320,19 @@ static const unsigned short char_table[2 /* Character class lookup */ static APR_INLINE int ct_isspace(char c) { - return char_table[(unsigned char)c] & CT_HTTP_SPACE; + return char_table[(unsigned char)c] & CT_WHITESPACE; } static APR_INLINE int ct_istoken(char c) { - return char_table[(unsigned char)c] & CT_HTTP_TOKEN; + static const apr_uint32_t ct = CT_TOKEN | CT_DIGIT | CT_UPPER | CT_LOWER; + return ct & char_table[(unsigned char)c]; +} + +static APR_INLINE int ct_istoken68(char c) +{ + static const apr_uint32_t ct = CT_TOKEN68 | CT_DIGIT | CT_UPPER | CT_LOWER; + return ct & char_table[(unsigned char)c]; } @@ -362,6 +373,15 @@ static const char *skip_space(const char return src; } +static const char *skip_token68(const char *src) +{ + while (ct_istoken68(*src)) + ++src; + while (*src == '=') + ++src; + return src; +} + #if 0 static const char *skip_comment(const char *src) { @@ -431,10 +451,19 @@ static const char *copy_token(char **dst apr_hash_t *serf__parse_authn_parameters(const char *attrs, apr_pool_t *pool) { apr_hash_t *dict = apr_hash_make(pool); - char *dst = apr_palloc(pool, strlen(attrs)); - const char *src = attrs; + char *dst = apr_palloc(pool, strlen(attrs) + 1); + const char *src = skip_space(attrs); + const char *end = skip_token68(src); bool want_comma = false; + /* Check if the parameters are a single token68. */ + if (end != src && !*skip_space(end)) { + memcpy(dst, src, end - src); + dst[end - src] = '\0'; + apr_hash_set(dict, "", 0, dst); + return dict; + } + while (src && *src) { const char *key; @@ -473,7 +502,8 @@ apr_hash_t *serf__parse_authn_parameters *dst++ = '\0'; /* Must be at the end of the string or at a valid separator. */ - if (*src && *src != ',' && !ct_isspace(*src)) + src = skip_space(src); + if (*src && *src != ',') break; /* Put the new key/value pair into the dict. */ Modified: serf/branches/user-defined-authn/test/test_internal.c URL: http://svn.apache.org/viewvc/serf/branches/user-defined-authn/test/test_internal.c?rev=1926729&r1=1926728&r2=1926729&view=diff ============================================================================== --- serf/branches/user-defined-authn/test/test_internal.c (original) +++ serf/branches/user-defined-authn/test/test_internal.c Thu Jun 26 03:01:58 2025 @@ -510,19 +510,14 @@ static void test_parse_bad_parameters(Cu static const struct expected_attrs expected[] = { { NULL, NULL } }; - static const struct expected_attrs unexpected[] = { - { "key", "value1" }, - { NULL, NULL } - }; parse_parameters(tc, "", expected); parse_parameters(tc, "\t", expected); parse_parameters(tc, "(comm", expected); - parse_parameters(tc, "key", expected); parse_parameters(tc, "key=\"value", expected); parse_parameters(tc, "key = value", expected); parse_parameters(tc, "key=\"value1\"key=value2", expected); - parse_parameters(tc, "key=value1 key=value2", unexpected); + parse_parameters(tc, "key=value1 key=value2", expected); } static void test_parse_repeated_parameters(CuTest *tc) @@ -535,6 +530,17 @@ static void test_parse_repeated_paramete parse_parameters(tc, "key=value1, key=value2", expected); } +static void test_parse_single_token_parameters(CuTest *tc) +{ + static const struct expected_attrs expected[] = { + { "", "Alice/In+Wonderland.==" }, + { NULL, NULL } + }; + + parse_parameters(tc, "\tAlice/In+Wonderland.== ", expected); + parse_parameters(tc, "Alice=In+Wonderland.=", &expected[1]); +} + static void test_parameter_case_folding(CuTest *tc) { static const struct expected_attrs expected[] = { @@ -564,6 +570,7 @@ CuSuite *test_internal(void) SUITE_ADD_TEST(suite, test_parse_parameters); SUITE_ADD_TEST(suite, test_parse_bad_parameters); SUITE_ADD_TEST(suite, test_parse_repeated_parameters); + SUITE_ADD_TEST(suite, test_parse_single_token_parameters); SUITE_ADD_TEST(suite, test_parameter_case_folding); return suite;