mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
add request unitests. fix TeeInput & parser
This commit is contained in:
parent
ba6db08825
commit
b568852465
@ -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
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 ""
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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
139
tests/002-test-request.py
Normal 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")
|
||||
|
||||
53
tests/t.py
53
tests/t.py
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user