add request unitests. fix TeeInput & parser

This commit is contained in:
Benoit Chesneau 2010-01-21 00:18:42 +01:00
parent ba6db08825
commit b568852465
9 changed files with 201 additions and 29 deletions

View File

@ -4,5 +4,5 @@
# See the NOTICE for more information.
from gunicorn.http.http_parser import HttpParser
from gunicorn.http.request import HTTPRequest, RequestError
from gunicorn.http.response import HTTPResponse
from gunicorn.http.request import HttpRequest, RequestError
from gunicorn.http.response import HttpResponse

View File

@ -16,9 +16,9 @@ class HttpParser(object):
self.status = ""
self.headers = []
self.headers_dict = {}
self.raw_version = ""
self.raw_version = "HTTP/1.0"
self.raw_path = ""
self.version = None
self.version = (1,0)
self.method = ""
self.path = ""
self.query_string = ""
@ -70,8 +70,7 @@ class HttpParser(object):
self.headers_dict = _headers
headers.extend(list(_headers.items()))
self.headers = headers
self._content_len = int(_headers.get('Content-Length') or 0)
self._content_len = int(_headers.get('Content-Length',0))
(_, _, self.path, self.query_string, self.fragment) = urlparse.urlsplit(self.raw_path)
return pos
@ -122,7 +121,7 @@ class HttpParser(object):
None."""
transfert_encoding = self.headers_dict.get('Transfer-Encoding')
content_length = self.headers_dict.get('Content-Length')
if transfert_encoding is None:
if transfert_encoding != "chunked":
if content_length is None:
return 0
return int(content_length)

View File

@ -30,7 +30,7 @@ class RequestError(Exception):
""" raised when something wrong happend"""
class HTTPRequest(object):
class HttpRequest(object):
SERVER_VERSION = "gunicorn/%s" % __version__
@ -74,9 +74,6 @@ class HTTPRequest(object):
i = self.parser.filter_headers(headers, buf)
if i != -1: break
if not headers:
environ.update(self.DEFAULTS)
return environ
self.log.info("%s", self.parser.status)

View File

@ -11,7 +11,7 @@ import time
import os
from gunicorn.util import http_date, write, read_partial, close
class HTTPResponse(object):
class HttpResponse(object):
def __init__(self, sock, response, req):
self.req = req

View File

@ -43,6 +43,7 @@ class TeeInput(object):
if self._len: return self._len
if self._is_socket:
pos = self.tmp.tell()
print pos
while True:
if not self._tee(CHUNK_SIZE):
break
@ -53,14 +54,13 @@ class TeeInput(object):
def flush(self):
self.tmp.flush()
def read(self, length=None):
def read(self, length=-1):
""" read """
if not self._is_socket:
return self.tmp.read(length)
if length is None:
if length < 0:
r = self.tmp.read() or ""
print "avant %s" % str(len(r))
while True:
chunk = self._tee(CHUNK_SIZE)
if not chunk: break
@ -125,10 +125,7 @@ class TeeInput(object):
if chunk:
self.tmp.write(chunk)
self.tmp.seek(0, os.SEEK_END)
return chunk
if not data:
self._is_socket = False
break
return chunk
self._finalize()
return ""

View File

@ -19,7 +19,6 @@ from gunicorn import http
from gunicorn import util
class Worker(object):
SIGNALS = map(
@ -126,9 +125,9 @@ class Worker(object):
def handle(self, client, addr):
self.close_on_exec(client)
try:
req = http.HTTPRequest(client, addr, self.address)
req = http.HttpRequest(client, addr, self.address)
response = self.app(req.read(), req.start_response)
http.HTTPResponse(client, response, req).send()
http.HttpResponse(client, response, req).send()
except Exception, e:
# TODO: try to send something if an error happend
self.log.exception("Error processing request. [%s]" % str(e))

View File

@ -22,7 +22,7 @@ def test_001(buf, p):
])
body, tr = p.filter_body(buf[i:])
t.eq(body, '{"nom": "nom"}')
print t.eq(p.body_eof(), True)
t.eq(p.body_eof(), True)
@t.request("002.http")
def test_002(buf, p):

139
tests/002-test-request.py Normal file
View File

@ -0,0 +1,139 @@
# -*- coding: utf-8 -
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
import t
from gunicorn.http import tee
@t.http_request("001.http")
def test_001(req):
e = req.read()
t.eq(e['CONTENT_LENGTH'], '14')
t.eq(e['wsgi.version'], (1,0))
t.eq(e['REQUEST_METHOD'], 'PUT')
t.eq(e['PATH_INFO'], '/stuff/here')
t.eq(e['CONTENT_TYPE'], 'application/json')
t.eq(e['QUERY_STRING'], 'foo=bar')
t.eq(isinstance(e['wsgi.input'], tee.TeeInput), True)
body = e['wsgi.input'].read()
t.eq(body, '{"nom": "nom"}')
@t.http_request("002.http")
def http_request(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'GET')
t.eq(e['PATH_INFO'], "/test")
t.eq(e['QUERY_STRING'], "")
t.eq(sorted(p.headers), [
("Accept", "*/*"),
("Host", "0.0.0.0=5000"),
("User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1")
])
t.eq(e['HTTP_ACCEPT'], "*/*")
t.eq(e['HTTP_HOST'], "0.0.0.0=5000")
t.eq(e['HTTP_USER_AGENT', "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1"])
body = e['wsgi.input'].read()
t.eq(body, '')
@t.http_request("003.http")
def test_003(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'GET')
t.eq(e['PATH_INFO'], "/favicon.ico")
t.eq(e['QUERY_STRING'], "")
t.eq(e['HTTP_ACCEPT'], "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
t.eq(e['HTTP_KEEP_ALIVE'], "300")
body = e['wsgi.input'].read()
t.eq(body, '')
@t.http_request("004.http")
def test_004(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'GET')
t.eq(e['PATH_INFO'], "/dumbfuck")
t.eq(e['QUERY_STRING'], "")
body = e['wsgi.input'].read()
t.eq(body, '')
@t.http_request("005.http")
def test_005(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'GET')
t.eq(e['PATH_INFO'], "/forums/1/topics/2375")
t.eq(e['QUERY_STRING'], "page=1")
body = e['wsgi.input'].read()
t.eq(body, '')
@t.http_request("006.http")
def test_006(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'GET')
t.eq(e['PATH_INFO'], "/get_no_headers_no_body/world")
t.eq(e['QUERY_STRING'], "")
body = e['wsgi.input'].read()
t.eq(body, '')
@t.http_request("007.http")
def test_007(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'GET')
t.eq(e['PATH_INFO'], "/get_one_header_no_body")
t.eq(e['QUERY_STRING'], "")
t.eq(e['HTTP_ACCEPT'], "*/*")
body = e['wsgi.input'].read()
t.eq(body, '')
@t.http_request("008.http")
def test_008(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'GET')
t.eq(e['PATH_INFO'], "/get_funky_content_length_body_hello")
t.eq(e['QUERY_STRING'], "")
t.eq(e['CONTENT_LENGTH'], '5')
body = e['wsgi.input'].read()
t.eq(body, "HELLO")
@t.http_request("009.http")
def test_009(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'POST')
t.eq(e['PATH_INFO'], "/post_identity_body_world")
t.eq(e['QUERY_STRING'], "q=search")
t.eq(e['CONTENT_LENGTH'], '5')
body = e['wsgi.input'].read()
t.eq(body, "World")
@t.http_request("010.http")
def test_010(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'POST')
t.eq(e['PATH_INFO'], "/post_chunked_all_your_base")
t.eq(e['HTTP_TRANSFER_ENCODING'], "chunked")
t.eq(e['CONTENT_LENGTH'], '30')
body = e['wsgi.input'].read()
t.eq(body, "all your base are belong to us")
@t.http_request("011.http")
def test_011(req):
e = req.read()
t.eq(e['REQUEST_METHOD'], 'POST')
t.eq(e['PATH_INFO'], "/two_chunks_mult_zero_end")
t.eq(e['HTTP_TRANSFER_ENCODING'], "chunked")
t.eq(e['CONTENT_LENGTH'], '11')
body = e['wsgi.input'].read()
t.eq(body, "hello world")

View File

@ -7,14 +7,15 @@
import inspect
import os
import re
import tempfile
import unittest
from gunicorn.http import HttpParser
dirname = os.path.dirname(__file__)
from gunicorn.http.http_parser import HttpParser
from gunicorn.http.request import HttpRequest
def data_source(fname, eol):
def data_source(fname):
with open(fname) as handle:
lines = []
for line in handle:
@ -23,16 +24,56 @@ def data_source(fname, eol):
return "".join(lines)
class request(object):
def __init__(self, name, eol="\r\n"):
def __init__(self, name):
self.fname = os.path.join(dirname, "requests", name)
self.eol = eol
def __call__(self, func):
def run():
src = data_source(self.fname, self.eol)
src = data_source(self.fname)
func(src, HttpParser())
run.func_name = func.func_name
return run
class FakeSocket(object):
def __init__(self, data):
self.tmp = tempfile.TemporaryFile()
self.tmp.write(data)
self.tmp.flush()
self.tmp.seek(0)
def fileno(self):
return self.tmp.fileno()
def len(self):
return self.tmp.len
def recv(self, length=None):
return self.tmp.read()
def seek(self, offset, whence=0):
self.tmp.seek(offset, whence)
class http_request(object):
def __init__(self, name):
self.fname = os.path.join(dirname, "requests", name)
def __call__(self, func):
def run():
fsock = FakeSocket(data_source(self.fname))
req = HttpRequest(fsock, ('127.0.0.1', 6000),
('127.0.0.1', 8000))
func(req)
run.func_name = func.func_name
return run
def eq(a, b):
assert a == b, "%r != %r" % (a, b)