Permalink
Browse files

add parser request tests

  • Loading branch information...
1 parent d754c6f commit 19d31b196317ecb9b63a1e6732aff886f4e3459d @benoitc benoitc committed Jun 10, 2010
Showing with 790 additions and 625 deletions.
  1. +1 −0 .gitignore
  2. +0 −234 restkit/parser.py
  3. +0 −207 tests/001-test-parser-request.py
  4. +28 −0 tests/001-test-valid-requests.py
  5. +18 −0 tests/002-test-invalid-requests.py
  6. +0 −110 tests/002-test-parser-response.py
  7. +0 −3 tests/requests/004.http
  8. +0 −4 tests/requests/008.http
  9. +0 −8 tests/requests/013.http
  10. +0 −2 tests/requests/014.http
  11. +0 −5 tests/requests/015.http
  12. +2 −0 tests/requests/invalid/001.http
  13. +2 −0 tests/requests/invalid/001.py
  14. +2 −0 tests/requests/invalid/002.http
  15. +2 −0 tests/requests/invalid/002.py
  16. +2 −0 tests/requests/invalid/003.http
  17. +2 −0 tests/requests/invalid/003.py
  18. +2 −0 tests/requests/invalid/004.http
  19. +2 −0 tests/requests/invalid/004.py
  20. +3 −0 tests/requests/invalid/005.http
  21. +2 −0 tests/requests/invalid/005.py
  22. 0 tests/requests/{ → valid}/001.http
  23. +11 −0 tests/requests/valid/001.py
  24. +1 −1 tests/requests/{ → valid}/002.http
  25. +11 −0 tests/requests/valid/002.py
  26. +1 −1 tests/requests/{ → valid}/003.http
  27. +16 −0 tests/requests/valid/003.py
  28. +3 −0 tests/requests/valid/004.http
  29. +9 −0 tests/requests/valid/004.py
  30. +1 −1 tests/requests/{ → valid}/005.http
  31. +7 −0 tests/requests/valid/005.py
  32. +1 −1 tests/requests/{ → valid}/006.http
  33. +7 −0 tests/requests/valid/006.py
  34. +1 −1 tests/requests/{ → valid}/007.http
  35. +9 −0 tests/requests/valid/007.py
  36. +4 −0 tests/requests/valid/008.http
  37. +9 −0 tests/requests/valid/008.py
  38. 0 tests/requests/{ → valid}/009.http
  39. +11 −0 tests/requests/valid/009.py
  40. +1 −1 tests/requests/{ → valid}/010.http
  41. +9 −0 tests/requests/valid/010.py
  42. 0 tests/requests/{ → valid}/011.http
  43. +9 −0 tests/requests/valid/011.py
  44. 0 tests/requests/{ → valid}/012.http
  45. +13 −0 tests/requests/valid/012.py
  46. +9 −0 tests/requests/valid/013.http
  47. +9 −0 tests/requests/valid/013.py
  48. +2 −0 tests/requests/valid/014.http
  49. +7 −0 tests/requests/valid/014.py
  50. +5 −0 tests/requests/valid/015.http
  51. +11 −0 tests/requests/valid/015.py
  52. +34 −33 tests/requests/{ → valid}/016.http
  53. +40 −0 tests/requests/valid/016.py
  54. 0 tests/requests/{ → valid}/017.http
  55. +10 −0 tests/requests/valid/017.py
  56. +4 −0 tests/requests/valid/018.http
  57. +17 −0 tests/requests/valid/018.py
  58. +4 −0 tests/requests/valid/019.http
  59. +7 −0 tests/requests/valid/019.py
  60. +5 −0 tests/requests/valid/020.http
  61. +7 −0 tests/requests/valid/020.py
  62. +5 −0 tests/requests/valid/021.http
  63. +7 −0 tests/requests/valid/021.py
  64. +5 −0 tests/requests/valid/022.http
  65. +17 −0 tests/requests/valid/022.py
  66. +11 −0 tests/requests/valid/023.http
  67. +19 −0 tests/requests/valid/023.py
  68. +35 −13 tests/t.py
  69. +318 −0 tests/treq.py
View
@@ -26,3 +26,4 @@ restkit.egg-info
dist/
doc/_build/
distribute-*
+.coverage
View
@@ -1,234 +0,0 @@
-# -*- coding: utf-8 -
-#
-# This file is part of restkit released under the MIT license.
-# See the NOTICE for more information.
-
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-import urlparse
-
-from restkit.errors import BadStatusLine, ParserError
-
-class Parser(object):
- """ HTTP Parser compatible 1.0 & 1.1
- This parser can parse HTTP requests and response.
- """
-
- def __init__(self, ptype='response', should_close=False):
- self.status_line = ""
- self.status_int = None
- self.reason = ""
- self.status = ""
- self.headers = []
- self.headers_dict = {}
- self.raw_version = "HTTP/1.0"
- self.raw_path = ""
- self.version = (1,0)
- self.method = ""
- self.path = ""
- self.query_string = ""
- self.fragment = ""
- self._content_len = None
- self.start_offset = 0
- self.chunk_size = 0
- self._chunk_eof = False
- self.type = ptype
- self._should_close = should_close
-
- @classmethod
- def parse_response(cls, should_close=False):
- """ Return parser object for response"""
- return cls(should_close=should_close)
-
- @classmethod
- def parse_request(cls):
- """ return parser object for requests """
- return cls(ptype='request')
-
- def filter_headers(self, headers, buf):
- """ take a string as buffer and an header dict
- (empty or not). It return new position or -1
- if parsing isn't done. headers dict is updated
- with new headers.
- """
- line = buf.getvalue()
- i = line.find("\r\n\r\n")
- if i != -1:
- r = line[:i]
- pos = i+4
- buf2 = StringIO()
- buf2.write(line[pos:])
- return self.finalize_headers(headers, r, buf2)
- return False
-
- def finalize_headers(self, headers, headers_str, buf2):
- """ parse the headers """
- lines = headers_str.split("\r\n")
-
- # parse first line of headers
- self._first_line(lines.pop(0))
-
- # parse headers. We silently ignore
- # bad headers' lines
-
- _headers = {}
- hname = ""
- for line in lines:
- if line.startswith('\t') or line.startswith(' '):
- headers[hname] += line.strip()
- else:
- try:
- hname =self._parse_headerl(_headers, line)
- except ValueError:
- # bad headers
- pass
- self.headers_dict = _headers
- headers.extend(list(_headers.items()))
- self.headers = headers
- self._content_len = int(_headers.get('Content-Length',0))
-
- if self.type == 'request':
- (_, _, self.path, self.query_string, self.fragment) = \
- urlparse.urlsplit(self.raw_path)
-
- return buf2
-
- def _parse_version(self, version):
- self.raw_version = version.strip()
- try:
- major, minor = self.raw_version.split("HTTP/")[1].split(".")
- self.version = (int(major), int(minor))
- except IndexError:
- self.version = (1, 0)
-
- def _first_line(self, line):
- """ parse first line """
- self.status_line = status_line = line.strip()
- try:
- if self.type == 'response':
- version, self.status = status_line.split(None, 1)
- self._parse_version(version)
- try:
- self.status_int, self.reason = self.status.split(None, 1)
- except ValueError:
- self.status_int = self.status
- self.status_int = int(self.status_int)
- else:
- method, path, version = status_line.split(None, 2)
- self._parse_version(version)
- self.method = method.upper()
- self.raw_path = path
- except ValueError:
- raise BadStatusLine(line)
-
- def _parse_headerl(self, hdrs, line):
- """ parse header line"""
- name, value = line.split(":", 1)
- name = name.strip().title()
- value = value.rsplit("\r\n",1)[0].strip()
- if name in hdrs:
- hdrs[name] = "%s, %s" % (hdrs[name], value)
- else:
- hdrs[name] = value
- return name
-
- @property
- def should_close(self):
- if self._should_close:
- return True
- elif self.headers_dict.get("Connection") == "close":
- return True
- elif self.headers_dict.get("Connection") == "Keep-Alive":
- return False
- elif self.version <= (1, 0):
- return True
- return False
-
- @property
- def is_chunked(self):
- """ is TE: chunked ?"""
- return (self.headers_dict.get('Transfer-Encoding') == "chunked")
-
- @property
- def content_len(self):
- """ return content length as integer or
- None."""
- transfert_encoding = self.headers_dict.get('Transfer-Encoding')
- content_length = self.headers_dict.get('Content-Length')
- if transfert_encoding != "chunked":
- if content_length is None:
- return 0
- return int(content_length)
- else:
- return None
-
- def body_eof(self):
- """do we have all the body ?"""
- if self.is_chunked:
- if self._chunk_eof:
- return True
- elif self._content_len == 0:
- return True
- return False
-
- def read_chunk(self, buf):
- line = buf.getvalue()
- buf2 = StringIO()
-
- if not self.start_offset:
- i = line.find("\r\n")
- if i != -1:
- chunk = line[:i].strip().split(";", 1)
- chunk_size = int(chunk.pop(0), 16)
- self.start_offset = i+2
- self.chunk_size = chunk_size
-
- if self.start_offset:
- if self.chunk_size == 0:
- self._chunk_eof = True
- buf2.write(line[:self.start_offset])
- return '', buf2
- else:
- chunk = line[self.start_offset:self.start_offset+self.chunk_size]
- end_offset = self.start_offset + self.chunk_size + 2
- # we wait CRLF else return None
- if len(buf.getvalue()) >= end_offset:
- buf2.write(line[end_offset:])
- self.chunk_size = 0
- return chunk, buf2
- return '', buf
-
- def trailing_header(self, buf):
- line = buf.getvalue()
- i = line.find("\r\n\r\n")
- return (i != -1)
-
- def filter_body(self, buf):
- """\
- Filter body and return a tuple: (body_chunk, new_buffer)
- Both can be None, and new_buffer is always None if its empty.
- """
- dlen = len(buf.getvalue())
- chunk = ''
-
- if self.is_chunked:
- try:
- chunk, buf2 = self.read_chunk(buf)
- except Exception, e:
- raise ParserError("chunked decoding error [%s]" % str(e))
-
- if not chunk:
- return '', buf
- else:
- buf2 = StringIO()
- if self._content_len > 0:
- nr = min(dlen, self._content_len)
- chunk = buf.getvalue()[:nr]
- self._content_len -= nr
-
- self.start_offset = 0
- buf2.seek(0, 2)
- return (chunk, buf2)
-
Oops, something went wrong.

0 comments on commit 19d31b1

Please sign in to comment.