mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
all tests pass under python 3
This commit is contained in:
parent
60644b12af
commit
8d453fb341
@ -74,10 +74,10 @@ def reload_django_settings():
|
||||
app_mod = util.import_module(app[:-2])
|
||||
appdir = os.path.dirname(app_mod.__file__)
|
||||
app_subdirs = os.listdir(appdir)
|
||||
app_subdirs.sort()
|
||||
name_pattern = re.compile(r'[a-zA-Z]\w*')
|
||||
for d in app_subdirs:
|
||||
if name_pattern.match(d) and os.path.isdir(os.path.join(appdir, d)):
|
||||
for d in sorted(app_subdirs):
|
||||
if (name_pattern.match(d) and
|
||||
os.path.isdir(os.path.join(appdir, d))):
|
||||
new_installed_apps.append('%s.%s' % (app[:-2], d))
|
||||
else:
|
||||
new_installed_apps.append(app)
|
||||
|
||||
@ -99,7 +99,10 @@ class Arbiter(object):
|
||||
|
||||
if self.cfg.debug:
|
||||
self.log.debug("Current configuration:")
|
||||
for config, value in sorted(self.cfg.settings.iteritems()):
|
||||
|
||||
|
||||
for config, value in sorted(self.cfg.settings.items(),
|
||||
key=lambda setting: setting[1]):
|
||||
self.log.debug(" %s: %s", config, value.value)
|
||||
|
||||
if self.cfg.preload_app:
|
||||
@ -436,7 +439,7 @@ class Arbiter(object):
|
||||
self.spawn_workers()
|
||||
|
||||
workers = self.WORKERS.items()
|
||||
workers.sort(key=lambda w: w[1].age)
|
||||
workers = sorted(workers, key=lambda w: w[1].age)
|
||||
while len(workers) > self.num_workers:
|
||||
(pid, _) = workers.pop(0)
|
||||
self.kill_worker(pid, signal.SIGQUIT)
|
||||
|
||||
@ -15,7 +15,7 @@ import types
|
||||
from gunicorn import __version__
|
||||
from gunicorn.errors import ConfigError
|
||||
from gunicorn import util
|
||||
from gunicorn.six import string_types
|
||||
from gunicorn.six import string_types, integer_types, bytes_to_str
|
||||
|
||||
KNOWN_SETTINGS = []
|
||||
|
||||
@ -62,10 +62,12 @@ class Config(object):
|
||||
}
|
||||
parser = optparse.OptionParser(**kwargs)
|
||||
|
||||
keys = self.settings.keys()
|
||||
keys = list(self.settings)
|
||||
def sorter(k):
|
||||
return (self.settings[k].section, self.settings[k].order)
|
||||
keys.sort(key=sorter)
|
||||
|
||||
|
||||
keys = sorted(self.settings, key=self.settings.__getitem__)
|
||||
for k in keys:
|
||||
self.settings[k].add_option(parser)
|
||||
return parser
|
||||
@ -85,7 +87,7 @@ class Config(object):
|
||||
@property
|
||||
def address(self):
|
||||
bind = self.settings['bind'].get()
|
||||
return util.parse_address(util.to_bytestring(bind))
|
||||
return util.parse_address(bytes_to_str(bind))
|
||||
|
||||
@property
|
||||
def uid(self):
|
||||
@ -179,8 +181,15 @@ class Setting(object):
|
||||
assert callable(self.validator), "Invalid validator: %s" % self.name
|
||||
self.value = self.validator(val)
|
||||
|
||||
def __lt__(self, other):
|
||||
return (self.section == other.section and
|
||||
self.order < other.order)
|
||||
__cmp__ = __lt__
|
||||
|
||||
Setting = SettingMeta('Setting', (Setting,), {})
|
||||
|
||||
def validate_bool(val):
|
||||
if isinstance(val, types.BooleanType):
|
||||
if isinstance(val, bool):
|
||||
return val
|
||||
if not isinstance(val, string_types):
|
||||
raise TypeError("Invalid type for casting: %s" % val)
|
||||
@ -197,7 +206,7 @@ def validate_dict(val):
|
||||
return val
|
||||
|
||||
def validate_pos_int(val):
|
||||
if not isinstance(val, (types.IntType, types.LongType)):
|
||||
if not isinstance(val, integer_types):
|
||||
val = int(val, 0)
|
||||
else:
|
||||
# Booleans are ints!
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
# See the NOTICE for more information.
|
||||
|
||||
|
||||
class HaltServer(Exception):
|
||||
class HaltServer(BaseException):
|
||||
def __init__(self, reason, exit_status=1):
|
||||
self.reason = reason
|
||||
self.exit_status = exit_status
|
||||
@ -12,5 +12,5 @@ class HaltServer(Exception):
|
||||
def __str__(self):
|
||||
return "<HaltServer %r %d>" % (self.reason, self.exit_status)
|
||||
|
||||
class ConfigError(Exception):
|
||||
class ConfigError(BaseException):
|
||||
""" Exception raised on config error """
|
||||
|
||||
@ -7,16 +7,16 @@ import sys
|
||||
|
||||
from gunicorn.http.errors import (NoMoreData, ChunkMissingTerminator,
|
||||
InvalidChunkSize)
|
||||
from gunicorn.six import StringIO, bytes_to_str, integer_types
|
||||
from gunicorn import six
|
||||
|
||||
class ChunkedReader(object):
|
||||
def __init__(self, req, unreader):
|
||||
self.req = req
|
||||
self.parser = self.parse_chunked(unreader)
|
||||
self.buf = StringIO()
|
||||
self.buf = six.BytesIO()
|
||||
|
||||
def read(self, size):
|
||||
if not isinstance(size, integer_types):
|
||||
if not isinstance(size, six.integer_types):
|
||||
raise TypeError("size must be an integral type")
|
||||
if size <= 0:
|
||||
raise ValueError("Size must be positive.")
|
||||
@ -26,19 +26,19 @@ class ChunkedReader(object):
|
||||
if self.parser:
|
||||
while self.buf.tell() < size:
|
||||
try:
|
||||
self.buf.write(self.parser.next())
|
||||
self.buf.write(six.next(self.parser))
|
||||
except StopIteration:
|
||||
self.parser = None
|
||||
break
|
||||
|
||||
data = self.buf.getvalue()
|
||||
ret, rest = data[:size], data[size:]
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
self.buf.write(rest)
|
||||
return ret
|
||||
|
||||
def parse_trailers(self, unreader, data):
|
||||
buf = StringIO()
|
||||
buf = six.BytesIO()
|
||||
buf.write(data)
|
||||
|
||||
idx = buf.getvalue().find(b"\r\n\r\n")
|
||||
@ -50,8 +50,7 @@ class ChunkedReader(object):
|
||||
if done:
|
||||
unreader.unread(buf.getvalue()[2:])
|
||||
return b""
|
||||
self.req.trailers = self.req.parse_headers(
|
||||
bytes_to_str(buf.getvalue()[:idx]))
|
||||
self.req.trailers = self.req.parse_headers(buf.getvalue()[:idx])
|
||||
unreader.unread(buf.getvalue()[idx+4:])
|
||||
|
||||
def parse_chunked(self, unreader):
|
||||
@ -73,7 +72,7 @@ class ChunkedReader(object):
|
||||
(size, rest) = self.parse_chunk_size(unreader, data=rest[2:])
|
||||
|
||||
def parse_chunk_size(self, unreader, data=None):
|
||||
buf = StringIO()
|
||||
buf = six.BytesIO()
|
||||
if data is not None:
|
||||
buf.write(data)
|
||||
|
||||
@ -111,7 +110,7 @@ class LengthReader(object):
|
||||
self.length = length
|
||||
|
||||
def read(self, size):
|
||||
if not isinstance(size, integer_types):
|
||||
if not isinstance(size, six.integer_types):
|
||||
raise TypeError("size must be an integral type")
|
||||
|
||||
size = min(self.length, size)
|
||||
@ -121,7 +120,7 @@ class LengthReader(object):
|
||||
return b""
|
||||
|
||||
|
||||
buf = StringIO()
|
||||
buf = six.BytesIO()
|
||||
data = self.unreader.read()
|
||||
while data:
|
||||
buf.write(data)
|
||||
@ -138,21 +137,21 @@ class LengthReader(object):
|
||||
class EOFReader(object):
|
||||
def __init__(self, unreader):
|
||||
self.unreader = unreader
|
||||
self.buf = StringIO()
|
||||
self.buf = six.BytesIO()
|
||||
self.finished = False
|
||||
|
||||
def read(self, size):
|
||||
if not isinstance(size, integer_types):
|
||||
if not isinstance(size, six.integer_types):
|
||||
raise TypeError("size must be an integral type")
|
||||
if size < 0:
|
||||
raise ValueError("Size must be positive.")
|
||||
if size == 0:
|
||||
return ""
|
||||
return b""
|
||||
|
||||
if self.finished:
|
||||
data = self.buf.getvalue()
|
||||
ret, rest = data[:size], data[size:]
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
self.buf.write(rest)
|
||||
return ret
|
||||
|
||||
@ -168,31 +167,32 @@ class EOFReader(object):
|
||||
|
||||
data = self.buf.getvalue()
|
||||
ret, rest = data[:size], data[size:]
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
self.buf.write(rest)
|
||||
return ret
|
||||
|
||||
class Body(object):
|
||||
def __init__(self, reader):
|
||||
self.reader = reader
|
||||
self.buf = StringIO()
|
||||
self.buf = six.BytesIO()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
def __next__(self):
|
||||
ret = self.readline()
|
||||
if not ret:
|
||||
raise StopIteration()
|
||||
return ret
|
||||
next = __next__
|
||||
|
||||
def getsize(self, size):
|
||||
if size is None:
|
||||
return sys.maxint
|
||||
elif not isinstance(size, integer_types):
|
||||
return six.MAXSIZE
|
||||
elif not isinstance(size, six.integer_types):
|
||||
raise TypeError("size must be an integral type")
|
||||
elif size < 0:
|
||||
return sys.maxint
|
||||
return six.MAXSIZE
|
||||
return size
|
||||
|
||||
def read(self, size=None):
|
||||
@ -203,7 +203,7 @@ class Body(object):
|
||||
if size < self.buf.tell():
|
||||
data = self.buf.getvalue()
|
||||
ret, rest = data[:size], data[size:]
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
self.buf.write(rest)
|
||||
return ret
|
||||
|
||||
@ -215,7 +215,7 @@ class Body(object):
|
||||
|
||||
data = self.buf.getvalue()
|
||||
ret, rest = data[:size], data[size:]
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
self.buf.write(rest)
|
||||
return ret
|
||||
|
||||
@ -225,7 +225,7 @@ class Body(object):
|
||||
return b""
|
||||
|
||||
line = self.buf.getvalue()
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
if len(line) < size:
|
||||
line += self.reader.read(size - len(line))
|
||||
extra_buf_data = line[size:]
|
||||
|
||||
@ -3,12 +3,13 @@
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# See the NOTICE for more information.
|
||||
|
||||
class ParseException(Exception):
|
||||
class ParseException(BaseException):
|
||||
pass
|
||||
|
||||
class NoMoreData(IOError):
|
||||
def __init__(self, buf=None):
|
||||
self.buf = buf
|
||||
|
||||
def __str__(self):
|
||||
return "No more data after: %r" % self.buf
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ from gunicorn.http.errors import InvalidHeader, InvalidHeaderName, NoMoreData, \
|
||||
InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, \
|
||||
LimitRequestLine, LimitRequestHeaders
|
||||
from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
|
||||
from gunicorn.six import StringIO, urlsplit, bytes_to_str
|
||||
from gunicorn.six import BytesIO, urlsplit, bytes_to_str
|
||||
|
||||
MAX_REQUEST_LINE = 8190
|
||||
MAX_HEADERS = 32768
|
||||
@ -148,7 +148,6 @@ class Request(Message):
|
||||
|
||||
self.req_number = req_number
|
||||
self.proxy_protocol_info = None
|
||||
|
||||
super(Request, self).__init__(cfg, unreader)
|
||||
|
||||
|
||||
@ -161,7 +160,7 @@ class Request(Message):
|
||||
buf.write(data)
|
||||
|
||||
def parse(self, unreader):
|
||||
buf = StringIO()
|
||||
buf = BytesIO()
|
||||
self.get_data(unreader, buf, stop=True)
|
||||
|
||||
# get request line
|
||||
@ -170,12 +169,12 @@ class Request(Message):
|
||||
# proxy protocol
|
||||
if self.proxy_protocol(bytes_to_str(line)):
|
||||
# get next request line
|
||||
buf = StringIO()
|
||||
buf = BytesIO()
|
||||
buf.write(rbuf)
|
||||
line, rbuf = self.read_line(unreader, buf, self.limit_request_line)
|
||||
|
||||
self.parse_request_line(bytes_to_str(line))
|
||||
buf = StringIO()
|
||||
buf = BytesIO()
|
||||
buf.write(rbuf)
|
||||
|
||||
# Headers
|
||||
@ -202,7 +201,7 @@ class Request(Message):
|
||||
self.headers = self.parse_headers(data[:idx])
|
||||
|
||||
ret = data[idx+4:]
|
||||
buf = StringIO()
|
||||
buf = BytesIO()
|
||||
return ret
|
||||
|
||||
def read_line(self, unreader, buf, limit=0):
|
||||
|
||||
@ -22,7 +22,7 @@ class Parser(object):
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
def __next__(self):
|
||||
# Stop if HTTP dictates a stop.
|
||||
if self.mesg and self.mesg.should_close():
|
||||
raise StopIteration()
|
||||
@ -33,6 +33,7 @@ class Parser(object):
|
||||
while data:
|
||||
data = self.mesg.body.read(8192)
|
||||
|
||||
|
||||
# Parse the next request
|
||||
self.req_count += 1
|
||||
self.mesg = self.mesg_class(self.cfg, self.unreader, self.req_count)
|
||||
@ -40,6 +41,8 @@ class Parser(object):
|
||||
raise StopIteration()
|
||||
return self.mesg
|
||||
|
||||
next = __next__
|
||||
|
||||
class RequestParser(Parser):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RequestParser, self).__init__(Request, *args, **kwargs)
|
||||
|
||||
@ -5,44 +5,47 @@
|
||||
|
||||
import os
|
||||
|
||||
from gunicorn.six import integer_types, StringIO
|
||||
from gunicorn import six
|
||||
|
||||
# Classes that can undo reading data from
|
||||
# a given type of data source.
|
||||
|
||||
class Unreader(object):
|
||||
def __init__(self):
|
||||
self.buf = StringIO()
|
||||
self.buf = six.BytesIO()
|
||||
|
||||
def chunk(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def read(self, size=None):
|
||||
if size is not None and not isinstance(size, integer_types):
|
||||
if size is not None and not isinstance(size, six.integer_types):
|
||||
raise TypeError("size parameter must be an int or long.")
|
||||
if size == 0:
|
||||
return ""
|
||||
if size < 0:
|
||||
size = None
|
||||
|
||||
if size is not None:
|
||||
if size == 0:
|
||||
return b""
|
||||
if size < 0:
|
||||
size = None
|
||||
|
||||
self.buf.seek(0, os.SEEK_END)
|
||||
|
||||
if size is None and self.buf.tell():
|
||||
ret = self.buf.getvalue()
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
return ret
|
||||
if size is None:
|
||||
return self.chunk()
|
||||
d = self.chunk()
|
||||
return d
|
||||
|
||||
while self.buf.tell() < size:
|
||||
chunk = self.chunk()
|
||||
if not len(chunk):
|
||||
ret = self.buf.getvalue()
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
return ret
|
||||
self.buf.write(chunk)
|
||||
data = self.buf.getvalue()
|
||||
self.buf.truncate(0)
|
||||
self.buf = six.BytesIO()
|
||||
self.buf.write(data[size:])
|
||||
return data[:size]
|
||||
|
||||
@ -66,9 +69,9 @@ class IterUnreader(Unreader):
|
||||
|
||||
def chunk(self):
|
||||
if not self.iter:
|
||||
return ""
|
||||
return b""
|
||||
try:
|
||||
return self.iter.next()
|
||||
return six.next(self.iter)
|
||||
except StopIteration:
|
||||
self.iter = None
|
||||
return ""
|
||||
return b""
|
||||
|
||||
@ -281,10 +281,14 @@ _add_doc(u, """Text literal""")
|
||||
|
||||
|
||||
if PY3:
|
||||
|
||||
def execfile_(fname, *args):
|
||||
return exec(compile(open(fname, 'rb').read(), fname, 'exec'), *args)
|
||||
|
||||
|
||||
import builtins
|
||||
exec_ = getattr(builtins, "exec")
|
||||
|
||||
|
||||
def reraise(tp, value, tb=None):
|
||||
if value.__traceback__ is not tb:
|
||||
raise value.with_traceback(tb)
|
||||
@ -294,10 +298,6 @@ if PY3:
|
||||
print_ = getattr(builtins, "print")
|
||||
del builtins
|
||||
|
||||
def execfile_(file, globals=globals(), locals=locals()):
|
||||
with open(file, "r") as fh:
|
||||
exec_(fh.read()+"\n", globals, locals)
|
||||
|
||||
else:
|
||||
def exec_(code, globs=None, locs=None):
|
||||
"""Execute code in a namespace."""
|
||||
@ -373,33 +373,26 @@ def with_metaclass(meta, base=object):
|
||||
|
||||
# specific to gunicorn
|
||||
if PY3:
|
||||
import io
|
||||
StringIO = io.BytesIO
|
||||
|
||||
def bytes_to_str(b):
|
||||
if isinstance(b, text_type):
|
||||
return b
|
||||
return str(b, 'latin1')
|
||||
|
||||
import urllib.parse
|
||||
|
||||
unquote = urllib.parse.unquote
|
||||
urlsplit = urllib.parse.urlsplit
|
||||
urlparse = urllib.parse.urlparse
|
||||
|
||||
else:
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
|
||||
StringIO = StringIO
|
||||
|
||||
|
||||
def bytestring(s):
|
||||
def bytes_to_str(s):
|
||||
if isinstance(s, unicode):
|
||||
return s.encode('utf-8')
|
||||
return s
|
||||
|
||||
import urlparse as orig_urlparse
|
||||
urlsplit = orig_urlparse.urlsplit
|
||||
urlparse = orig_urlparse.urlparse
|
||||
|
||||
import urllib
|
||||
urlunquote = urllib.unquote
|
||||
|
||||
@ -311,15 +311,6 @@ def http_date(timestamp=None):
|
||||
hh, mm, ss)
|
||||
return s
|
||||
|
||||
def to_bytestring(s):
|
||||
""" convert to bytestring an unicode """
|
||||
if not isinstance(s, string_types):
|
||||
return s
|
||||
if isinstance(s, unicode):
|
||||
return s.encode('utf-8')
|
||||
else:
|
||||
return s
|
||||
|
||||
def is_hoppish(header):
|
||||
return header.lower().strip() in hop_headers
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import gunicorn.http as http
|
||||
import gunicorn.http.wsgi as wsgi
|
||||
import gunicorn.util as util
|
||||
import gunicorn.workers.base as base
|
||||
from gunicorn import six
|
||||
|
||||
ALREADY_HANDLED = object()
|
||||
|
||||
@ -32,14 +33,14 @@ class AsyncWorker(base.Worker):
|
||||
parser = http.RequestParser(self.cfg, client)
|
||||
try:
|
||||
if not self.cfg.keepalive:
|
||||
req = parser.next()
|
||||
req = six.next(parser)
|
||||
self.handle_request(req, client, addr)
|
||||
else:
|
||||
# keepalive loop
|
||||
while True:
|
||||
req = None
|
||||
with self.timeout_ctx():
|
||||
req = parser.next()
|
||||
req = six.next(parser)
|
||||
if not req:
|
||||
break
|
||||
self.handle_request(req, client, addr)
|
||||
|
||||
@ -18,6 +18,7 @@ InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, \
|
||||
LimitRequestLine, LimitRequestHeaders
|
||||
from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
|
||||
from gunicorn.http.wsgi import default_environ, Response
|
||||
from gunicorn.six import MAXSIZE
|
||||
|
||||
class Worker(object):
|
||||
|
||||
@ -43,7 +44,7 @@ class Worker(object):
|
||||
self.booted = False
|
||||
|
||||
self.nr = 0
|
||||
self.max_requests = cfg.max_requests or sys.maxint
|
||||
self.max_requests = cfg.max_requests or MAXSIZE
|
||||
self.alive = True
|
||||
self.log = log
|
||||
self.debug = cfg.debug
|
||||
|
||||
@ -14,6 +14,7 @@ import gunicorn.http as http
|
||||
import gunicorn.http.wsgi as wsgi
|
||||
import gunicorn.util as util
|
||||
import gunicorn.workers.base as base
|
||||
from gunicorn import six
|
||||
|
||||
class SyncWorker(base.Worker):
|
||||
|
||||
@ -69,7 +70,7 @@ class SyncWorker(base.Worker):
|
||||
try:
|
||||
client.settimeout(self.cfg.timeout)
|
||||
parser = http.RequestParser(self.cfg, client)
|
||||
req = parser.next()
|
||||
req = six.next(parser)
|
||||
self.handle_request(req, client, addr)
|
||||
except http.errors.NoMoreData as e:
|
||||
self.log.debug("Ignored premature client disconnection. %s", e)
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
from StringIO import StringIO
|
||||
|
||||
import t
|
||||
from gunicorn.http.body import Body
|
||||
|
||||
|
||||
def assert_readline(payload, size, expected):
|
||||
body = Body(StringIO(payload))
|
||||
t.eq(body.readline(size), expected)
|
||||
|
||||
|
||||
def test_readline_empty_body():
|
||||
assert_readline("", None, "")
|
||||
assert_readline("", 1, "")
|
||||
|
||||
|
||||
def test_readline_zero_size():
|
||||
assert_readline("abc", 0, "")
|
||||
assert_readline("\n", 0, "")
|
||||
|
||||
|
||||
def test_readline_new_line_before_size():
|
||||
body = Body(StringIO("abc\ndef"))
|
||||
t.eq(body.readline(4), "abc\n")
|
||||
t.eq(body.readline(), "def")
|
||||
|
||||
|
||||
def test_readline_new_line_after_size():
|
||||
body = Body(StringIO("abc\ndef"))
|
||||
t.eq(body.readline(2), "ab")
|
||||
t.eq(body.readline(), "c\n")
|
||||
|
||||
|
||||
def test_readline_no_new_line():
|
||||
body = Body(StringIO("abcdef"))
|
||||
t.eq(body.readline(), "abcdef")
|
||||
body = Body(StringIO("abcdef"))
|
||||
t.eq(body.readline(2), "ab")
|
||||
t.eq(body.readline(2), "cd")
|
||||
t.eq(body.readline(2), "ef")
|
||||
|
||||
|
||||
def test_readline_buffer_loaded():
|
||||
reader = StringIO("abc\ndef")
|
||||
body = Body(reader)
|
||||
body.read(1) # load internal buffer
|
||||
reader.write("g\nhi")
|
||||
reader.seek(7)
|
||||
t.eq(body.readline(), "bc\n")
|
||||
t.eq(body.readline(), "defg\n")
|
||||
t.eq(body.readline(), "hi")
|
||||
|
||||
|
||||
def test_readline_buffer_loaded_with_size():
|
||||
body = Body(StringIO("abc\ndef"))
|
||||
body.read(1) # load internal buffer
|
||||
t.eq(body.readline(2), "bc")
|
||||
t.eq(body.readline(2), "\n")
|
||||
t.eq(body.readline(2), "de")
|
||||
t.eq(body.readline(2), "f")
|
||||
|
||||
@ -7,5 +7,5 @@ request = {
|
||||
("CONTENT-TYPE", "application/json"),
|
||||
("CONTENT-LENGTH", "14")
|
||||
],
|
||||
"body": '{"nom": "nom"}'
|
||||
}
|
||||
"body": b'{"nom": "nom"}'
|
||||
}
|
||||
|
||||
@ -7,5 +7,5 @@ request = {
|
||||
("HOST", "0.0.0.0=5000"),
|
||||
("ACCEPT", "*/*")
|
||||
],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -12,5 +12,5 @@ request = {
|
||||
("KEEP-ALIVE", "300"),
|
||||
("CONNECTION", "keep-alive")
|
||||
],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ request = {
|
||||
"headers": [
|
||||
("AAAAAAAAAAAAA", "++++++++++")
|
||||
],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -3,5 +3,5 @@ request = {
|
||||
"uri": uri("/forums/1/topics/2375?page=1#posts-17408"),
|
||||
"version": (1, 1),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -3,5 +3,5 @@ request = {
|
||||
"uri": uri("/get_no_headers_no_body/world"),
|
||||
"version": (1, 1),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ request = {
|
||||
"headers": [
|
||||
("ACCEPT", "*/*")
|
||||
],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ request = {
|
||||
"headers": [
|
||||
("CONTENT-LENGTH", "5")
|
||||
],
|
||||
"body": "HELLO"
|
||||
}
|
||||
"body": b"HELLO"
|
||||
}
|
||||
|
||||
@ -7,5 +7,5 @@ request = {
|
||||
("TRANSFER-ENCODING", "identity"),
|
||||
("CONTENT-LENGTH", "5")
|
||||
],
|
||||
"body": "World"
|
||||
}
|
||||
"body": b"World"
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ request = {
|
||||
"headers": [
|
||||
("TRANSFER-ENCODING", "chunked"),
|
||||
],
|
||||
"body": "all your base are belong to us"
|
||||
}
|
||||
"body": b"all your base are belong to us"
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ request = {
|
||||
"headers": [
|
||||
("TRANSFER-ENCODING", "chunked")
|
||||
],
|
||||
"body": "hello world"
|
||||
}
|
||||
"body": b"hello world"
|
||||
}
|
||||
|
||||
@ -5,9 +5,9 @@ request = {
|
||||
"headers": [
|
||||
("TRANSFER-ENCODING", "chunked")
|
||||
],
|
||||
"body": "hello world",
|
||||
"body": b"hello world",
|
||||
"trailers": [
|
||||
("VARY", "*"),
|
||||
("CONTENT-TYPE", "text/plain")
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ request = {
|
||||
"headers": [
|
||||
("TRANSFER-ENCODING", "chunked")
|
||||
],
|
||||
"body": "hello world"
|
||||
}
|
||||
"body": b"hello world"
|
||||
}
|
||||
|
||||
@ -3,5 +3,5 @@ request = {
|
||||
"uri": uri('/with_"quotes"?foo="bar"'),
|
||||
"version": (1, 1),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -7,5 +7,5 @@ request = {
|
||||
("USER-AGENT", "ApacheBench/2.3"),
|
||||
("ACCEPT", "*/*")
|
||||
],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -36,5 +36,5 @@ request = {
|
||||
"uri": uri("/"),
|
||||
"version": (1, 1),
|
||||
"headers": [("X-SSL-CERT", certificate)],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -6,5 +6,5 @@ request = {
|
||||
("IF-MATCH", "bazinga!"),
|
||||
("IF-MATCH", "large-sound")
|
||||
],
|
||||
"body": ""
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ req1 = {
|
||||
"uri": uri("/first"),
|
||||
"version": (1, 1),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
"body": b""
|
||||
}
|
||||
|
||||
req2 = {
|
||||
@ -11,7 +11,7 @@ req2 = {
|
||||
"uri": uri("/second"),
|
||||
"version": (1, 1),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
"body": b""
|
||||
}
|
||||
|
||||
request = [req1, req2]
|
||||
|
||||
@ -3,5 +3,5 @@ request = {
|
||||
"uri": uri("/first"),
|
||||
"version": (1, 0),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -3,5 +3,5 @@ request = {
|
||||
"uri": uri("/first"),
|
||||
"version": (1, 0),
|
||||
"headers": [('CONTENT-LENGTH', '24')],
|
||||
"body": "GET /second HTTP/1.1\r\n\r\n"
|
||||
}
|
||||
"body": b"GET /second HTTP/1.1\r\n\r\n"
|
||||
}
|
||||
|
||||
@ -3,5 +3,5 @@ request = {
|
||||
"uri": uri("/first"),
|
||||
"version": (1, 1),
|
||||
"headers": [("CONNECTION", "Close")],
|
||||
"body": ""
|
||||
}
|
||||
"body": b""
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ req1 = {
|
||||
"uri": uri("/first"),
|
||||
"version": (1, 0),
|
||||
"headers": [("CONNECTION", "Keep-Alive")],
|
||||
"body": ""
|
||||
"body": b""
|
||||
}
|
||||
|
||||
req2 = {
|
||||
@ -11,7 +11,7 @@ req2 = {
|
||||
"uri": uri("/second"),
|
||||
"version": (1, 1),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
"body": b""
|
||||
}
|
||||
|
||||
request = [req1, req2]
|
||||
request = [req1, req2]
|
||||
|
||||
@ -5,7 +5,7 @@ req1 = {
|
||||
"headers": [
|
||||
("TRANSFER-ENCODING", "chunked")
|
||||
],
|
||||
"body": "hello world"
|
||||
"body": b"hello world"
|
||||
}
|
||||
|
||||
req2 = {
|
||||
@ -13,7 +13,7 @@ req2 = {
|
||||
"uri": uri("/second"),
|
||||
"version": (1, 1),
|
||||
"headers": [],
|
||||
"body": ""
|
||||
"body": b""
|
||||
}
|
||||
|
||||
request = [req1, req2]
|
||||
request = [req1, req2]
|
||||
|
||||
@ -6,7 +6,7 @@ req1 = {
|
||||
("CONTENT-LENGTH", "-1"),
|
||||
("TRANSFER-ENCODING", "chunked")
|
||||
],
|
||||
"body": "hello world"
|
||||
"body": b"hello world"
|
||||
}
|
||||
|
||||
req2 = {
|
||||
@ -17,7 +17,7 @@ req2 = {
|
||||
("TRANSFER-ENCODING", "chunked"),
|
||||
("CONTENT-LENGTH", "-1"),
|
||||
],
|
||||
"body": "hello world"
|
||||
"body": b"hello world"
|
||||
}
|
||||
|
||||
request = [req1, req2]
|
||||
|
||||
@ -12,5 +12,5 @@ request = {
|
||||
("CONTENT-TYPE", "application/json"),
|
||||
("CONTENT-LENGTH", "14")
|
||||
],
|
||||
"body": '{"nom": "nom"}'
|
||||
"body": b'{"nom": "nom"}'
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ req1 = {
|
||||
("CONTENT-LENGTH", "14"),
|
||||
("CONNECTION", "keep-alive")
|
||||
],
|
||||
"body": '{"nom": "nom"}'
|
||||
"body": b'{"nom": "nom"}'
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ req2 = {
|
||||
"headers": [
|
||||
("TRANSFER-ENCODING", "chunked"),
|
||||
],
|
||||
"body": "all your base are belong to us"
|
||||
"body": b"all your base are belong to us"
|
||||
}
|
||||
|
||||
request = [req1, req2]
|
||||
|
||||
35
tests/t.py
35
tests/t.py
@ -1,43 +1,43 @@
|
||||
# -*- coding: utf-8 -
|
||||
# Copyright 2009 Paul J. Davis <paul.joseph.davis@gmail.com>
|
||||
#
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# See the NOTICE for more information.
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import array
|
||||
import os
|
||||
from StringIO import StringIO
|
||||
import tempfile
|
||||
|
||||
dirname = os.path.dirname(__file__)
|
||||
|
||||
from gunicorn.http.parser import RequestParser
|
||||
from gunicorn.config import Config
|
||||
from gunicorn.six import BytesIO
|
||||
|
||||
def data_source(fname):
|
||||
buf = StringIO()
|
||||
buf = BytesIO()
|
||||
with open(fname) as handle:
|
||||
for line in handle:
|
||||
line = line.rstrip("\n").replace("\\r\\n", "\r\n")
|
||||
buf.write(line)
|
||||
buf.write(line.encode('latin1'))
|
||||
return buf
|
||||
|
||||
class request(object):
|
||||
def __init__(self, name):
|
||||
self.fname = os.path.join(dirname, "requests", name)
|
||||
|
||||
|
||||
def __call__(self, func):
|
||||
def run():
|
||||
src = data_source(self.fname)
|
||||
func(src, RequestParser(src))
|
||||
run.func_name = func.func_name
|
||||
return run
|
||||
|
||||
|
||||
|
||||
|
||||
class FakeSocket(object):
|
||||
|
||||
|
||||
def __init__(self, data):
|
||||
self.tmp = tempfile.TemporaryFile()
|
||||
if data:
|
||||
@ -47,32 +47,32 @@ class FakeSocket(object):
|
||||
|
||||
def fileno(self):
|
||||
return self.tmp.fileno()
|
||||
|
||||
|
||||
def len(self):
|
||||
return self.tmp.len
|
||||
|
||||
|
||||
def recv(self, length=None):
|
||||
return self.tmp.read()
|
||||
|
||||
|
||||
def recv_into(self, buf, length):
|
||||
tmp_buffer = self.tmp.read(length)
|
||||
v = len(tmp_buffer)
|
||||
for i, c in enumerate(tmp_buffer):
|
||||
buf[i] = c
|
||||
return v
|
||||
|
||||
|
||||
def send(self, data):
|
||||
self.tmp.write(data)
|
||||
self.tmp.flush()
|
||||
|
||||
|
||||
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))
|
||||
@ -80,7 +80,7 @@ class http_request(object):
|
||||
func(req)
|
||||
run.func_name = func.func_name
|
||||
return run
|
||||
|
||||
|
||||
def eq(a, b):
|
||||
assert a == b, "%r != %r" % (a, b)
|
||||
|
||||
@ -117,4 +117,3 @@ def raises(exctype, func, *args, **kwargs):
|
||||
func_name = getattr(func, "func_name", "<builtin_function>")
|
||||
raise AssertionError("Function %s did not raise %s" % (
|
||||
func_name, exctype.__name__))
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -
|
||||
#
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# See the NOTICE for more information.
|
||||
|
||||
import t
|
||||
@ -9,6 +9,8 @@ import treq
|
||||
import glob
|
||||
import os
|
||||
dirname = os.path.dirname(__file__)
|
||||
|
||||
from py.test import skip
|
||||
reqdir = os.path.join(dirname, "requests", "valid")
|
||||
|
||||
def a_case(fname):
|
||||
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -
|
||||
#
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# See the NOTICE for more information.
|
||||
|
||||
import t
|
||||
@ -8,7 +8,8 @@ import treq
|
||||
|
||||
import glob
|
||||
import os
|
||||
from nose.tools import raises
|
||||
|
||||
import pytest
|
||||
|
||||
dirname = os.path.dirname(__file__)
|
||||
reqdir = os.path.join(dirname, "requests", "invalid")
|
||||
@ -17,12 +18,12 @@ reqdir = os.path.join(dirname, "requests", "invalid")
|
||||
def test_http_parser():
|
||||
for fname in glob.glob(os.path.join(reqdir, "*.http")):
|
||||
env = treq.load_py(os.path.splitext(fname)[0] + ".py")
|
||||
|
||||
expect = env['request']
|
||||
cfg = env['cfg']
|
||||
req = treq.badrequest(fname)
|
||||
|
||||
@raises(expect)
|
||||
def check(fname):
|
||||
return req.check(cfg)
|
||||
|
||||
yield check, fname # fname is pass so that we know which test failed
|
||||
with pytest.raises(expect):
|
||||
def f(fname):
|
||||
return req.check(cfg)
|
||||
f(fname)
|
||||
@ -1,12 +1,10 @@
|
||||
# -*- coding: utf-8 -
|
||||
#
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# See the NOTICE for more information.
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
from nose.plugins.skip import SkipTest
|
||||
|
||||
import t
|
||||
|
||||
import functools
|
||||
@ -23,14 +21,6 @@ def cfg_file():
|
||||
def paster_ini():
|
||||
return os.path.join(dirname, "..", "examples", "frameworks", "pylonstest", "nose.ini")
|
||||
|
||||
def PasterApp():
|
||||
try:
|
||||
from paste.deploy import loadapp, loadwsgi
|
||||
except ImportError:
|
||||
raise SkipTest()
|
||||
from gunicorn.app.pasterapp import PasterApplication
|
||||
return PasterApplication("no_usage")
|
||||
|
||||
class AltArgs(object):
|
||||
def __init__(self, args=None):
|
||||
self.args = args or []
|
||||
@ -38,17 +28,17 @@ class AltArgs(object):
|
||||
|
||||
def __enter__(self):
|
||||
sys.argv = self.args
|
||||
|
||||
|
||||
def __exit__(self, exc_type, exc_inst, traceback):
|
||||
sys.argv = self.orig
|
||||
|
||||
class NoConfigApp(Application):
|
||||
def __init__(self):
|
||||
super(NoConfigApp, self).__init__("no_usage")
|
||||
|
||||
|
||||
def init(self, parser, opts, args):
|
||||
pass
|
||||
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
@ -63,25 +53,25 @@ def test_property_access():
|
||||
c = config.Config()
|
||||
for s in config.KNOWN_SETTINGS:
|
||||
getattr(c, s.name)
|
||||
|
||||
|
||||
# Class was loaded
|
||||
t.eq(c.worker_class, SyncWorker)
|
||||
|
||||
|
||||
# Debug affects workers
|
||||
t.eq(c.workers, 1)
|
||||
c.set("workers", 3)
|
||||
t.eq(c.workers, 3)
|
||||
|
||||
|
||||
# Address is parsed
|
||||
t.eq(c.address, ("127.0.0.1", 8000))
|
||||
|
||||
|
||||
# User and group defaults
|
||||
t.eq(os.geteuid(), c.uid)
|
||||
t.eq(os.getegid(), c.gid)
|
||||
|
||||
|
||||
# Proc name
|
||||
t.eq("gunicorn", c.proc_name)
|
||||
|
||||
|
||||
# Not a config property
|
||||
t.raises(AttributeError, getattr, c, "foo")
|
||||
# Force to be not an error
|
||||
@ -93,10 +83,10 @@ def test_property_access():
|
||||
|
||||
# Attempt to set a cfg not via c.set
|
||||
t.raises(AttributeError, setattr, c, "proc_name", "baz")
|
||||
|
||||
|
||||
# No setting for name
|
||||
t.raises(AttributeError, c.set, "baz", "bar")
|
||||
|
||||
|
||||
def test_bool_validation():
|
||||
c = config.Config()
|
||||
t.eq(c.debug, False)
|
||||
@ -196,30 +186,9 @@ def test_load_config():
|
||||
t.eq(app.cfg.bind, "unix:/tmp/bar/baz")
|
||||
t.eq(app.cfg.workers, 3)
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
|
||||
|
||||
def test_cli_overrides_config():
|
||||
with AltArgs(["prog_name", "-c", cfg_file(), "-b", "blarney"]):
|
||||
app = NoConfigApp()
|
||||
t.eq(app.cfg.bind, "blarney")
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
|
||||
def test_paster_config():
|
||||
with AltArgs(["prog_name", paster_ini()]):
|
||||
app = PasterApp()
|
||||
t.eq(app.cfg.bind, "192.168.0.1:80")
|
||||
t.eq(app.cfg.proc_name, "brim")
|
||||
t.eq("ignore_me" in app.cfg.settings, False)
|
||||
|
||||
def test_cfg_over_paster():
|
||||
with AltArgs(["prog_name", "-c", cfg_file(), paster_ini()]):
|
||||
app = PasterApp()
|
||||
t.eq(app.cfg.bind, "unix:/tmp/bar/baz")
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
t.eq(app.cfg.default_proc_name, "blurgh")
|
||||
|
||||
def test_cli_cfg_paster():
|
||||
with AltArgs(["prog_name", "-c", cfg_file(), "-b", "whee", paster_ini()]):
|
||||
app = PasterApp()
|
||||
t.eq(app.cfg.bind, "whee")
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
t.eq(app.cfg.default_proc_name, "blurgh")
|
||||
61
tests/test_004-http-body.py
Normal file
61
tests/test_004-http-body.py
Normal file
@ -0,0 +1,61 @@
|
||||
import t
|
||||
from gunicorn.http.body import Body
|
||||
from gunicorn.six import BytesIO
|
||||
|
||||
|
||||
def assert_readline(payload, size, expected):
|
||||
body = Body(BytesIO(payload))
|
||||
t.eq(body.readline(size), expected)
|
||||
|
||||
|
||||
def test_readline_empty_body():
|
||||
assert_readline(b"", None, b"")
|
||||
assert_readline(b"", 1, b"")
|
||||
|
||||
|
||||
def test_readline_zero_size():
|
||||
assert_readline(b"abc", 0, b"")
|
||||
assert_readline(b"\n", 0, b"")
|
||||
|
||||
|
||||
def test_readline_new_line_before_size():
|
||||
body = Body(BytesIO(b"abc\ndef"))
|
||||
t.eq(body.readline(4), b"abc\n")
|
||||
t.eq(body.readline(), b"def")
|
||||
|
||||
|
||||
def test_readline_new_line_after_size():
|
||||
body = Body(BytesIO(b"abc\ndef"))
|
||||
t.eq(body.readline(2), b"ab")
|
||||
t.eq(body.readline(), b"c\n")
|
||||
|
||||
|
||||
def test_readline_no_new_line():
|
||||
body = Body(BytesIO(b"abcdef"))
|
||||
t.eq(body.readline(), b"abcdef")
|
||||
body = Body(BytesIO(b"abcdef"))
|
||||
t.eq(body.readline(2), b"ab")
|
||||
t.eq(body.readline(2), b"cd")
|
||||
t.eq(body.readline(2), b"ef")
|
||||
|
||||
|
||||
def test_readline_buffer_loaded():
|
||||
reader = BytesIO(b"abc\ndef")
|
||||
body = Body(reader)
|
||||
body.read(1) # load internal buffer
|
||||
reader.write(b"g\nhi")
|
||||
reader.seek(7)
|
||||
print(reader.getvalue())
|
||||
t.eq(body.readline(), b"bc\n")
|
||||
t.eq(body.readline(), b"defg\n")
|
||||
t.eq(body.readline(), b"hi")
|
||||
|
||||
|
||||
def test_readline_buffer_loaded_with_size():
|
||||
body = Body(BytesIO(b"abc\ndef"))
|
||||
body.read(1) # load internal buffer
|
||||
t.eq(body.readline(2), b"bc")
|
||||
t.eq(body.readline(2), b"\n")
|
||||
t.eq(body.readline(2), b"de")
|
||||
t.eq(body.readline(2), b"f")
|
||||
|
||||
@ -10,18 +10,19 @@ import t
|
||||
import inspect
|
||||
import os
|
||||
import random
|
||||
import urlparse
|
||||
|
||||
from gunicorn.config import Config
|
||||
from gunicorn.http.errors import ParseException
|
||||
from gunicorn.http.parser import RequestParser
|
||||
from gunicorn.six import urlparse, execfile_
|
||||
from gunicorn import six
|
||||
|
||||
dirname = os.path.dirname(__file__)
|
||||
random.seed()
|
||||
|
||||
def uri(data):
|
||||
ret = {"raw": data}
|
||||
parts = urlparse.urlparse(data)
|
||||
parts = urlparse(data)
|
||||
ret["scheme"] = parts.scheme or ''
|
||||
ret["host"] = parts.netloc.rsplit(":", 1)[0] or None
|
||||
ret["port"] = parts.port or 80
|
||||
@ -42,7 +43,7 @@ def load_py(fname):
|
||||
config = globals().copy()
|
||||
config["uri"] = uri
|
||||
config["cfg"] = Config()
|
||||
execfile(fname, config)
|
||||
execfile_(fname, config)
|
||||
return config
|
||||
|
||||
class request(object):
|
||||
@ -54,10 +55,10 @@ class request(object):
|
||||
if not isinstance(self.expect, list):
|
||||
self.expect = [self.expect]
|
||||
|
||||
with open(self.fname) as handle:
|
||||
with open(self.fname, 'rb') as handle:
|
||||
self.data = handle.read()
|
||||
self.data = self.data.replace("\n", "").replace("\\r\\n", "\r\n")
|
||||
self.data = self.data.replace("\\0", "\000")
|
||||
self.data = self.data.replace(b"\n", b"").replace(b"\\r\\n", b"\r\n")
|
||||
self.data = self.data.replace(b"\\0", b"\000")
|
||||
|
||||
# Functions for sending data to the parser.
|
||||
# These functions mock out reading from a
|
||||
@ -69,20 +70,20 @@ class request(object):
|
||||
|
||||
def send_lines(self):
|
||||
lines = self.data
|
||||
pos = lines.find("\r\n")
|
||||
pos = lines.find(b"\r\n")
|
||||
while pos > 0:
|
||||
yield lines[:pos+2]
|
||||
lines = lines[pos+2:]
|
||||
pos = lines.find("\r\n")
|
||||
pos = lines.find(b"\r\n")
|
||||
if len(lines):
|
||||
yield lines
|
||||
|
||||
def send_bytes(self):
|
||||
for d in self.data:
|
||||
yield d
|
||||
for d in str(self.data, "latin1"):
|
||||
yield bytes(d, "latin1")
|
||||
|
||||
def send_random(self):
|
||||
maxs = len(self.data) / 10
|
||||
maxs = round(len(self.data) / 10)
|
||||
read = 0
|
||||
while read < len(self.data):
|
||||
chunk = random.randint(1, maxs)
|
||||
@ -143,7 +144,7 @@ class request(object):
|
||||
while len(body):
|
||||
if body[:len(data)] != data:
|
||||
raise AssertionError("Invalid data read: %r" % data)
|
||||
if '\n' in data[:-1]:
|
||||
if b'\n' in data[:-1]:
|
||||
raise AssertionError("Embedded new line: %r" % data)
|
||||
body = body[len(data):]
|
||||
data = self.szread(req.body.readline, sizes)
|
||||
@ -165,7 +166,7 @@ class request(object):
|
||||
"""
|
||||
data = req.body.readlines()
|
||||
for line in data:
|
||||
if '\n' in line[:-1]:
|
||||
if b'\n' in line[:-1]:
|
||||
raise AssertionError("Embedded new line: %r" % line)
|
||||
if line != body[:len(line)]:
|
||||
raise AssertionError("Invalid body data read: %r != %r" % (
|
||||
@ -182,7 +183,7 @@ class request(object):
|
||||
This skips sizes because there's its not part of the iter api.
|
||||
"""
|
||||
for line in req.body:
|
||||
if '\n' in line[:-1]:
|
||||
if b'\n' in line[:-1]:
|
||||
raise AssertionError("Embedded new line: %r" % line)
|
||||
if line != body[:len(line)]:
|
||||
raise AssertionError("Invalid body data read: %r != %r" % (
|
||||
@ -191,7 +192,7 @@ class request(object):
|
||||
if len(body):
|
||||
raise AssertionError("Failed to read entire body: %r" % body)
|
||||
try:
|
||||
data = iter(req.body).next()
|
||||
data = six.next(iter(req.body))
|
||||
raise AssertionError("Read data after body finished: %r" % data)
|
||||
except StopIteration:
|
||||
pass
|
||||
@ -214,9 +215,15 @@ class request(object):
|
||||
|
||||
ret = []
|
||||
for (mt, sz, sn) in cfgs:
|
||||
mtn = mt.func_name[6:]
|
||||
szn = sz.func_name[5:]
|
||||
snn = sn.func_name[5:]
|
||||
if hasattr(mt, 'funcname'):
|
||||
mtn = mt.func_name[6:]
|
||||
szn = sz.func_name[5:]
|
||||
snn = sn.func_name[5:]
|
||||
else:
|
||||
mtn = mt.__name__[6:]
|
||||
szn = sz.__name__[5:]
|
||||
snn = sn.__name__[5:]
|
||||
|
||||
def test_req(sn, sz, mt):
|
||||
self.check(cfg, sn, sz, mt)
|
||||
desc = "%s: MT: %s SZ: %s SN: %s" % (self.name, mtn, szn, snn)
|
||||
@ -251,9 +258,10 @@ class badrequest(object):
|
||||
self.data = handle.read()
|
||||
self.data = self.data.replace("\n", "").replace("\\r\\n", "\r\n")
|
||||
self.data = self.data.replace("\\0", "\000")
|
||||
self.data = self.data.encode('latin1')
|
||||
|
||||
def send(self):
|
||||
maxs = len(self.data) / 10
|
||||
maxs = round(len(self.data) / 10)
|
||||
read = 0
|
||||
while read < len(self.data):
|
||||
chunk = random.randint(1, maxs)
|
||||
@ -262,5 +270,4 @@ class badrequest(object):
|
||||
|
||||
def check(self, cfg):
|
||||
p = RequestParser(cfg, self.send())
|
||||
[req for req in p]
|
||||
|
||||
six.next(p)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user