changeset 9572 | 73b2410bdadc |
parent 9571 | aaf83cc07eed |
child 9726 | 8905267dc7ae |
child 9936 | 5dbf45204109 |
9571:aaf83cc07eed | 9572:73b2410bdadc |
---|---|
26 |
26 |
27 header_case_mapping = {} |
27 header_case_mapping = {} |
28 |
28 |
29 def casemappingify(d): |
29 def casemappingify(d): |
30 global header_case_mapping |
30 global header_case_mapping |
31 newd = dict([(key.lower(),key) for key in d]) |
31 newd = dict([(key.lower(), key) for key in d]) |
32 header_case_mapping.update(newd) |
32 header_case_mapping.update(newd) |
33 |
33 |
34 def lowerify(d): |
34 def lowerify(d): |
35 return dict([(key.lower(),value) for key,value in d.items()]) |
35 return dict([(key.lower(), value) for key, value in d.items()]) |
36 |
36 |
37 |
37 |
38 class HeaderHandler(object): |
38 class HeaderHandler(object): |
39 """HeaderHandler manages header generating and parsing functions. |
39 """HeaderHandler manages header generating and parsing functions. |
40 """ |
40 """ |
72 if parser is None: |
72 if parser is None: |
73 raise ValueError("No header parser for header '%s', either add one or use getHeaderRaw." % (name,)) |
73 raise ValueError("No header parser for header '%s', either add one or use getHeaderRaw." % (name,)) |
74 |
74 |
75 try: |
75 try: |
76 for p in parser: |
76 for p in parser: |
77 # print "Parsing %s: %s(%s)" % (name, repr(p), repr(h)) |
77 #print "==> Parsing %s: %s(%s)" % (name, repr(p), repr(header)) |
78 header = p(header) |
78 header = p(header) |
79 # if isinstance(h, types.GeneratorType): |
79 # if isinstance(h, types.GeneratorType): |
80 # h=list(h) |
80 # h = list(h) |
81 except ValueError as v: |
81 except ValueError as v: |
82 # print v |
82 # print v |
83 header=None |
83 header = None |
84 |
84 |
85 return header |
85 return header |
86 |
86 |
87 def generate(self, name, header): |
87 def generate(self, name, header): |
88 """ |
88 """ |
186 # (Note: "GMT" is literal, not a variable timezone) |
186 # (Note: "GMT" is literal, not a variable timezone) |
187 # (also handles without without "GMT") |
187 # (also handles without without "GMT") |
188 # Two digit year, yucko. |
188 # Two digit year, yucko. |
189 day, month, year = parts[1].split('-') |
189 day, month, year = parts[1].split('-') |
190 time = parts[2] |
190 time = parts[2] |
191 year=int(year) |
191 year = int(year) |
192 if year < 69: |
192 if year < 69: |
193 year = year + 2000 |
193 year = year + 2000 |
194 elif year < 100: |
194 elif year < 100: |
195 year = year + 1900 |
195 year = year + 1900 |
196 elif len(parts) == 5: |
196 elif len(parts) == 5: |
241 NOTE: not all headers can be parsed with this function. |
241 NOTE: not all headers can be parsed with this function. |
242 |
242 |
243 Takes a raw header value (list of strings), and |
243 Takes a raw header value (list of strings), and |
244 Returns a generator of strings and Token class instances. |
244 Returns a generator of strings and Token class instances. |
245 """ |
245 """ |
246 tokens=http_tokens |
246 tokens = http_tokens |
247 ctls=http_ctls |
247 ctls = http_ctls |
248 |
248 |
249 string = ",".join(header) |
249 string = ",".join(header) |
250 list = [] |
250 list = [] |
251 start = 0 |
251 start = 0 |
252 cur = 0 |
252 cur = 0 |
264 elif x == '\\': |
264 elif x == '\\': |
265 qpair = True |
265 qpair = True |
266 elif x == '"': |
266 elif x == '"': |
267 quoted = False |
267 quoted = False |
268 yield qstring+string[start:cur] |
268 yield qstring+string[start:cur] |
269 qstring=None |
269 qstring = None |
270 start = cur+1 |
270 start = cur+1 |
271 elif x in tokens: |
271 elif x in tokens: |
272 if start != cur: |
272 if start != cur: |
273 if foldCase: |
273 if foldCase: |
274 yield string[start:cur].lower() |
274 yield string[start:cur].lower() |
338 Apache does it this way and has some comments about broken clients which |
338 Apache does it this way and has some comments about broken clients which |
339 forget commas (?), so I'm doing it the same way. It shouldn't |
339 forget commas (?), so I'm doing it the same way. It shouldn't |
340 hurt anything, in any case. |
340 hurt anything, in any case. |
341 """ |
341 """ |
342 |
342 |
343 l=[] |
343 l = [] |
344 for x in seq: |
344 for x in seq: |
345 if not isinstance(x, Token): |
345 if not isinstance(x, Token): |
346 l.append(x) |
346 l.append(x) |
347 return l |
347 return l |
348 |
348 |
352 raise ValueError, "Expected single token, not %s." % (tokens,) |
352 raise ValueError, "Expected single token, not %s." % (tokens,) |
353 return tokens[0] |
353 return tokens[0] |
354 |
354 |
355 def parseKeyValue(val): |
355 def parseKeyValue(val): |
356 if len(val) == 1: |
356 if len(val) == 1: |
357 return val[0],None |
357 return val[0], None |
358 elif len(val) == 3 and val[1] == Token('='): |
358 elif len(val) == 3 and val[1] == Token('='): |
359 return val[0],val[2] |
359 return val[0], val[2] |
360 raise ValueError, "Expected key or key=value, but got %s." % (val,) |
360 raise ValueError, "Expected key or key=value, but got %s." % (val,) |
361 |
361 |
362 def parseArgs(field): |
362 def parseArgs(field): |
363 args=split(field, Token(';')) |
363 args = split(field, Token(';')) |
364 val = args.next() |
364 val = args.next() |
365 args = [parseKeyValue(arg) for arg in args] |
365 args = [parseKeyValue(arg) for arg in args] |
366 return val,args |
366 return val, args |
367 |
367 |
368 def listParser(fun): |
368 def listParser(fun): |
369 """Return a function which applies 'fun' to every element in the |
369 """Return a function which applies 'fun' to every element in the |
370 comma-separated list""" |
370 comma-separated list""" |
371 def listParserHelper(tokens): |
371 def listParserHelper(tokens): |
376 |
376 |
377 return listParserHelper |
377 return listParserHelper |
378 |
378 |
379 def last(seq): |
379 def last(seq): |
380 """Return seq[-1]""" |
380 """Return seq[-1]""" |
381 |
|
382 return seq[-1] |
381 return seq[-1] |
383 |
382 |
384 def unique(seq): |
383 def unique(seq): |
385 '''if seq is not a string, check it's a sequence of one element and return it''' |
384 '''if seq is not a string, check it's a sequence of one element and return it''' |
386 if isinstance(seq, basestring): |
385 if isinstance(seq, basestring): |
437 return [item] |
436 return [item] |
438 |
437 |
439 def generateKeyValues(kvs): |
438 def generateKeyValues(kvs): |
440 l = [] |
439 l = [] |
441 # print kvs |
440 # print kvs |
442 for k,v in kvs: |
441 for k, v in kvs: |
443 if v is None: |
442 if v is None: |
444 l.append('%s' % k) |
443 l.append('%s' % k) |
445 else: |
444 else: |
446 l.append('%s=%s' % (k,v)) |
445 l.append('%s=%s' % (k, v)) |
447 return ";".join(l) |
446 return ";".join(l) |
448 |
447 |
449 |
448 |
450 class MimeType(object): |
449 class MimeType(object): |
451 def fromString(klass, mimeTypeString): |
450 def fromString(klass, mimeTypeString): |
489 def __hash__(self): |
488 def __hash__(self): |
490 return hash(self.mediaType)^hash(self.mediaSubtype)^hash(tuple(self.params.iteritems())) |
489 return hash(self.mediaType)^hash(self.mediaSubtype)^hash(tuple(self.params.iteritems())) |
491 |
490 |
492 ##### Specific header parsers. |
491 ##### Specific header parsers. |
493 def parseAccept(field): |
492 def parseAccept(field): |
494 type,args = parseArgs(field) |
493 type, args = parseArgs(field) |
495 |
494 |
496 if len(type) != 3 or type[1] != Token('/'): |
495 if len(type) != 3 or type[1] != Token('/'): |
497 raise ValueError, "MIME Type "+str(type)+" invalid." |
496 raise ValueError, "MIME Type "+str(type)+" invalid." |
498 |
497 |
499 # okay, this spec is screwy. A 'q' parameter is used as the separator |
498 # okay, this spec is screwy. A 'q' parameter is used as the separator |
501 # parameters. |
500 # parameters. |
502 |
501 |
503 num = 0 |
502 num = 0 |
504 for arg in args: |
503 for arg in args: |
505 if arg[0] == 'q': |
504 if arg[0] == 'q': |
506 mimeparams=tuple(args[0:num]) |
505 mimeparams = tuple(args[0:num]) |
507 params=args[num:] |
506 params = args[num:] |
508 break |
507 break |
509 num = num + 1 |
508 num = num + 1 |
510 else: |
509 else: |
511 mimeparams=tuple(args) |
510 mimeparams = tuple(args) |
512 params=[] |
511 params = [] |
513 |
512 |
514 # Default values for parameters: |
513 # Default values for parameters: |
515 qval = 1.0 |
514 qval = 1.0 |
516 |
515 |
517 # Parse accept parameters: |
516 # Parse accept parameters: |
518 for param in params: |
517 for param in params: |
519 if param[0] =='q': |
518 if param[0] == 'q': |
520 qval = float(param[1]) |
519 qval = float(param[1]) |
521 else: |
520 else: |
522 # Warn? ignored parameter. |
521 # Warn? ignored parameter. |
523 pass |
522 pass |
524 |
523 |
525 ret = MimeType(type[0],type[2],mimeparams),qval |
524 ret = MimeType(type[0], type[2], mimeparams), qval |
526 return ret |
525 return ret |
527 |
526 |
528 def parseAcceptQvalue(field): |
527 def parseAcceptQvalue(field): |
529 type,args=parseArgs(field) |
528 type, args = parseArgs(field) |
530 |
529 |
531 type = checkSingleToken(type) |
530 type = checkSingleToken(type) |
532 |
531 |
533 qvalue = 1.0 # Default qvalue is 1 |
532 qvalue = 1.0 # Default qvalue is 1 |
534 for arg in args: |
533 for arg in args: |
535 if arg[0] == 'q': |
534 if arg[0] == 'q': |
536 qvalue = float(arg[1]) |
535 qvalue = float(arg[1]) |
537 return type,qvalue |
536 return type, qvalue |
538 |
537 |
539 def addDefaultCharset(charsets): |
538 def addDefaultCharset(charsets): |
540 if charsets.get('*') is None and charsets.get('iso-8859-1') is None: |
539 if charsets.get('*') is None and charsets.get('iso-8859-1') is None: |
541 charsets['iso-8859-1'] = 1.0 |
540 charsets['iso-8859-1'] = 1.0 |
542 return charsets |
541 return charsets |
552 def parseContentType(header): |
551 def parseContentType(header): |
553 # Case folding is disabled for this header, because of use of |
552 # Case folding is disabled for this header, because of use of |
554 # Content-Type: multipart/form-data; boundary=CaSeFuLsTuFf |
553 # Content-Type: multipart/form-data; boundary=CaSeFuLsTuFf |
555 # So, we need to explicitly .lower() the type/subtype and arg keys. |
554 # So, we need to explicitly .lower() the type/subtype and arg keys. |
556 |
555 |
557 type,args = parseArgs(header) |
556 type, args = parseArgs(header) |
558 |
557 |
559 if len(type) != 3 or type[1] != Token('/'): |
558 if len(type) != 3 or type[1] != Token('/'): |
560 raise ValueError, "MIME Type "+str(type)+" invalid." |
559 raise ValueError, "MIME Type "+str(type)+" invalid." |
561 |
560 |
562 args = [(kv[0].lower(), kv[1]) for kv in args] |
561 args = [(kv[0].lower(), kv[1]) for kv in args] |
571 |
570 |
572 def parseContentRange(header): |
571 def parseContentRange(header): |
573 """Parse a content-range header into (kind, start, end, realLength). |
572 """Parse a content-range header into (kind, start, end, realLength). |
574 |
573 |
575 realLength might be None if real length is not known ('*'). |
574 realLength might be None if real length is not known ('*'). |
576 start and end might be None if start,end unspecified (for response code 416) |
575 start and end might be None if start, end unspecified (for response code 416) |
577 """ |
576 """ |
578 kind, other = header.strip().split() |
577 kind, other = header.strip().split() |
579 if kind.lower() != "bytes": |
578 if kind.lower() != "bytes": |
580 raise ValueError("a range of type %r is not supported") |
579 raise ValueError("a range of type %r is not supported") |
581 startend, realLength = other.split("/") |
580 startend, realLength = other.split("/") |
582 if startend.strip() == '*': |
581 if startend.strip() == '*': |
583 start,end=None,None |
582 start, end = None, None |
584 else: |
583 else: |
585 start, end = map(int, startend.split("-")) |
584 start, end = map(int, startend.split("-")) |
586 if realLength == "*": |
585 if realLength == "*": |
587 realLength = None |
586 realLength = None |
588 else: |
587 else: |
589 realLength = int(realLength) |
588 realLength = int(realLength) |
590 return (kind, start, end, realLength) |
589 return (kind, start, end, realLength) |
591 |
590 |
592 def parseExpect(field): |
591 def parseExpect(field): |
593 type,args=parseArgs(field) |
592 type, args = parseArgs(field) |
594 |
593 |
595 type=parseKeyValue(type) |
594 type = parseKeyValue(type) |
596 return (type[0], (lambda *args:args)(type[1], *args)) |
595 return (type[0], (lambda *args:args)(type[1], *args)) |
597 |
596 |
598 def parseExpires(header): |
597 def parseExpires(header): |
599 # """HTTP/1.1 clients and caches MUST treat other invalid date formats, |
598 # """HTTP/1.1 clients and caches MUST treat other invalid date formats, |
600 # especially including the value 0, as in the past (i.e., "already expired").""" |
599 # especially including the value 0, as in the past (i.e., "already expired").""" |
622 def parseRange(range): |
621 def parseRange(range): |
623 range = list(range) |
622 range = list(range) |
624 if len(range) < 3 or range[1] != Token('='): |
623 if len(range) < 3 or range[1] != Token('='): |
625 raise ValueError("Invalid range header format: %s" %(range,)) |
624 raise ValueError("Invalid range header format: %s" %(range,)) |
626 |
625 |
627 type=range[0] |
626 type = range[0] |
628 if type != 'bytes': |
627 if type != 'bytes': |
629 raise ValueError("Unknown range unit: %s." % (type,)) |
628 raise ValueError("Unknown range unit: %s." % (type,)) |
630 rangeset=split(range[2:], Token(',')) |
629 rangeset = split(range[2:], Token(',')) |
631 ranges = [] |
630 ranges = [] |
632 |
631 |
633 for byterangespec in rangeset: |
632 for byterangespec in rangeset: |
634 if len(byterangespec) != 1: |
633 if len(byterangespec) != 1: |
635 raise ValueError("Invalid range header format: %s" % (range,)) |
634 raise ValueError("Invalid range header format: %s" % (range,)) |
636 start,end=byterangespec[0].split('-') |
635 start, end = byterangespec[0].split('-') |
637 |
636 |
638 if not start and not end: |
637 if not start and not end: |
639 raise ValueError("Invalid range header format: %s" % (range,)) |
638 raise ValueError("Invalid range header format: %s" % (range,)) |
640 |
639 |
641 if start: |
640 if start: |
648 else: |
647 else: |
649 end = None |
648 end = None |
650 |
649 |
651 if start and end and start > end: |
650 if start and end and start > end: |
652 raise ValueError("Invalid range header, start > end: %s" % (range,)) |
651 raise ValueError("Invalid range header, start > end: %s" % (range,)) |
653 ranges.append((start,end)) |
652 ranges.append((start, end)) |
654 return type,ranges |
653 return type, ranges |
655 |
654 |
656 def parseRetryAfter(header): |
655 def parseRetryAfter(header): |
657 try: |
656 try: |
658 # delta seconds |
657 # delta seconds |
659 return time.time() + int(header) |
658 return time.time() + int(header) |
712 # in the unquoted base64 encoded credentials |
711 # in the unquoted base64 encoded credentials |
713 return scheme.lower(), rest |
712 return scheme.lower(), rest |
714 |
713 |
715 #### Header generators |
714 #### Header generators |
716 def generateAccept(accept): |
715 def generateAccept(accept): |
717 mimeType,q = accept |
716 mimeType, q = accept |
718 |
717 |
719 out="%s/%s"%(mimeType.mediaType, mimeType.mediaSubtype) |
718 out ="%s/%s"%(mimeType.mediaType, mimeType.mediaSubtype) |
720 if mimeType.params: |
719 if mimeType.params: |
721 out+=';'+generateKeyValues(mimeType.params.iteritems()) |
720 out+=';'+generateKeyValues(mimeType.params.iteritems()) |
722 |
721 |
723 if q != 1.0: |
722 if q != 1.0: |
724 out+=(';q=%.3f' % (q,)).rstrip('0').rstrip('.') |
723 out+=(';q=%.3f' % (q,)).rstrip('0').rstrip('.') |
760 else: |
759 else: |
761 if k == 'no-cache' or k == 'private': |
760 if k == 'no-cache' or k == 'private': |
762 # quoted list of values |
761 # quoted list of values |
763 v = quoteString(generateList( |
762 v = quoteString(generateList( |
764 [header_case_mapping.get(name) or dashCapitalize(name) for name in v])) |
763 [header_case_mapping.get(name) or dashCapitalize(name) for name in v])) |
765 return '%s=%s' % (k,v) |
764 return '%s=%s' % (k, v) |
766 |
765 |
767 def generateContentRange(tup): |
766 def generateContentRange(tup): |
768 """tup is (type, start, end, len) |
767 """tup is (type, start, end, len) |
769 len can be None. |
768 len can be None. |
770 """ |
769 """ |
803 def noneOr(s): |
802 def noneOr(s): |
804 if s is None: |
803 if s is None: |
805 return '' |
804 return '' |
806 return s |
805 return s |
807 |
806 |
808 type,ranges=range |
807 type, ranges = range |
809 |
808 |
810 if type != 'bytes': |
809 if type != 'bytes': |
811 raise ValueError("Unknown range unit: "+type+".") |
810 raise ValueError("Unknown range unit: "+type+".") |
812 |
811 |
813 return (type+'='+ |
812 return (type+'='+ |
817 def generateRetryAfter(when): |
816 def generateRetryAfter(when): |
818 # always generate delta seconds format |
817 # always generate delta seconds format |
819 return str(int(when - time.time())) |
818 return str(int(when - time.time())) |
820 |
819 |
821 def generateContentType(mimeType): |
820 def generateContentType(mimeType): |
822 out="%s/%s"%(mimeType.mediaType, mimeType.mediaSubtype) |
821 out = "%s/%s" % (mimeType.mediaType, mimeType.mediaSubtype) |
823 if mimeType.params: |
822 if mimeType.params: |
824 out+=';'+generateKeyValues(mimeType.params.iteritems()) |
823 out += ';' + generateKeyValues(mimeType.params.iteritems()) |
825 return out |
824 return out |
826 |
825 |
827 def generateIfRange(dateOrETag): |
826 def generateIfRange(dateOrETag): |
828 if isinstance(dateOrETag, ETag): |
827 if isinstance(dateOrETag, ETag): |
829 return dateOrETag.generate() |
828 return dateOrETag.generate() |
840 # If we're going to parse out to something other than a dict |
839 # If we're going to parse out to something other than a dict |
841 # we need to be able to generate from something other than a dict |
840 # we need to be able to generate from something other than a dict |
842 |
841 |
843 try: |
842 try: |
844 l = [] |
843 l = [] |
845 for k,v in dict(challenge).iteritems(): |
844 for k, v in dict(challenge).iteritems(): |
846 l.append("%s=%s" % (k, quoteString(v))) |
845 l.append("%s=%s" % (k, quoteString(v))) |
847 |
846 |
848 _generated.append("%s %s" % (scheme, ", ".join(l))) |
847 _generated.append("%s %s" % (scheme, ", ".join(l))) |
849 except ValueError: |
848 except ValueError: |
850 _generated.append("%s %s" % (scheme, challenge)) |
849 _generated.append("%s %s" % (scheme, challenge)) |
885 |
884 |
886 def __repr__(self): |
885 def __repr__(self): |
887 return "Etag(%r, weak=%r)" % (self.tag, self.weak) |
886 return "Etag(%r, weak=%r)" % (self.tag, self.weak) |
888 |
887 |
889 def parse(tokens): |
888 def parse(tokens): |
890 tokens=tuple(tokens) |
889 tokens = tuple(tokens) |
891 if len(tokens) == 1 and not isinstance(tokens[0], Token): |
890 if len(tokens) == 1 and not isinstance(tokens[0], Token): |
892 return ETag(tokens[0]) |
891 return ETag(tokens[0]) |
893 |
892 |
894 if(len(tokens) == 3 and tokens[0] == "w" |
893 if(len(tokens) == 3 and tokens[0] == "w" |
895 and tokens[1] == Token('/')): |
894 and tokens[1] == Token('/')): |
896 return ETag(tokens[2], weak=True) |
895 return ETag(tokens[2], weak=True) |
897 |
896 |
898 raise ValueError("Invalid ETag.") |
897 raise ValueError("Invalid ETag.") |
899 |
898 |
900 parse=staticmethod(parse) |
899 parse = staticmethod(parse) |
901 |
900 |
902 def generate(self): |
901 def generate(self): |
903 if self.weak: |
902 if self.weak: |
904 return 'W/'+quoteString(self.tag) |
903 return 'W/'+quoteString(self.tag) |
905 else: |
904 else: |
906 return quoteString(self.tag) |
905 return quoteString(self.tag) |
907 |
906 |
908 def parseStarOrETag(tokens): |
907 def parseStarOrETag(tokens): |
909 tokens=tuple(tokens) |
908 tokens = tuple(tokens) |
910 if tokens == ('*',): |
909 if tokens == ('*',): |
911 return '*' |
910 return '*' |
912 else: |
911 else: |
913 return ETag.parse(tokens) |
912 return ETag.parse(tokens) |
914 |
913 |
915 def generateStarOrETag(etag): |
914 def generateStarOrETag(etag): |
916 if etag=='*': |
915 if etag == '*': |
917 return etag |
916 return etag |
918 else: |
917 else: |
919 return etag.generate() |
918 return etag.generate() |
920 |
919 |
921 #### Cookies. Blech! |
920 #### Cookies. Blech! |
922 class Cookie(object): |
921 class Cookie(object): |
923 # __slots__ = ['name', 'value', 'path', 'domain', 'ports', 'expires', 'discard', 'secure', 'comment', 'commenturl', 'version'] |
922 # __slots__ = ['name', 'value', 'path', 'domain', 'ports', 'expires', 'discard', 'secure', 'comment', 'commenturl', 'version'] |
924 |
923 |
925 def __init__(self, name, value, path=None, domain=None, ports=None, expires=None, discard=False, secure=False, comment=None, commenturl=None, version=0): |
924 def __init__(self, name, value, path=None, domain=None, ports=None, expires=None, discard=False, secure=False, comment=None, commenturl=None, version=0): |
926 self.name=name |
925 self.name = name |
927 self.value=value |
926 self.value = value |
928 self.path=path |
927 self.path = path |
929 self.domain=domain |
928 self.domain = domain |
930 self.ports=ports |
929 self.ports = ports |
931 self.expires=expires |
930 self.expires = expires |
932 self.discard=discard |
931 self.discard = discard |
933 self.secure=secure |
932 self.secure = secure |
934 self.comment=comment |
933 self.comment = comment |
935 self.commenturl=commenturl |
934 self.commenturl = commenturl |
936 self.version=version |
935 self.version = version |
937 |
936 |
938 def __repr__(self): |
937 def __repr__(self): |
939 s="Cookie(%r=%r" % (self.name, self.value) |
938 s = "Cookie(%r=%r" % (self.name, self.value) |
940 if self.path is not None: s+=", path=%r" % (self.path,) |
939 if self.path is not None: s+=", path=%r" % (self.path,) |
941 if self.domain is not None: s+=", domain=%r" % (self.domain,) |
940 if self.domain is not None: s+=", domain=%r" % (self.domain,) |
942 if self.ports is not None: s+=", ports=%r" % (self.ports,) |
941 if self.ports is not None: s+=", ports=%r" % (self.ports,) |
943 if self.expires is not None: s+=", expires=%r" % (self.expires,) |
942 if self.expires is not None: s+=", expires=%r" % (self.expires,) |
944 if self.secure is not False: s+=", secure=%r" % (self.secure,) |
943 if self.secure is not False: s+=", secure=%r" % (self.secure,) |
977 # Neither new RFC2965 cookies nor old netscape cookies are. |
976 # Neither new RFC2965 cookies nor old netscape cookies are. |
978 |
977 |
979 header = ';'.join(headers) |
978 header = ';'.join(headers) |
980 if header[0:8].lower() == "$version": |
979 if header[0:8].lower() == "$version": |
981 # RFC2965 cookie |
980 # RFC2965 cookie |
982 h=tokenize([header], foldCase=False) |
981 h = tokenize([header], foldCase=False) |
983 r_cookies = split(h, Token(',')) |
982 r_cookies = split(h, Token(',')) |
984 for r_cookie in r_cookies: |
983 for r_cookie in r_cookies: |
985 last_cookie = None |
984 last_cookie = None |
986 rr_cookies = split(r_cookie, Token(';')) |
985 rr_cookies = split(r_cookie, Token(';')) |
987 for cookie in rr_cookies: |
986 for cookie in rr_cookies: |
990 (name,), (value,) = nameval |
989 (name,), (value,) = nameval |
991 else: |
990 else: |
992 (name,), = nameval |
991 (name,), = nameval |
993 value = None |
992 value = None |
994 |
993 |
995 name=name.lower() |
994 name = name.lower() |
996 if name == '$version': |
995 if name == '$version': |
997 continue |
996 continue |
998 if name[0] == '$': |
997 if name[0] == '$': |
999 if last_cookie is not None: |
998 if last_cookie is not None: |
1000 if name == '$path': |
999 if name == '$path': |
1001 last_cookie.path=value |
1000 last_cookie.path = value |
1002 elif name == '$domain': |
1001 elif name == '$domain': |
1003 last_cookie.domain=value |
1002 last_cookie.domain = value |
1004 elif name == '$port': |
1003 elif name == '$port': |
1005 if value is None: |
1004 if value is None: |
1006 last_cookie.ports = () |
1005 last_cookie.ports = () |
1007 else: |
1006 else: |
1008 last_cookie.ports=tuple([int(s) for s in value.split(',')]) |
1007 last_cookie.ports = tuple([int(s) for s in value.split(',')]) |
1009 else: |
1008 else: |
1010 last_cookie = Cookie(name, value, version=1) |
1009 last_cookie = Cookie(name, value, version=1) |
1011 cookies.append(last_cookie) |
1010 cookies.append(last_cookie) |
1012 else: |
1011 else: |
1013 # Oldstyle cookies don't do quoted strings or anything sensible. |
1012 # Oldstyle cookies don't do quoted strings or anything sensible. |
1014 # All characters are valid for names except ';' and '=', and all |
1013 # All characters are valid for names except ';' and '=', and all |
1015 # characters are valid for values except ';'. Spaces are stripped, |
1014 # characters are valid for values except ';'. Spaces are stripped, |
1016 # however. |
1015 # however. |
1017 r_cookies = header.split(';') |
1016 r_cookies = header.split(';') |
1018 for r_cookie in r_cookies: |
1017 for r_cookie in r_cookies: |
1019 name,value = r_cookie.split('=', 1) |
1018 name, value = r_cookie.split('=', 1) |
1020 name=name.strip(' \t') |
1019 name = name.strip(' \t') |
1021 value=value.strip(' \t') |
1020 value = value.strip(' \t') |
1022 |
1021 |
1023 cookies.append(Cookie(name, value)) |
1022 cookies.append(Cookie(name, value)) |
1024 |
1023 |
1025 return cookies |
1024 return cookies |
1026 |
1025 |
1084 # the other side. |
1083 # the other side. |
1085 |
1084 |
1086 if cookie_validname_re.match(cookie.name) is None: |
1085 if cookie_validname_re.match(cookie.name) is None: |
1087 continue |
1086 continue |
1088 |
1087 |
1089 value=cookie.value |
1088 value = cookie.value |
1090 if cookie_validvalue_re.match(cookie.value) is None: |
1089 if cookie_validvalue_re.match(cookie.value) is None: |
1091 value = quoteString(value) |
1090 value = quoteString(value) |
1092 |
1091 |
1093 str_cookies.append("%s=%s" % (cookie.name, value)) |
1092 str_cookies.append("%s=%s" % (cookie.name, value)) |
1094 else: |
1093 else: |
1114 l = [] |
1113 l = [] |
1115 |
1114 |
1116 for part in parts: |
1115 for part in parts: |
1117 namevalue = part.split('=',1) |
1116 namevalue = part.split('=',1) |
1118 if len(namevalue) == 1: |
1117 if len(namevalue) == 1: |
1119 name=namevalue[0] |
1118 name = namevalue[0] |
1120 value=None |
1119 value = None |
1121 else: |
1120 else: |
1122 name,value=namevalue |
1121 name, value = namevalue |
1123 value=value.strip(' \t') |
1122 value = value.strip(' \t') |
1124 |
1123 |
1125 name=name.strip(' \t') |
1124 name = name.strip(' \t') |
1126 |
1125 |
1127 l.append((name, value)) |
1126 l.append((name, value)) |
1128 |
1127 |
1129 setCookies.append(makeCookieFromList(l, True)) |
1128 setCookies.append(makeCookieFromList(l, True)) |
1130 except ValueError: |
1129 except ValueError: |
1151 if name.startswith("$"): |
1150 if name.startswith("$"): |
1152 raise ValueError("Invalid cookie name: %r, starts with '$'." % name) |
1151 raise ValueError("Invalid cookie name: %r, starts with '$'." % name) |
1153 cookie = Cookie(name, value) |
1152 cookie = Cookie(name, value) |
1154 hadMaxAge = False |
1153 hadMaxAge = False |
1155 |
1154 |
1156 for name,value in tup[1:]: |
1155 for name, value in tup[1:]: |
1157 name = name.lower() |
1156 name = name.lower() |
1158 |
1157 |
1159 if value is None: |
1158 if value is None: |
1160 if name in ("discard", "secure"): |
1159 if name in ("discard", "secure"): |
1161 # Boolean attrs |
1160 # Boolean attrs |
1265 # if item1[0] == item2[0]: |
1264 # if item1[0] == item2[0]: |
1266 # return 0 |
1265 # return 0 |
1267 |
1266 |
1268 |
1267 |
1269 # def getMimeQuality(mimeType, accepts): |
1268 # def getMimeQuality(mimeType, accepts): |
1270 # type,args = parseArgs(mimeType) |
1269 # type, args = parseArgs(mimeType) |
1271 # type=type.split(Token('/')) |
1270 # type = type.split(Token('/')) |
1272 # if len(type) != 2: |
1271 # if len(type) != 2: |
1273 # raise ValueError, "MIME Type "+s+" invalid." |
1272 # raise ValueError, "MIME Type "+s+" invalid." |
1274 |
1273 |
1275 # for accept in accepts: |
1274 # for accept in accepts: |
1276 # accept,acceptQual=accept |
1275 # accept, acceptQual = accept |
1277 # acceptType=accept[0:1] |
1276 # acceptType = accept[0:1] |
1278 # acceptArgs=accept[2] |
1277 # acceptArgs = accept[2] |
1279 |
1278 |
1280 # if ((acceptType == type or acceptType == (type[0],'*') or acceptType==('*','*')) and |
1279 # if ((acceptType == type or acceptType == (type[0],'*') or acceptType==('*','*')) and |
1281 # (args == acceptArgs or len(acceptArgs) == 0)): |
1280 # (args == acceptArgs or len(acceptArgs) == 0)): |
1282 # return acceptQual |
1281 # return acceptQual |
1283 |
1282 |
1335 hasHeader = __contains__ |
1334 hasHeader = __contains__ |
1336 |
1335 |
1337 def getRawHeaders(self, name, default=None): |
1336 def getRawHeaders(self, name, default=None): |
1338 """Returns a list of headers matching the given name as the raw string given.""" |
1337 """Returns a list of headers matching the given name as the raw string given.""" |
1339 |
1338 |
1340 name=name.lower() |
1339 name = name.lower() |
1341 raw_header = self._raw_headers.get(name, default) |
1340 raw_header = self._raw_headers.get(name, default) |
1342 if raw_header is not _RecalcNeeded: |
1341 if raw_header is not _RecalcNeeded: |
1343 return raw_header |
1342 return raw_header |
1344 |
1343 |
1345 return self._toRaw(name) |
1344 return self._toRaw(name) |
1350 |
1349 |
1351 If no parser for the header exists, raise ValueError. |
1350 If no parser for the header exists, raise ValueError. |
1352 |
1351 |
1353 If the header doesn't exist, return default (or None if not specified) |
1352 If the header doesn't exist, return default (or None if not specified) |
1354 """ |
1353 """ |
1355 name=name.lower() |
1354 name = name.lower() |
1356 parsed = self._headers.get(name, default) |
1355 parsed = self._headers.get(name, default) |
1357 if parsed is not _RecalcNeeded: |
1356 if parsed is not _RecalcNeeded: |
1358 return parsed |
1357 return parsed |
1359 return self._toParsed(name) |
1358 return self._toParsed(name) |
1360 |
1359 |
1361 def setRawHeaders(self, name, value): |
1360 def setRawHeaders(self, name, value): |
1362 """Sets the raw representation of the given header. |
1361 """Sets the raw representation of the given header. |
1363 Value should be a list of strings, each being one header of the |
1362 Value should be a list of strings, each being one header of the |
1364 given name. |
1363 given name. |
1365 """ |
1364 """ |
1366 name=name.lower() |
1365 name = name.lower() |
1367 self._raw_headers[name] = value |
1366 self._raw_headers[name] = value |
1368 self._headers[name] = _RecalcNeeded |
1367 self._headers[name] = _RecalcNeeded |
1369 |
1368 |
1370 def setHeader(self, name, value): |
1369 def setHeader(self, name, value): |
1371 """Sets the parsed representation of the given header. |
1370 """Sets the parsed representation of the given header. |
1372 Value should be a list of objects whose exact form depends |
1371 Value should be a list of objects whose exact form depends |
1373 on the header in question. |
1372 on the header in question. |
1374 """ |
1373 """ |
1375 name=name.lower() |
1374 name = name.lower() |
1376 self._raw_headers[name] = _RecalcNeeded |
1375 self._raw_headers[name] = _RecalcNeeded |
1377 self._headers[name] = value |
1376 self._headers[name] = value |
1378 |
1377 |
1379 def addRawHeader(self, name, value): |
1378 def addRawHeader(self, name, value): |
1380 """ |
1379 """ |
1381 Add a raw value to a header that may or may not already exist. |
1380 Add a raw value to a header that may or may not already exist. |
1382 If it exists, add it as a separate header to output; do not |
1381 If it exists, add it as a separate header to output; do not |
1383 replace anything. |
1382 replace anything. |
1384 """ |
1383 """ |
1385 name=name.lower() |
1384 name = name.lower() |
1386 raw_header = self._raw_headers.get(name) |
1385 raw_header = self._raw_headers.get(name) |
1387 if raw_header is None: |
1386 if raw_header is None: |
1388 # No header yet |
1387 # No header yet |
1389 raw_header = [] |
1388 raw_header = [] |
1390 self._raw_headers[name] = raw_header |
1389 self._raw_headers[name] = raw_header |
1398 """ |
1397 """ |
1399 Add a parsed representatoin to a header that may or may not already exist. |
1398 Add a parsed representatoin to a header that may or may not already exist. |
1400 If it exists, add it as a separate header to output; do not |
1399 If it exists, add it as a separate header to output; do not |
1401 replace anything. |
1400 replace anything. |
1402 """ |
1401 """ |
1403 name=name.lower() |
1402 name = name.lower() |
1404 header = self._headers.get(name) |
1403 header = self._headers.get(name) |
1405 if header is None: |
1404 if header is None: |
1406 # No header yet |
1405 # No header yet |
1407 header = [] |
1406 header = [] |
1408 self._headers[name] = header |
1407 self._headers[name] = header |
1411 header.append(value) |
1410 header.append(value) |
1412 self._raw_headers[name] = _RecalcNeeded |
1411 self._raw_headers[name] = _RecalcNeeded |
1413 |
1412 |
1414 def removeHeader(self, name): |
1413 def removeHeader(self, name): |
1415 """Removes the header named.""" |
1414 """Removes the header named.""" |
1416 name=name.lower() |
1415 name = name.lower() |
1417 if name in self._raw_headers: |
1416 if name in self._raw_headers: |
1418 del self._raw_headers[name] |
1417 del self._raw_headers[name] |
1419 del self._headers[name] |
1418 del self._headers[name] |
1420 |
1419 |
1421 def __repr__(self): |
1420 def __repr__(self): |
1425 """Return the name with the canonical capitalization, if known, |
1424 """Return the name with the canonical capitalization, if known, |
1426 otherwise, Caps-After-Dashes""" |
1425 otherwise, Caps-After-Dashes""" |
1427 return header_case_mapping.get(name) or dashCapitalize(name) |
1426 return header_case_mapping.get(name) or dashCapitalize(name) |
1428 |
1427 |
1429 def getAllRawHeaders(self): |
1428 def getAllRawHeaders(self): |
1430 """Return an iterator of key,value pairs of all headers |
1429 """Return an iterator of key, value pairs of all headers |
1431 contained in this object, as strings. The keys are capitalized |
1430 contained in this object, as strings. The keys are capitalized |
1432 in canonical capitalization.""" |
1431 in canonical capitalization.""" |
1433 for k,v in self._raw_headers.iteritems(): |
1432 for k, v in self._raw_headers.iteritems(): |
1434 if v is _RecalcNeeded: |
1433 if v is _RecalcNeeded: |
1435 v = self._toRaw(k) |
1434 v = self._toRaw(k) |
1436 yield self.canonicalNameCaps(k), v |
1435 yield self.canonicalNameCaps(k), v |
1437 |
1436 |
1438 def makeImmutable(self): |
1437 def makeImmutable(self): |
1454 |
1453 |
1455 iteritems = lambda x: x.iteritems() |
1454 iteritems = lambda x: x.iteritems() |
1456 |
1455 |
1457 |
1456 |
1458 parser_general_headers = { |
1457 parser_general_headers = { |
1459 'Cache-Control':(tokenize, listParser(parseCacheControl), dict), |
1458 'Cache-Control': (tokenize, listParser(parseCacheControl), dict), |
1460 'Connection':(tokenize,filterTokens), |
1459 'Connection': (tokenize, filterTokens), |
1461 'Date':(last,parseDateTime), |
1460 'Date': (last, parseDateTime), |
1462 # 'Pragma':tokenize |
1461 # 'Pragma':tokenize |
1463 # 'Trailer':tokenize |
1462 # 'Trailer':tokenize |
1464 'Transfer-Encoding':(tokenize,filterTokens), |
1463 'Transfer-Encoding': (tokenize, filterTokens), |
1465 # 'Upgrade':tokenize |
1464 # 'Upgrade':tokenize |
1466 # 'Via':tokenize,stripComment |
1465 # 'Via':tokenize, stripComment |
1467 # 'Warning':tokenize |
1466 # 'Warning':tokenize |
1468 } |
1467 } |
1469 |
1468 |
1470 generator_general_headers = { |
1469 generator_general_headers = { |
1471 'Cache-Control':(iteritems, listGenerator(generateCacheControl), singleHeader), |
1470 'Cache-Control': (iteritems, listGenerator(generateCacheControl), singleHeader), |
1472 'Connection':(generateList,singleHeader), |
1471 'Connection': (generateList, singleHeader), |
1473 'Date':(generateDateTime,singleHeader), |
1472 'Date': (generateDateTime, singleHeader), |
1474 # 'Pragma': |
1473 # 'Pragma': |
1475 # 'Trailer': |
1474 # 'Trailer': |
1476 'Transfer-Encoding':(generateList,singleHeader), |
1475 'Transfer-Encoding': (generateList, singleHeader), |
1477 # 'Upgrade': |
1476 # 'Upgrade': |
1478 # 'Via': |
1477 # 'Via': |
1479 # 'Warning': |
1478 # 'Warning': |
1480 } |
1479 } |
1481 |
1480 |
1482 parser_request_headers = { |
1481 parser_request_headers = { |
1483 'Accept': (tokenize, listParser(parseAccept), dict), |
1482 'Accept': (tokenize, listParser(parseAccept), dict), |
1484 'Accept-Charset': (tokenize, listParser(parseAcceptQvalue), dict, addDefaultCharset), |
1483 'Accept-Charset': (tokenize, listParser(parseAcceptQvalue), dict, addDefaultCharset), |
1485 'Accept-Encoding':(tokenize, listParser(parseAcceptQvalue), dict, addDefaultEncoding), |
1484 'Accept-Encoding': (tokenize, listParser(parseAcceptQvalue), dict, addDefaultEncoding), |
1486 'Accept-Language':(tokenize, listParser(parseAcceptQvalue), dict), |
1485 'Accept-Language': (tokenize, listParser(parseAcceptQvalue), dict), |
1487 'Access-Control-Allow-Origin': (last, parseAllowOrigin,), |
1486 'Access-Control-Allow-Origin': (last, parseAllowOrigin,), |
1488 'Access-Control-Allow-Credentials': (last, parseAllowCreds,), |
1487 'Access-Control-Allow-Credentials': (last, parseAllowCreds,), |
1489 'Access-Control-Allow-Methods': (tokenize, listParser(parseHTTPMethod), list), |
1488 'Access-Control-Allow-Methods': (tokenize, listParser(parseHTTPMethod), list), |
1490 'Access-Control-Request-Method': (parseHTTPMethod, ), |
1489 'Access-Control-Request-Method': (parseHTTPMethod, ), |
1491 'Access-Control-Request-Headers': (filterTokens, ), |
1490 'Access-Control-Request-Headers': (filterTokens, ), |
1492 'Access-Control-Expose-Headers': (filterTokens, ), |
1491 'Access-Control-Expose-Headers': (filterTokens, ), |
1493 'Authorization': (last, parseAuthorization), |
1492 'Authorization': (last, parseAuthorization), |
1494 'Cookie':(parseCookie,), |
1493 'Cookie': (parseCookie,), |
1495 'Expect':(tokenize, listParser(parseExpect), dict), |
1494 'Expect': (tokenize, listParser(parseExpect), dict), |
1496 'From':(last,), |
|
1497 'Host':(last,), |
|
1498 'If-Match':(tokenize, listParser(parseStarOrETag), list), |
|
1499 'If-Modified-Since':(last, parseIfModifiedSince), |
|
1500 'If-None-Match':(tokenize, listParser(parseStarOrETag), list), |
|
1501 'If-Range':(parseIfRange,), |
|
1502 'If-Unmodified-Since':(last,parseDateTime), |
|
1503 'Max-Forwards':(last,int), |
|
1504 'Origin': (last,), |
1495 'Origin': (last,), |
1496 'From': (last,), |
|
1497 'Host': (last,), |
|
1498 'If-Match': (tokenize, listParser(parseStarOrETag), list), |
|
1499 'If-Modified-Since': (last, parseIfModifiedSince), |
|
1500 'If-None-Match': (tokenize, listParser(parseStarOrETag), list), |
|
1501 'If-Range': (parseIfRange,), |
|
1502 'If-Unmodified-Since': (last, parseDateTime), |
|
1503 'Max-Forwards': (last, int), |
|
1505 # 'Proxy-Authorization':str, # what is "credentials" |
1504 # 'Proxy-Authorization':str, # what is "credentials" |
1506 'Range':(tokenize, parseRange), |
1505 'Range': (tokenize, parseRange), |
1507 'Referer':(last,str), # TODO: URI object? |
1506 'Referer': (last, str), # TODO: URI object? |
1508 'TE':(tokenize, listParser(parseAcceptQvalue), dict), |
1507 'TE': (tokenize, listParser(parseAcceptQvalue), dict), |
1509 'User-Agent':(last,str), |
1508 'User-Agent': (last, str), |
1510 } |
1509 } |
1511 |
1510 |
1512 generator_request_headers = { |
1511 generator_request_headers = { |
1513 'Accept': (iteritems,listGenerator(generateAccept),singleHeader), |
1512 'Accept': (iteritems, listGenerator(generateAccept), singleHeader), |
1514 'Accept-Charset': (iteritems, listGenerator(generateAcceptQvalue),singleHeader), |
1513 'Accept-Charset': (iteritems, listGenerator(generateAcceptQvalue), singleHeader), |
1515 'Accept-Encoding': (iteritems, removeDefaultEncoding, listGenerator(generateAcceptQvalue),singleHeader), |
1514 'Accept-Encoding': (iteritems, removeDefaultEncoding, |
1516 'Accept-Language': (iteritems, listGenerator(generateAcceptQvalue),singleHeader), |
1515 listGenerator(generateAcceptQvalue), singleHeader), |
1516 'Accept-Language': (iteritems, listGenerator(generateAcceptQvalue), singleHeader), |
|
1517 'Access-Control-Request-Method': (unique, str, singleHeader, ), |
1517 'Access-Control-Request-Method': (unique, str, singleHeader, ), |
1518 'Access-Control-Expose-Headers': (listGenerator(str), ), |
1518 'Access-Control-Expose-Headers': (listGenerator(str), ), |
1519 'Access-Control-Allow-Headers': (listGenerator(str), ), |
1519 'Access-Control-Allow-Headers': (listGenerator(str), ), |
1520 'Authorization': (generateAuthorization,), # what is "credentials" |
1520 'Authorization': (generateAuthorization,), # what is "credentials" |
1521 'Cookie':(generateCookie,singleHeader), |
1521 'Cookie': (generateCookie, singleHeader), |
1522 'Expect':(iteritems, listGenerator(generateExpect), singleHeader), |
1522 'Expect': (iteritems, listGenerator(generateExpect), singleHeader), |
1523 'From':(unique, str,singleHeader), |
1523 'From': (unique, str, singleHeader), |
1524 'Host':(unique, str,singleHeader), |
1524 'Host': (unique, str, singleHeader), |
1525 'If-Match': (listGenerator(generateStarOrETag), singleHeader), |
|
1526 'If-Modified-Since': (generateDateTime, singleHeader), |
|
1527 'If-None-Match': (listGenerator(generateStarOrETag), singleHeader), |
|
1528 'If-Range': (generateIfRange, singleHeader), |
|
1529 'If-Unmodified-Since': (generateDateTime, singleHeader), |
|
1530 'Max-Forwards': (unique, str, singleHeader), |
|
1525 'Origin': (unique, str, singleHeader), |
1531 'Origin': (unique, str, singleHeader), |
1526 'If-Match':(listGenerator(generateStarOrETag), singleHeader), |
|
1527 'If-Modified-Since':(generateDateTime,singleHeader), |
|
1528 'If-None-Match':(listGenerator(generateStarOrETag), singleHeader), |
|
1529 'If-Range':(generateIfRange, singleHeader), |
|
1530 'If-Unmodified-Since':(generateDateTime,singleHeader), |
|
1531 'Max-Forwards':(unique, str, singleHeader), |
|
1532 # 'Proxy-Authorization':str, # what is "credentials" |
1532 # 'Proxy-Authorization':str, # what is "credentials" |
1533 'Range':(generateRange,singleHeader), |
1533 'Range': (generateRange, singleHeader), |
1534 'Referer':(unique, str,singleHeader), |
1534 'Referer': (unique, str, singleHeader), |
1535 'TE': (iteritems, listGenerator(generateAcceptQvalue),singleHeader), |
1535 'TE': (iteritems, listGenerator(generateAcceptQvalue), singleHeader), |
1536 'User-Agent':(unique, str,singleHeader), |
1536 'User-Agent': (unique, str, singleHeader), |
1537 } |
1537 } |
1538 |
1538 |
1539 parser_response_headers = { |
1539 parser_response_headers = { |
1540 'Accept-Ranges':(tokenize, filterTokens), |
1540 'Accept-Ranges': (tokenize, filterTokens), |
1541 'Age':(last,int), |
1541 'Age': (last, int), |
1542 'ETag':(tokenize, ETag.parse), |
1542 'ETag': (tokenize, ETag.parse), |
1543 'Location':(last,), # TODO: URI object? |
1543 'Location': (last,), # TODO: URI object? |
1544 # 'Proxy-Authenticate' |
1544 # 'Proxy-Authenticate' |
1545 'Retry-After':(last, parseRetryAfter), |
1545 'Retry-After': (last, parseRetryAfter), |
1546 'Server':(last,), |
1546 'Server': (last,), |
1547 'Set-Cookie':(parseSetCookie,), |
1547 'Set-Cookie': (parseSetCookie,), |
1548 'Set-Cookie2':(tokenize, parseSetCookie2), |
1548 'Set-Cookie2': (tokenize, parseSetCookie2), |
1549 'Vary':(tokenize, filterTokens), |
1549 'Vary': (tokenize, filterTokens), |
1550 'WWW-Authenticate': (lambda h: tokenize(h, foldCase=False), |
1550 'WWW-Authenticate': (lambda h: tokenize(h, foldCase=False), |
1551 parseWWWAuthenticate,) |
1551 parseWWWAuthenticate,) |
1552 } |
1552 } |
1553 |
1553 |
1554 generator_response_headers = { |
1554 generator_response_headers = { |
1555 'Accept-Ranges':(generateList, singleHeader), |
1555 'Accept-Ranges': (generateList, singleHeader), |
1556 'Age':(unique, str, singleHeader), |
1556 'Age': (unique, str, singleHeader), |
1557 'ETag':(ETag.generate, singleHeader), |
1557 'ETag': (ETag.generate, singleHeader), |
1558 'Location':(unique, str, singleHeader), |
1558 'Location': (unique, str, singleHeader), |
1559 # 'Proxy-Authenticate' |
1559 # 'Proxy-Authenticate' |
1560 'Retry-After':(generateRetryAfter, singleHeader), |
1560 'Retry-After': (generateRetryAfter, singleHeader), |
1561 'Server':(unique, str, singleHeader), |
1561 'Server': (unique, str, singleHeader), |
1562 'Set-Cookie':(generateSetCookie,), |
1562 'Set-Cookie': (generateSetCookie,), |
1563 'Set-Cookie2':(generateSetCookie2,), |
1563 'Set-Cookie2': (generateSetCookie2,), |
1564 'Vary':(generateList, singleHeader), |
1564 'Vary': (generateList, singleHeader), |
1565 'WWW-Authenticate':(generateWWWAuthenticate,) |
1565 'WWW-Authenticate': (generateWWWAuthenticate,) |
1566 } |
1566 } |
1567 |
1567 |
1568 parser_entity_headers = { |
1568 parser_entity_headers = { |
1569 'Allow':(lambda str:tokenize(str, foldCase=False), filterTokens), |
1569 'Allow': (lambda str:tokenize(str, foldCase=False), filterTokens), |
1570 'Content-Encoding':(tokenize, filterTokens), |
1570 'Content-Encoding': (tokenize, filterTokens), |
1571 'Content-Language':(tokenize, filterTokens), |
1571 'Content-Language': (tokenize, filterTokens), |
1572 'Content-Length':(last, int), |
1572 'Content-Length': (last, int), |
1573 'Content-Location':(last,), # TODO: URI object? |
1573 'Content-Location': (last,), # TODO: URI object? |
1574 'Content-MD5':(last, parseContentMD5), |
1574 'Content-MD5': (last, parseContentMD5), |
1575 'Content-Range':(last, parseContentRange), |
1575 'Content-Range': (last, parseContentRange), |
1576 'Content-Type':(lambda str:tokenize(str, foldCase=False), parseContentType), |
1576 'Content-Type': (lambda str:tokenize(str, foldCase=False), parseContentType), |
1577 'Expires':(last, parseExpires), |
1577 'Expires': (last, parseExpires), |
1578 'Last-Modified':(last, parseDateTime), |
1578 'Last-Modified': (last, parseDateTime), |
1579 } |
1579 } |
1580 |
1580 |
1581 generator_entity_headers = { |
1581 generator_entity_headers = { |
1582 'Allow':(generateList, singleHeader), |
1582 'Allow': (generateList, singleHeader), |
1583 'Content-Encoding':(generateList, singleHeader), |
1583 'Content-Encoding': (generateList, singleHeader), |
1584 'Content-Language':(generateList, singleHeader), |
1584 'Content-Language': (generateList, singleHeader), |
1585 'Content-Length':(unique, str, singleHeader), |
1585 'Content-Length': (unique, str, singleHeader), |
1586 'Content-Location':(unique, str, singleHeader), |
1586 'Content-Location': (unique, str, singleHeader), |
1587 'Content-MD5':(base64.encodestring, lambda x: x.strip("\n"), singleHeader), |
1587 'Content-MD5': (base64.encodestring, lambda x: x.strip("\n"), singleHeader), |
1588 'Content-Range':(generateContentRange, singleHeader), |
1588 'Content-Range': (generateContentRange, singleHeader), |
1589 'Content-Type':(generateContentType, singleHeader), |
1589 'Content-Type': (generateContentType, singleHeader), |
1590 'Expires':(generateDateTime, singleHeader), |
1590 'Expires': (generateDateTime, singleHeader), |
1591 'Last-Modified':(generateDateTime, singleHeader), |
1591 'Last-Modified': (generateDateTime, singleHeader), |
1592 } |
1592 } |
1593 |
1593 |
1594 DefaultHTTPHandler.updateParsers(parser_general_headers) |
1594 DefaultHTTPHandler.updateParsers(parser_general_headers) |
1595 DefaultHTTPHandler.updateParsers(parser_request_headers) |
1595 DefaultHTTPHandler.updateParsers(parser_request_headers) |
1596 DefaultHTTPHandler.updateParsers(parser_response_headers) |
1596 DefaultHTTPHandler.updateParsers(parser_response_headers) |