Refactory in contexts.
This commit is contained in:
parent
588c84f64f
commit
728dee527d
2 changed files with 149 additions and 129 deletions
|
@ -9,142 +9,14 @@
|
||||||
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import urllib2
|
import urllib2
|
||||||
from threading import Thread
|
|
||||||
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
|
|
||||||
|
|
||||||
from pyvows import Vows
|
from pyvows import Vows
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.core.handlers.wsgi import WSGIHandler
|
|
||||||
|
|
||||||
from django_pyvows.assertions import Url, Model, Template
|
from django_pyvows.assertions import Url, Model, Template
|
||||||
|
from django_pyvows.server import DjangoServer
|
||||||
|
|
||||||
class WSGIRequestHandler(BaseHTTPRequestHandler):
|
|
||||||
"""A request handler that implements WSGI dispatching."""
|
|
||||||
|
|
||||||
@property
|
|
||||||
def server_version(self):
|
|
||||||
return 'pyVowsServer'
|
|
||||||
|
|
||||||
def make_environ(self):
|
|
||||||
if '?' in self.path:
|
|
||||||
path_info, query = self.path.split('?', 1)
|
|
||||||
else:
|
|
||||||
path_info = self.path
|
|
||||||
query = ''
|
|
||||||
|
|
||||||
environ = {
|
|
||||||
'wsgi.version': (1, 0),
|
|
||||||
'wsgi.url_scheme': 'http',
|
|
||||||
'wsgi.input': self.rfile,
|
|
||||||
'wsgi.errors': sys.stderr,
|
|
||||||
'wsgi.multithread': False,
|
|
||||||
'wsgi.multiprocess': False,
|
|
||||||
'wsgi.run_once': False,
|
|
||||||
'SERVER_SOFTWARE': self.server_version,
|
|
||||||
'REQUEST_METHOD': self.command,
|
|
||||||
'SCRIPT_NAME': '',
|
|
||||||
'PATH_INFO': urllib2.unquote(path_info),
|
|
||||||
'QUERY_STRING': query,
|
|
||||||
'CONTENT_TYPE': self.headers.get('Content-Type', ''),
|
|
||||||
'CONTENT_LENGTH': self.headers.get('Content-Length', ''),
|
|
||||||
'REMOTE_ADDR': self.client_address[0],
|
|
||||||
'REMOTE_PORT': self.client_address[1],
|
|
||||||
'SERVER_NAME': self.server.server_address[0],
|
|
||||||
'SERVER_PORT': str(self.server.server_address[1]),
|
|
||||||
'SERVER_PROTOCOL': self.request_version
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value in self.headers.items():
|
|
||||||
key = 'HTTP_' + key.upper().replace('-', '_')
|
|
||||||
if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
|
|
||||||
environ[key] = value
|
|
||||||
|
|
||||||
return environ
|
|
||||||
|
|
||||||
def run_wsgi(self):
|
|
||||||
app = self.server.app
|
|
||||||
environ = self.make_environ()
|
|
||||||
headers_set = []
|
|
||||||
headers_sent = []
|
|
||||||
|
|
||||||
def write(data):
|
|
||||||
assert headers_set, 'write() before start_response'
|
|
||||||
if not headers_sent:
|
|
||||||
status, response_headers = headers_sent[:] = headers_set
|
|
||||||
code, msg = status.split(None, 1)
|
|
||||||
self.send_response(int(code), msg)
|
|
||||||
header_keys = set()
|
|
||||||
for key, value in response_headers:
|
|
||||||
self.send_header(key, value)
|
|
||||||
key = key.lower()
|
|
||||||
header_keys.add(key)
|
|
||||||
if 'content-length' not in header_keys:
|
|
||||||
self.close_connection = True
|
|
||||||
self.send_header('Connection', 'close')
|
|
||||||
if 'server' not in header_keys:
|
|
||||||
self.send_header('Server', self.version_string())
|
|
||||||
if 'date' not in header_keys:
|
|
||||||
self.send_header('Date', self.date_time_string())
|
|
||||||
self.end_headers()
|
|
||||||
|
|
||||||
assert type(data) is str, 'applications must write bytes'
|
|
||||||
self.wfile.write(data)
|
|
||||||
self.wfile.flush()
|
|
||||||
|
|
||||||
def start_response(status, response_headers, exc_info=None):
|
|
||||||
if exc_info:
|
|
||||||
try:
|
|
||||||
if headers_sent:
|
|
||||||
raise exc_info[0], exc_info[1], exc_info[2]
|
|
||||||
finally:
|
|
||||||
exc_info = None
|
|
||||||
elif headers_set:
|
|
||||||
raise AssertionError('Headers already set')
|
|
||||||
headers_set[:] = [status, response_headers]
|
|
||||||
return write
|
|
||||||
|
|
||||||
application_iter = app(environ, start_response)
|
|
||||||
try:
|
|
||||||
for data in application_iter:
|
|
||||||
write(data)
|
|
||||||
# make sure the headers are sent
|
|
||||||
if not headers_sent:
|
|
||||||
write('')
|
|
||||||
finally:
|
|
||||||
if hasattr(application_iter, 'close'):
|
|
||||||
application_iter.close()
|
|
||||||
application_iter = None
|
|
||||||
|
|
||||||
def handle_one_request(self):
|
|
||||||
self.raw_requestline = self.rfile.readline()
|
|
||||||
if self.parse_request():
|
|
||||||
return self.run_wsgi()
|
|
||||||
|
|
||||||
def log_request(self, *args, **kwargs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def log_error(self, *args):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def log_message(self, *args):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class DjangoServer(HTTPServer, object):
|
|
||||||
|
|
||||||
def __init__(self, host, port):
|
|
||||||
HTTPServer.__init__(self, (host, int(port)), WSGIRequestHandler)
|
|
||||||
self.app = WSGIHandler()
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
self.server_activate()
|
|
||||||
def make_response():
|
|
||||||
while True:
|
|
||||||
self.handle_request()
|
|
||||||
self.thr = Thread(target=make_response)
|
|
||||||
self.thr.daemon = True
|
|
||||||
self.thr.start()
|
|
||||||
|
|
||||||
class DjangoContext(Vows.Context):
|
class DjangoContext(Vows.Context):
|
||||||
|
|
||||||
|
|
148
django_pyvows/server.py
Normal file
148
django_pyvows/server.py
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# django-pyvows extensions
|
||||||
|
# https://github.com/rafaelcaricio/django-pyvows
|
||||||
|
|
||||||
|
# Licensed under the MIT license:
|
||||||
|
# http://www.opensource.org/licenses/mit-license
|
||||||
|
# Copyright (c) 2011 Rafael Caricio rafael@caricio.com
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import urllib2
|
||||||
|
from threading import Thread
|
||||||
|
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
|
||||||
|
|
||||||
|
from pyvows import Vows
|
||||||
|
from django.http import HttpRequest
|
||||||
|
from django.core.handlers.wsgi import WSGIHandler
|
||||||
|
|
||||||
|
from django_pyvows.assertions import Url, Model, Template
|
||||||
|
|
||||||
|
class WSGIRequestHandler(BaseHTTPRequestHandler):
|
||||||
|
"""A request handler that implements WSGI dispatching."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def server_version(self):
|
||||||
|
return 'pyVowsServer'
|
||||||
|
|
||||||
|
def make_environ(self):
|
||||||
|
if '?' in self.path:
|
||||||
|
path_info, query = self.path.split('?', 1)
|
||||||
|
else:
|
||||||
|
path_info = self.path
|
||||||
|
query = ''
|
||||||
|
|
||||||
|
environ = {
|
||||||
|
'wsgi.version': (1, 0),
|
||||||
|
'wsgi.url_scheme': 'http',
|
||||||
|
'wsgi.input': self.rfile,
|
||||||
|
'wsgi.errors': sys.stderr,
|
||||||
|
'wsgi.multithread': False,
|
||||||
|
'wsgi.multiprocess': False,
|
||||||
|
'wsgi.run_once': False,
|
||||||
|
'SERVER_SOFTWARE': self.server_version,
|
||||||
|
'REQUEST_METHOD': self.command,
|
||||||
|
'SCRIPT_NAME': '',
|
||||||
|
'PATH_INFO': urllib2.unquote(path_info),
|
||||||
|
'QUERY_STRING': query,
|
||||||
|
'CONTENT_TYPE': self.headers.get('Content-Type', ''),
|
||||||
|
'CONTENT_LENGTH': self.headers.get('Content-Length', ''),
|
||||||
|
'REMOTE_ADDR': self.client_address[0],
|
||||||
|
'REMOTE_PORT': self.client_address[1],
|
||||||
|
'SERVER_NAME': self.server.server_address[0],
|
||||||
|
'SERVER_PORT': str(self.server.server_address[1]),
|
||||||
|
'SERVER_PROTOCOL': self.request_version
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value in self.headers.items():
|
||||||
|
key = 'HTTP_' + key.upper().replace('-', '_')
|
||||||
|
if key not in ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
|
||||||
|
environ[key] = value
|
||||||
|
|
||||||
|
return environ
|
||||||
|
|
||||||
|
def run_wsgi(self):
|
||||||
|
app = self.server.app
|
||||||
|
environ = self.make_environ()
|
||||||
|
headers_set = []
|
||||||
|
headers_sent = []
|
||||||
|
|
||||||
|
def write(data):
|
||||||
|
assert headers_set, 'write() before start_response'
|
||||||
|
if not headers_sent:
|
||||||
|
status, response_headers = headers_sent[:] = headers_set
|
||||||
|
code, msg = status.split(None, 1)
|
||||||
|
self.send_response(int(code), msg)
|
||||||
|
header_keys = set()
|
||||||
|
for key, value in response_headers:
|
||||||
|
self.send_header(key, value)
|
||||||
|
key = key.lower()
|
||||||
|
header_keys.add(key)
|
||||||
|
if 'content-length' not in header_keys:
|
||||||
|
self.close_connection = True
|
||||||
|
self.send_header('Connection', 'close')
|
||||||
|
if 'server' not in header_keys:
|
||||||
|
self.send_header('Server', self.version_string())
|
||||||
|
if 'date' not in header_keys:
|
||||||
|
self.send_header('Date', self.date_time_string())
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
assert type(data) is str, 'applications must write bytes'
|
||||||
|
self.wfile.write(data)
|
||||||
|
self.wfile.flush()
|
||||||
|
|
||||||
|
def start_response(status, response_headers, exc_info=None):
|
||||||
|
if exc_info:
|
||||||
|
try:
|
||||||
|
if headers_sent:
|
||||||
|
raise exc_info[0], exc_info[1], exc_info[2]
|
||||||
|
finally:
|
||||||
|
exc_info = None
|
||||||
|
elif headers_set:
|
||||||
|
raise AssertionError('Headers already set')
|
||||||
|
headers_set[:] = [status, response_headers]
|
||||||
|
return write
|
||||||
|
|
||||||
|
application_iter = app(environ, start_response)
|
||||||
|
try:
|
||||||
|
for data in application_iter:
|
||||||
|
write(data)
|
||||||
|
# make sure the headers are sent
|
||||||
|
if not headers_sent:
|
||||||
|
write('')
|
||||||
|
finally:
|
||||||
|
if hasattr(application_iter, 'close'):
|
||||||
|
application_iter.close()
|
||||||
|
application_iter = None
|
||||||
|
|
||||||
|
def handle_one_request(self):
|
||||||
|
self.raw_requestline = self.rfile.readline()
|
||||||
|
if self.parse_request():
|
||||||
|
return self.run_wsgi()
|
||||||
|
|
||||||
|
def log_request(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def log_error(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def log_message(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DjangoServer(HTTPServer, object):
|
||||||
|
|
||||||
|
def __init__(self, host, port):
|
||||||
|
HTTPServer.__init__(self, (host, int(port)), WSGIRequestHandler)
|
||||||
|
self.app = WSGIHandler()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.server_activate()
|
||||||
|
def make_response():
|
||||||
|
while True:
|
||||||
|
self.handle_request()
|
||||||
|
self.thr = Thread(target=make_response)
|
||||||
|
self.thr.daemon = True
|
||||||
|
self.thr.start()
|
||||||
|
|
Reference in a new issue