r"""Parse header values into a list of lists containing key,value pairs. The function knows how to deal with ",", ";" and "=" as well as quoted values after "=". A list of space separated tokens are parsed as if they were separated by ";". If the header_values passed as argument c
(header_values)
| 346 | HEADER_VALUE_RE = re.compile(r"^\s*=\s*([^\s;,]*)") |
| 347 | HEADER_ESCAPE_RE = re.compile(r"\\(.)") |
| 348 | def split_header_words(header_values): |
| 349 | r"""Parse header values into a list of lists containing key,value pairs. |
| 350 | |
| 351 | The function knows how to deal with ",", ";" and "=" as well as quoted |
| 352 | values after "=". A list of space separated tokens are parsed as if they |
| 353 | were separated by ";". |
| 354 | |
| 355 | If the header_values passed as argument contains multiple values, then they |
| 356 | are treated as if they were a single value separated by comma ",". |
| 357 | |
| 358 | This means that this function is useful for parsing header fields that |
| 359 | follow this syntax (BNF as from the HTTP/1.1 specification, but we relax |
| 360 | the requirement for tokens). |
| 361 | |
| 362 | headers = #header |
| 363 | header = (token | parameter) *( [";"] (token | parameter)) |
| 364 | |
| 365 | token = 1*<any CHAR except CTLs or separators> |
| 366 | separators = "(" | ")" | "<" | ">" | "@" |
| 367 | | "," | ";" | ":" | "\" | <"> |
| 368 | | "/" | "[" | "]" | "?" | "=" |
| 369 | | "{" | "}" | SP | HT |
| 370 | |
| 371 | quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) |
| 372 | qdtext = <any TEXT except <">> |
| 373 | quoted-pair = "\" CHAR |
| 374 | |
| 375 | parameter = attribute "=" value |
| 376 | attribute = token |
| 377 | value = token | quoted-string |
| 378 | |
| 379 | Each header is represented by a list of key/value pairs. The value for a |
| 380 | simple token (not part of a parameter) is None. Syntactically incorrect |
| 381 | headers will not necessarily be parsed as you would want. |
| 382 | |
| 383 | This is easier to describe with some examples: |
| 384 | |
| 385 | >>> split_header_words(['foo="bar"; port="80,81"; discard, bar=baz']) |
| 386 | [[('foo', 'bar'), ('port', '80,81'), ('discard', None)], [('bar', 'baz')]] |
| 387 | >>> split_header_words(['text/html; charset="iso-8859-1"']) |
| 388 | [[('text/html', None), ('charset', 'iso-8859-1')]] |
| 389 | >>> split_header_words([r'Basic realm="\"foo\bar\""']) |
| 390 | [[('Basic', None), ('realm', '"foobar"')]] |
| 391 | |
| 392 | """ |
| 393 | assert not isinstance(header_values, str) |
| 394 | result = [] |
| 395 | for text in header_values: |
| 396 | orig_text = text |
| 397 | pairs = [] |
| 398 | while text: |
| 399 | m = HEADER_TOKEN_RE.search(text) |
| 400 | if m: |
| 401 | text = unmatched(m) |
| 402 | name = m.group(1) |
| 403 | m = HEADER_QUOTED_VALUE_RE.search(text) |
| 404 | if m: # quoted value |
| 405 | text = unmatched(m) |
searching dependent graphs…