Retrieve an HTTP header field list item, as separated by a comma, * while stripping insignificant whitespace and lowercasing anything not in * a quoted string or comment. The return value is a new string containing * the converted list item (or NULL if none) and the address pointed to by * field is shifted to the next non-comma, non-whitespace. */
| 1312 | * field is shifted to the next non-comma, non-whitespace. |
| 1313 | */ |
| 1314 | AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field) |
| 1315 | { |
| 1316 | const char *tok_start; |
| 1317 | const unsigned char *ptr; |
| 1318 | unsigned char *pos; |
| 1319 | char *token; |
| 1320 | int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0; |
| 1321 | |
| 1322 | /* Find the beginning and maximum length of the list item so that |
| 1323 | * we can allocate a buffer for the new string and reset the field. |
| 1324 | */ |
| 1325 | if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) { |
| 1326 | return NULL; |
| 1327 | } |
| 1328 | token = apr_palloc(p, tok_len + 1); |
| 1329 | |
| 1330 | /* Scan the token again, but this time copy only the good bytes. |
| 1331 | * We skip extra whitespace and any whitespace around a '=', '/', |
| 1332 | * or ';' and lowercase normal characters not within a comment, |
| 1333 | * quoted-string or quoted-pair. |
| 1334 | */ |
| 1335 | for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token; |
| 1336 | *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); |
| 1337 | ++ptr) { |
| 1338 | |
| 1339 | if (in_qpair) { |
| 1340 | in_qpair = 0; |
| 1341 | *pos++ = *ptr; |
| 1342 | } |
| 1343 | else { |
| 1344 | switch (*ptr) { |
| 1345 | case '\\': in_qpair = 1; |
| 1346 | if (addspace == 1) |
| 1347 | *pos++ = ' '; |
| 1348 | *pos++ = *ptr; |
| 1349 | addspace = 0; |
| 1350 | break; |
| 1351 | case '"' : if (!in_com) |
| 1352 | in_qstr = !in_qstr; |
| 1353 | if (addspace == 1) |
| 1354 | *pos++ = ' '; |
| 1355 | *pos++ = *ptr; |
| 1356 | addspace = 0; |
| 1357 | break; |
| 1358 | case '(' : if (!in_qstr) |
| 1359 | ++in_com; |
| 1360 | if (addspace == 1) |
| 1361 | *pos++ = ' '; |
| 1362 | *pos++ = *ptr; |
| 1363 | addspace = 0; |
| 1364 | break; |
| 1365 | case ')' : if (in_com) |
| 1366 | --in_com; |
| 1367 | *pos++ = *ptr; |
| 1368 | addspace = 0; |
| 1369 | break; |
| 1370 | case ' ' : |
| 1371 | case '\t': if (addspace) |