Porting to netlib proceeds apace.

This commit is contained in:
Aldo Cortesi 2012-06-19 13:23:07 +12:00
parent bd99a13f39
commit a700721891
6 changed files with 122 additions and 194 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ MANIFEST
*.swp
/doc
.coverage
netlib

97
libpathod/app.py Normal file
View File

@ -0,0 +1,97 @@
class APILog(tornado.web.RequestHandler):
def get(self):
self.write(
dict(
d = self.application.get_log()
)
)
class APILogClear(tornado.web.RequestHandler):
def post(self):
self.application.clear_log()
self.write("OK")
class APIShutdown(tornado.web.RequestHandler):
def post(self):
tornado.ioloop.IOLoop.instance().stop()
self.write("OK")
class APIInfo(tornado.web.RequestHandler):
def get(self):
self.write(
dict(
version = version.IVERSION
)
)
class _Page(tornado.web.RequestHandler):
def render(self, name, **kwargs):
tornado.web.RequestHandler.render(self, name + ".html", **kwargs)
class Index(_Page):
name = "index"
section = "main"
def get(self):
self.render(self.name, section=self.section, spec="")
class Preview(_Page):
name = "preview"
section = "main"
SANITY = 1024*1024
def get(self):
spec = self.get_argument("spec", None)
args = dict(
spec = spec,
section = self.section,
syntaxerror = None,
error = None
)
try:
r = rparse.parse(self.application.settings, spec)
except rparse.ParseException, v:
args["syntaxerror"] = str(v)
args["marked"] = v.marked()
return self.render(self.name, **args)
if r.length() > self.SANITY:
error = "Refusing to preview a response of %s bytes. This is for your own good."%r.length()
args["error"] = error
else:
d = utils.DummyRequest()
r.serve(d)
args["output"] = d.getvalue()
self.render(self.name, **args)
class Help(_Page):
name = "help"
section = "help"
def get(self):
self.render(self.name, section=self.section)
class Log(_Page):
name = "log"
section = "log"
def get(self):
self.render(self.name, section=self.section, log=self.application.log)
class OneLog(_Page):
name = "onelog"
section = "log"
def get(self, lid):
l = pprint.pformat(self.application.log_by_id(int(lid)))
self.render(self.name, section=self.section, alog=l, lid=lid)
class ClearLog(_Page):
def post(self):
self.application.clear_logs()
self.redirect("/log")

View File

@ -1,182 +0,0 @@
import select, socket, threading, traceback, sys
from OpenSSL import SSL
class NetLibError(Exception): pass
class FileLike:
def __init__(self, o):
self.o = o
def __getattr__(self, attr):
return getattr(self.o, attr)
def flush(self):
pass
def read(self, length):
result = ''
while len(result) < length:
try:
data = self.o.read(length)
except SSL.ZeroReturnError:
break
if not data:
break
result += data
return result
def write(self, v):
self.o.sendall(v)
def readline(self, size = None):
result = ''
bytes_read = 0
while True:
if size is not None and bytes_read >= size:
break
ch = self.read(1)
bytes_read += 1
if not ch:
break
else:
result += ch
if ch == '\n':
break
return result
class TCPClient:
def __init__(self, ssl, host, port, clientcert):
self.ssl, self.host, self.port, self.clientcert = ssl, host, port, clientcert
self.connection, self.rfile, self.wfile = None, None, None
self.cert = None
self.connect()
def connect(self):
try:
addr = socket.gethostbyname(self.host)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if self.ssl:
context = SSL.Context(SSL.SSLv23_METHOD)
if self.clientcert:
context.use_certificate_file(self.clientcert)
server = SSL.Connection(context, server)
server.connect((addr, self.port))
if self.ssl:
self.cert = server.get_peer_certificate()
self.rfile, self.wfile = FileLike(server), FileLike(server)
else:
self.rfile, self.wfile = server.makefile('rb'), server.makefile('wb')
except socket.error, err:
raise NetLibError('Error connecting to "%s": %s' % (self.host, err))
self.connection = server
class BaseHandler:
rbufsize = -1
wbufsize = 0
def __init__(self, connection, client_address, server):
self.connection = connection
self.rfile = self.connection.makefile('rb', self.rbufsize)
self.wfile = self.connection.makefile('wb', self.wbufsize)
self.client_address = client_address
self.server = server
self.handle()
self.finish()
def convert_to_ssl(self, cert, key):
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.use_privatekey_file(key)
ctx.use_certificate_file(cert)
self.connection = SSL.Connection(ctx, self.connection)
self.connection.set_accept_state()
self.rfile = FileLike(self.connection)
self.wfile = FileLike(self.connection)
def finish(self):
try:
if not getattr(self.wfile, "closed", False):
self.wfile.flush()
self.connection.close()
self.wfile.close()
self.rfile.close()
except IOError: # pragma: no cover
pass
def handle(self): # pragma: no cover
raise NotImplementedError
class TCPServer:
request_queue_size = 20
def __init__(self, server_address):
self.server_address = server_address
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname()
self.socket.listen(self.request_queue_size)
self.port = self.socket.getsockname()[1]
def request_thread(self, request, client_address):
try:
self.handle_connection(request, client_address)
request.close()
except:
self.handle_error(request, client_address)
request.close()
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
r, w, e = select.select([self.socket], [], [], poll_interval)
if self.socket in r:
try:
request, client_address = self.socket.accept()
except socket.error:
return
try:
t = threading.Thread(
target = self.request_thread,
args = (request, client_address)
)
t.setDaemon(1)
t.start()
except:
self.handle_error(request, client_address)
request.close()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
def shutdown(self):
self.__shutdown_request = True
self.__is_shut_down.wait()
self.handle_shutdown()
def handle_error(self, request, client_address, fp=sys.stderr):
"""
Called when handle_connection raises an exception.
"""
print >> fp, '-'*40
print >> fp, "Error processing of request from %s:%s"%client_address
print >> fp, traceback.format_exc()
print >> fp, '-'*40
def handle_connection(self, request, client_address): # pragma: no cover
"""
Called after client connection.
"""
raise NotImplementedError
def handle_shutdown(self):
"""
Called after server shutdown.
"""
pass

View File

@ -1,14 +1,25 @@
import netlib
from netlib import tcp, protocol, odict
class PathodHandler(netlib.BaseHandler):
class PathodHandler(tcp.BaseHandler):
def handle(self):
print "Here"
line = self.rfile.readline()
if line == "\r\n" or line == "\n": # Possible leftover from previous message
line = self.rfile.readline()
if line == "":
return None
method, path, httpversion = protocol.parse_init_http(line)
headers = odict.ODictCaseless(protocol.read_headers(self.rfile))
content = protocol.read_http_body_request(
self.rfile, self.wfile, headers, httpversion, None
)
print method, path, httpversion
#return flow.Request(client_conn, httpversion, host, port, "http", method, path, headers, content)
class PathodServer(netlib.TCPServer):
class Pathod(tcp.TCPServer):
def __init__(self, addr):
netlib.TCPServer.__init__(self, addr)
tcp.TCPServer.__init__(self, addr)
def handle_connection(self, request, client_address):
PathodHandler(request, client_address, self)

View File

@ -7,7 +7,8 @@ IFACE = "127.0.0.1"
class Daemon:
def __init__(self, staticdir=None, anchors=(), ssl=None):
self.app = pathod.make_app(staticdir=staticdir, anchors=anchors)
#self.app = pathod.make_app(staticdir=staticdir, anchors=anchors)
self.app = None
self.q = Queue.Queue()
self.thread = PaThread(self.q, self.app, ssl)
self.thread.start()
@ -19,7 +20,7 @@ class Daemon:
return resp.json
def shutdown(self):
requests.post("%s/api/shutdown"%self.urlbase, verify=False)
self.thread.server.shutdown()
self.thread.join()
@ -37,6 +38,7 @@ class PaThread(threading.Thread):
)
else:
ssloptions = self.ssl
self.server, self.port = pathod.make_server(self.app, 0, IFACE, ssloptions)
self.q.put(self.port)
pathod.run(self.server)
self.server = pathod.Pathod((IFACE, 0))
#self.server, self.port = pathod.make_server(self.app, 0, IFACE, ssloptions)
self.q.put(self.server.port)
self.server.serve_forever()

View File

@ -46,4 +46,3 @@ class TestDaemon:
def test_info(self):
assert tuple(self.d.info()["version"]) == version.IVERSION