Permalink
Browse files

working on faster wsgi server

  • Loading branch information...
1 parent 4e3cdec commit ba4a176282c55fb3f8fa9ad2efe5a17f32667b6e Henk Punt committed Feb 18, 2010
View
@@ -1,5 +1,8 @@
+import logging
+
from concurrence import dispatch
-from concurrence.http import WSGIServer
+#from concurrence.http import WSGIServer
+from concurrence.http.server2 import WSGIServer
def hello_world(environ, start_response):
start_response("200 OK", [])
@@ -10,4 +13,5 @@ def main():
server.serve(('localhost', 8080))
if __name__ == '__main__':
+ logging.basicConfig()
dispatch(main)
@@ -30,9 +30,9 @@ class COMMAND:
QUERY = 0x03
LIST = 0x04
PING = 0x0e
-
+
class CAPS(object):
- LONG_PASSWORD = 1 # new more secure passwords
+ LONG_PASSWORD = 1 # new more secure passwords
FOUND_ROWS = 2 #Found instead of affected rows
LONG_FLAG = 4 #Get all column flags */
CONNECT_WITH_DB = 8 # One can specify db on connect */
@@ -51,7 +51,7 @@ class CAPS(object):
MULTI_STATEMENTS= 65536 # Enable/disable multi-stmt support */
MULTI_RESULTS = 131072 # Enable/disable multi-results */
- __ALL__ = {LONG_PASSWORD: 'CLIENT_LONG_PASSWORD',
+ __ALL__ = {LONG_PASSWORD: 'CLIENT_LONG_PASSWORD',
FOUND_ROWS: 'CLIENT_FOUND_ROWS',
LONG_FLAG: 'CLIENT_LONG_FLAG',
CONNECT_WITH_DB: 'CLIENT_CONNECT_WITH_DB',
@@ -69,7 +69,7 @@ class CAPS(object):
SECURE_CONNECTION: 'CLIENT_SECURE_CONNECTION',
MULTI_STATEMENTS: 'CLIENT_MULTI_STATEMENTS',
MULTI_RESULTS: 'CLIENT_MULTI_RESULTS'}
-
+
@classmethod
def dbg(cls, caps):
for value, name in cls.__ALL__.items():
@@ -80,7 +80,7 @@ def create_scramble_buff():
import random
return ''.join([chr(random.randint(0, 255)) for _ in xrange(20)])
-
+
class BufferedPacketWriter(BufferedWriter):
#TODO make writers really buffered
def __init__(self, stream, buffer):
@@ -94,16 +94,16 @@ def write_error(self, errno, errmsg):
self.buffer.write_byte((errno >> 8) & 0xFF)
#ERROR MSG:
self.buffer.write_bytes(self.ERROR_TEMPLATE % errmsg)
-
+
def write_ok(self, field_count, affected_rows, insert_id, server_status, warning_count, msg = ''):
- self.buffer.write_byte(field_count)
+ self.buffer.write_byte(field_count)
self.buffer.write_byte(affected_rows)
- self.buffer.write_byte(insert_id)
+ self.buffer.write_byte(insert_id)
self.buffer.write_short(server_status) #server Status
- self.buffer.write_short(warning_count)
+ self.buffer.write_short(warning_count)
if msg:
self.buffer.write_bytes(msg)
-
+
def write_greeting(self, scramble_buff, protocol_version, server_version, thread_id, server_caps, server_language, server_status):
self.buffer.write_byte(protocol_version)
@@ -116,35 +116,35 @@ def write_greeting(self, scramble_buff, protocol_version, server_version, thread
self.buffer.write_short(server_status)
self.buffer.write_bytes('\0' * 13) #filler
self.buffer.write_bytes(scramble_buff[8:])
-
+
def write_header(self, length, packet_number):
self.buffer.write_int((length - 4) | (packet_number << 24))
-
+
def start(self):
"""starts building a packet"""
self.start_position = self.buffer.position #remember start of header
self.buffer.skip(4) #reserve room for header
-
+
def finish(self, packet_number):
"""finishes packet by going back to start of packet and writing header and packetNumber"""
position = self.buffer.position
- length = self.buffer.position - self.start_position
+ length = self.buffer.position - self.start_position
#print length
self.buffer.position = self.start_position
self.write_header(length, packet_number)
self.buffer.position = position
-
+
def write_int(self, i):
self.buffer.write_int(i)
def write_lcb(self, b):
assert b < 128, "TODO larger numbers"
self.buffer.write_byte(b)
-
+
def write_lcs(self, s):
self.write_lcb(len(s))
self.buffer.write_bytes(s)
-
+
class BufferedPacketReader(BufferedReader):
def __init__(self, stream, buffer):
@@ -155,47 +155,47 @@ def __init__(self, stream, buffer):
def read_packets(self):
reader = self.reader
-
+
READ_RESULT_END = PACKET_READ_RESULT.END
READ_RESULT_MORE = PACKET_READ_RESULT.MORE
while True:
read_result = reader.read_packet()
if read_result & READ_RESULT_END:
- yield reader.packet
+ yield reader.packet
if not (read_result & READ_RESULT_MORE):
- self._read_more()
-
+ self.fill()
+
def read_packet(self):
return self.read_packets().next()
def read_length_coded_binary(self):
return self.reader.read_length_coded_binary()
-
+
def read_fields(self, field_count):
-
+
#generator for rest of result packets
packets = self.read_packets()
-
+
#read field types
fields = []
-
+
reader = self.reader
i = 0
- while i < field_count:
+ while i < field_count:
_ = packets.next()
fields.append(reader.read_field_type())
i += 1
#end of field types
packet = packets.next()
assert packet.read_byte() == 0xFE, "expected end of fields"
-
- return fields
+
+ return fields
def read_rows(self, fields, row_count = 100):
reader = self.reader
-
+
READ_RESULT_EOF = PACKET_READ_RESULT.EOF
READ_RESULT_MORE = PACKET_READ_RESULT.MORE
@@ -206,6 +206,6 @@ def read_rows(self, fields, row_count = 100):
if read_result & READ_RESULT_EOF:
break
if not (read_result & READ_RESULT_MORE):
- self._read_more()
+ self.fill()
+
-
@@ -3,11 +3,13 @@
# This module is part of the Concurrence Framework and is released under
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
+from concurrence.http._http import HTTPParser, HTTPParserError
+
class HTTPError(Exception): pass
class HTTPRequest(object):
"""A class representing a HTTP request."""
-
+
def __init__(self, path = None, method = None, host = None):
"""Create a new http request for *path* using *method* to *host*."""
self.path = path
@@ -17,11 +19,11 @@ def __init__(self, path = None, method = None, host = None):
self._body = None
def add_header(self, key, value):
- """Adds a new header to the request with name *key* and given *value*."""
+ """Adds a new header to the request with name *key* and given *value*."""
self.headers.append((key, value))
def _set_body(self, body):
- if body is not None:
+ if body is not None:
assert type(body) == str
self.add_header('Content_length', len(body))
self._body = body
@@ -33,7 +35,7 @@ def _get_body(self):
class HTTPResponse(object):
"""Represents a HTTP Response."""
-
+
def __init__(self):
self.headers = []
self.status = ''
@@ -4,6 +4,7 @@
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
from concurrence.io._io cimport Buffer
+from concurrence.io._io import BufferUnderflowError
cdef extern from "http11_parser.h":
ctypedef struct http_parser
@@ -35,77 +36,106 @@ cdef extern from "Python.h":
cdef class HTTPParser
cdef void cb_request_method(void *data, char *at, size_t length):
- (<HTTPParser>data).request_method(PyString_FromStringAndSize(at, length))
+ (<HTTPParser>data)._cb_request_method(PyString_FromStringAndSize(at, length))
cdef void cb_request_uri(void *data, char *at, size_t length):
- (<HTTPParser>data).request_uri(PyString_FromStringAndSize(at, length))
+ (<HTTPParser>data)._cb_request_uri(PyString_FromStringAndSize(at, length))
cdef void cb_fragment(void *data, char *at, size_t length):
- (<HTTPParser>data).fragment(PyString_FromStringAndSize(at, length))
+ #(<HTTPParser>data)._cb_fragment(PyString_FromStringAndSize(at, length))
+ pass #unused for now, fragment is not part of cgi spec
cdef void cb_request_path(void *data, char *at, size_t length):
- (<HTTPParser>data).request_path(PyString_FromStringAndSize(at, length))
+ (<HTTPParser>data)._cb_request_path(PyString_FromStringAndSize(at, length))
cdef void cb_query_string(void *data, char *at, size_t length):
- (<HTTPParser>data).query_string(PyString_FromStringAndSize(at, length))
+ (<HTTPParser>data)._cb_query_string(PyString_FromStringAndSize(at, length))
cdef void cb_http_version(void *data, char *at, size_t length):
- (<HTTPParser>data).http_version(PyString_FromStringAndSize(at, length))
+ (<HTTPParser>data)._cb_http_version(PyString_FromStringAndSize(at, length))
cdef void cb_header_done(void *data, char *at, size_t length):
- (<HTTPParser>data).header_done(PyString_FromStringAndSize(at, length))
+ #(<HTTPParser>data)._cb_header_done(PyString_FromStringAndSize(at, length))
+ pass #unused
cdef void cb_field(void *data, char *field, size_t flen, char *value, size_t vlen):
- (<HTTPParser>data).field(PyString_FromStringAndSize(field, flen), PyString_FromStringAndSize(value, vlen))
+ (<HTTPParser>data)._cb_field(PyString_FromStringAndSize(field, flen), PyString_FromStringAndSize(value, vlen))
+
+class HTTPParserError(Exception):
+ pass
cdef class HTTPParser:
"""
"""
cdef http_parser *_parser
cdef Buffer _buffer
+ cdef readonly environ
def __cinit__(self, Buffer buffer):
- self._buffer = buffer
self._parser = http_parser_alloc(<void *>self, cb_request_method, cb_request_uri, cb_fragment, cb_request_path, cb_query_string, cb_http_version, cb_header_done, cb_field)
http_parser_init(self._parser)
+ def __init__(self, Buffer buffer):
+ self._buffer = buffer
+ self.environ = {}
+
def __dealloc__(self):
http_parser_free(self._parser)
- cdef request_method(self, method):
- pass
- #print 'method:', repr(method)
-
- cdef query_string(self, qs):
- pass
- #print 'qs:', repr(qs)
-
- cdef request_path(self, path):
- pass
- #print 'path:', repr(path)
-
-
- cdef fragment(self, fragment):
- pass
- #print 'fragment', repr(fragment)
-
- cdef request_uri(self, uri):
- pass
- #print 'r_uri', uri
-
- cdef http_version(self, version):
- pass
- #print 'version', repr(version)
-
- cdef header_done(self, hd):
- pass
- #print 'header_done', repr(hd)
-
- cdef field(self, name, value):
- pass
- #print 'field', repr(name), repr(value)
-
- def execute(self):
- return http_parser_execute(self._parser, <char *>self._buffer._buff, self._buffer._remaining(), self._buffer._position)
-
-
+ cdef _cb_request_method(self, method):
+ self.environ['REQUEST_METHOD'] = method
+
+ cdef _cb_query_string(self, qs):
+ self.environ['QUERY_STRING'] = qs
+
+ cdef _cb_request_path(self, path):
+ self.environ['PATH_INFO'] = path
+
+ cdef _cb_fragment(self, fragment):
+ pass #unused, not part of cgi spec
+
+ cdef _cb_request_uri(self, uri):
+ self.environ['REQUEST_URI'] = uri
+
+ cdef _cb_http_version(self, version):
+ self.environ['HTTP_VERSION'] = version
+
+ cdef _cb_header_done(self, hd):
+ pass #unused
+
+ cdef _cb_field(self, name, value):
+ key = 'HTTP_' + name
+ if key in self.environ:
+ self.environ[key] += ',' + value # comma-separate multiple headers
+ else:
+ self.environ[key] = value
+
+ def parse(self):
+ cdef size_t nread
+ cdef int r
+ if http_parser_is_finished(self._parser):
+ raise HTTPParserError("cannot parse: parser already finished")
+ elif http_parser_has_error(self._parser):
+ raise HTTPParserError("cannot parse: parser already finished with error")
+ remaining = self._buffer._remaining()
+ if remaining > 0:
+ nread = http_parser_execute(self._parser, <char *>self._buffer._buff, remaining, self._buffer._position)
+ if http_parser_has_error(self._parser):
+ raise HTTPParserError("parse error")
+ else:
+ self._buffer._position += self._buffer._position + nread
+ return self.is_finished()
+ else:
+ raise BufferUnderflowError()
+
+ def is_finished(self):
+ if http_parser_is_finished(self._parser):
+ return True
+ else:
+ return False
+
+ def has_error(self):
+ if http_parser_has_error(self._parser):
+ return True
+ else:
+ return False
@@ -11,6 +11,7 @@ http_parser *http_parser_alloc(void *obj, element_cb request_method,
element_cb http_version,
element_cb header_done,
field_cb field);
+
void http_parser_free(http_parser *);
#endif
Oops, something went wrong.

0 comments on commit ba4a176

Please sign in to comment.