changeset 37:c6b41464c021 default tip

factored async web server into separate file
author Atul Varma <varmaa@toolness.com>
date Thu, 24 Dec 2009 18:34:51 -0800
parents 352f4cc55d12
children
files async_web_server.py bzapi_server.py
diffstat 2 files changed, 106 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/async_web_server.py	Thu Dec 24 18:34:51 2009 -0800
@@ -0,0 +1,99 @@
+import os
+import httplib
+import cStringIO
+import mimetools
+import mimetypes
+import logging
+
+import cosocket
+
+KEEP_ALIVE_MAX_REQUESTS = 99
+KEEP_ALIVE_TIMEOUT = int(cosocket.DEFAULT_TIMEOUT)
+KEEP_ALIVE_ENABLED = True
+
+BLOCK_SIZE = 8192
+
+def until_http_response_sent(msg = '', mimetype = 'text/plain',
+                             length = None, code = 200,
+                             additional_headers = None):
+    headers = {'Content-Type': mimetype}
+    if KEEP_ALIVE_ENABLED:
+        headers.update({'Keep-Alive': 'timeout=%d, max=%d' %
+                        (KEEP_ALIVE_TIMEOUT,
+                         KEEP_ALIVE_MAX_REQUESTS),
+                        'Connection': 'Keep-Alive'})
+    if additional_headers:
+        headers.update(additional_headers)
+    if length is None:
+        length = len(msg)
+    headers['Content-Length'] = str(length)
+
+    header_lines = ['HTTP/1.1 %d %s' % (code,
+                                        httplib.responses[code])]
+    header_lines.extend(['%s: %s' % (key, value)
+                         for key, value in headers.items()])
+    header_lines.extend(['', msg])
+    content = '\r\n'.join(header_lines)
+    yield cosocket.until_sent(content)
+
+def until_http_file_sent(filename, block_size = BLOCK_SIZE):
+    ext = '.' + filename.split('.')[-1]
+
+    if ext in mimetypes.types_map:
+        mimetype = mimetypes.types_map[ext]
+    else:
+        mimetype = 'text/plain'
+
+    length = os.stat(filename).st_size
+    num_blocks = length / block_size
+    if length % block_size:
+        num_blocks += 1
+    infile = open(filename, 'r')
+
+    yield until_http_response_sent(mimetype = mimetype,
+                                   length = length)
+
+    for i in range(num_blocks):
+        # TODO: This could be bad since we're reading the file
+        # synchronously.
+        block = infile.read(block_size)
+        yield cosocket.until_sent(block)
+
+class AsyncWebServer(object):
+    def __init__(self, addr, app):
+        self._num_connections = 0
+        self._app = app
+        cosocket.AsyncChatCoroutine(self._server_coroutine(addr))
+
+    def _server_coroutine(self, bind_addr):
+        yield cosocket.until_listening(bind_addr)
+        while 1:
+            conn, addr = yield cosocket.until_connection_accepted()
+            cosocket.AsyncChatCoroutine(self._connection_coroutine(addr),
+                                        conn)
+
+    def _connection_coroutine(self, addr):
+        self._num_connections += 1
+        try:
+            if KEEP_ALIVE_ENABLED:
+                for i in range(KEEP_ALIVE_MAX_REQUESTS):
+                    yield self._until_one_request_processed(addr)
+            else:
+                yield self._until_one_request_processed(addr)
+        finally:
+            logging.info('Closing connection to %s' % repr(addr))
+            self._num_connections -= 1
+
+    def _until_one_request_processed(self, addr):
+        request = yield cosocket.until_received(terminator = '\r\n\r\n')
+        request = request.splitlines()
+        request_line = request[0]
+        logging.info("Request from %s: %s" % (addr, request_line))
+        stringfile = cStringIO.StringIO('\n'.join(request[1:]))
+        headers = mimetools.Message(stringfile)
+        req_parts = request_line.split()
+
+        yield self._app.until_request_processed(method = req_parts[0],
+                                                path = req_parts[1],
+                                                headers = headers,
+                                                addr = addr)
--- a/bzapi_server.py	Thu Dec 24 18:07:39 2009 -0800
+++ b/bzapi_server.py	Thu Dec 24 18:34:51 2009 -0800
@@ -1,110 +1,19 @@
 import os
 import sys
 import re
-import httplib
-import cStringIO
-import mimetools
-import mimetypes
 import cgi
 import logging
 
-from cosocket import *
-import channels
-
 try:
     import json
 except ImportError:
     import simplejson as json
 
-KEEP_ALIVE_MAX_REQUESTS = 99
-KEEP_ALIVE_TIMEOUT = int(DEFAULT_TIMEOUT)
-KEEP_ALIVE_ENABLED = True
-
-BLOCK_SIZE = 8192
-
-def until_http_response_sent(msg = '', mimetype = 'text/plain',
-                             length = None, code = 200,
-                             additional_headers = None):
-    headers = {'Content-Type': mimetype}
-    if KEEP_ALIVE_ENABLED:
-        headers.update({'Keep-Alive': 'timeout=%d, max=%d' %
-                        (KEEP_ALIVE_TIMEOUT,
-                         KEEP_ALIVE_MAX_REQUESTS),
-                        'Connection': 'Keep-Alive'})
-    if additional_headers:
-        headers.update(additional_headers)
-    if length is None:
-        length = len(msg)
-    headers['Content-Length'] = str(length)
-
-    header_lines = ['HTTP/1.1 %d %s' % (code,
-                                        httplib.responses[code])]
-    header_lines.extend(['%s: %s' % (key, value)
-                         for key, value in headers.items()])
-    header_lines.extend(['', msg])
-    content = '\r\n'.join(header_lines)
-    yield until_sent(content)
-
-def until_http_file_sent(filename, block_size = BLOCK_SIZE):
-    ext = '.' + filename.split('.')[-1]
-
-    if ext in mimetypes.types_map:
-        mimetype = mimetypes.types_map[ext]
-    else:
-        mimetype = 'text/plain'
-
-    length = os.stat(filename).st_size
-    num_blocks = length / block_size
-    if length % block_size:
-        num_blocks += 1
-    infile = open(filename, 'r')
-
-    yield until_http_response_sent(mimetype = mimetype,
-                                   length = length)
-
-    for i in range(num_blocks):
-        # TODO: This could be bad since we're reading the file
-        # synchronously.
-        block = infile.read(block_size)
-        yield until_sent(block)
-
-class AsyncWebServer(object):
-    def __init__(self, addr, app):
-        self._num_connections = 0
-        self._app = app
-        AsyncChatCoroutine(self._server_coroutine(addr))
-
-    def _server_coroutine(self, bind_addr):
-        yield until_listening(bind_addr)
-        while 1:
-            conn, addr = yield until_connection_accepted()
-            AsyncChatCoroutine(self._connection_coroutine(addr), conn)
-
-    def _connection_coroutine(self, addr):
-        self._num_connections += 1
-        try:
-            if KEEP_ALIVE_ENABLED:
-                for i in range(KEEP_ALIVE_MAX_REQUESTS):
-                    yield self._until_one_request_processed(addr)
-            else:
-                yield self._until_one_request_processed(addr)
-        finally:
-            logging.info('Closing connection to %s' % repr(addr))
-            self._num_connections -= 1
-
-    def _until_one_request_processed(self, addr):
-        request = yield until_received(terminator = '\r\n\r\n')
-        request = request.splitlines()
-        request_line = request[0]
-        logging.info("Request from %s: %s" % (addr, request_line))
-        stringfile = cStringIO.StringIO('\n'.join(request[1:]))
-        headers = mimetools.Message(stringfile)
-        req_parts = request_line.split()
-
-        yield self._app.until_request_processed(method = req_parts[0],
-                                                path = req_parts[1],
-                                                headers = headers,
-                                                addr = addr)
+import channels
+import cosocket
+from async_web_server import until_http_response_sent
+from async_web_server import until_http_file_sent
+from async_web_server import AsyncWebServer
 
 class BugzillaApiApp(object):
     QUERYSTRING_TEMPLATE = re.compile('([^\?]*)\?(.*)')
@@ -187,7 +96,7 @@
                 yield until_http_response_sent('message too large',
                                                code = 413)
             else:
-                msg = yield until_received(bytes = length)
+                msg = yield cosocket.until_received(bytes = length)
                 json_msg = json.loads(msg)
                 yield channels.until_message_sent(conv_name, json_msg)
                 yield until_http_response_sent('sent.')
@@ -218,4 +127,4 @@
                             app = app)
 
     logging.info("Starting server with configuration: %s" % args)
-    loop()
+    cosocket.loop()