| | 437 | |
|---|
| | 438 | def referer(pattern, accept=True, accept_missing=False, error=403, |
|---|
| | 439 | message='Forbidden Referer header.'): |
|---|
| | 440 | """Raise HTTPError if Referer header does not pass our test. |
|---|
| | 441 | |
|---|
| | 442 | pattern: a regular expression pattern to test against the Referer. |
|---|
| | 443 | accept: if True, the Referer must match the pattern; if False, |
|---|
| | 444 | the Referer must NOT match the pattern. |
|---|
| | 445 | accept_missing: if True, permit requests with no Referer header. |
|---|
| | 446 | error: the HTTP error code to return to the client on failure. |
|---|
| | 447 | message: a string to include in the response body on failure. |
|---|
| | 448 | """ |
|---|
| | 449 | try: |
|---|
| | 450 | match = bool(re.match(pattern, cherrypy.request.headers['Referer'])) |
|---|
| | 451 | if accept == match: |
|---|
| | 452 | return |
|---|
| | 453 | except KeyError: |
|---|
| | 454 | if accept_missing: |
|---|
| | 455 | return |
|---|
| | 456 | |
|---|
| | 457 | raise cherrypy.HTTPError(error, message) |
|---|
| | 458 | |
|---|
| | 459 | def accept(media=None): |
|---|
| | 460 | """Return the client's preferred media-type (from the given Content-Types). |
|---|
| | 461 | |
|---|
| | 462 | If 'media' is None (the default), no test will be performed. |
|---|
| | 463 | |
|---|
| | 464 | If 'media' is provided, it should be the Content-Type value (as a string) |
|---|
| | 465 | or values (as a list or tuple of strings) which the current request |
|---|
| | 466 | can emit. The client's acceptable media ranges (as declared in the |
|---|
| | 467 | Accept request header) will be matched in order to these Content-Type |
|---|
| | 468 | values; the first such string is returned. That is, the return value |
|---|
| | 469 | will always be one of the strings provided in the 'media' arg (or None |
|---|
| | 470 | if 'media' is None). |
|---|
| | 471 | |
|---|
| | 472 | If no match is found, then HTTPError 406 (Not Acceptable) is raised. |
|---|
| | 473 | Note that most web browsers send */* as a (low-quality) acceptable |
|---|
| | 474 | media range, which should match any Content-Type. In addition, "...if |
|---|
| | 475 | no Accept header field is present, then it is assumed that the client |
|---|
| | 476 | accepts all media types." |
|---|
| | 477 | |
|---|
| | 478 | Matching types are checked in order of client preference first, |
|---|
| | 479 | and then in the order of the given 'media' values. |
|---|
| | 480 | |
|---|
| | 481 | Note that this function does not honor accept-params (other than "q"). |
|---|
| | 482 | """ |
|---|
| | 483 | if not media: |
|---|
| | 484 | return |
|---|
| | 485 | if isinstance(media, basestring): |
|---|
| | 486 | media = [media] |
|---|
| | 487 | |
|---|
| | 488 | # Parse the Accept request header, and try to match one |
|---|
| | 489 | # of the requested media-ranges (in order of preference). |
|---|
| | 490 | ranges = cherrypy.request.headers.elements('Accept') |
|---|
| | 491 | if not ranges: |
|---|
| | 492 | # Any media type is acceptable. |
|---|
| | 493 | return media[0] |
|---|
| | 494 | else: |
|---|
| | 495 | # Note that 'ranges' is sorted in order of preference |
|---|
| | 496 | for element in ranges: |
|---|
| | 497 | if element.qvalue > 0: |
|---|
| | 498 | if element.value == "*/*": |
|---|
| | 499 | # Matches any type or subtype |
|---|
| | 500 | return media[0] |
|---|
| | 501 | elif element.value.endswith("/*"): |
|---|
| | 502 | # Matches any subtype |
|---|
| | 503 | mtype = element.value[:-1] # Keep the slash |
|---|
| | 504 | for m in media: |
|---|
| | 505 | if m.startswith(mtype): |
|---|
| | 506 | return m |
|---|
| | 507 | else: |
|---|
| | 508 | # Matches exact value |
|---|
| | 509 | if element.value in media: |
|---|
| | 510 | return element.value |
|---|
| | 511 | |
|---|
| | 512 | # No suitable media-range found. |
|---|
| | 513 | ah = cherrypy.request.headers.get('Accept') |
|---|
| | 514 | if ah is None: |
|---|
| | 515 | msg = "Your client did not send an Accept header." |
|---|
| | 516 | else: |
|---|
| | 517 | msg = "Your client sent this Accept header: %s." % ah |
|---|
| | 518 | msg += (" But this resource only emits these media types: %s." % |
|---|
| | 519 | ", ".join(media)) |
|---|
| | 520 | raise cherrypy.HTTPError(406, msg) |
|---|
| | 521 | |
|---|