mirror of
https://github.com/progval/Limnoria.git
synced 2025-04-26 04:51:06 -05:00
httpserver: Add support for WSGI apps
For example, with Flask: ``` from supybot import utils, plugins, ircutils, callbacks, httpserver from supybot.commands import * from supybot.i18n import PluginInternationalization _ = PluginInternationalization('TestWsgi') from flask import Flask, request, render_template app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>" @app.route('/login/', methods=['POST', 'GET']) def login(): error = None if request.method == 'POST': if request.form['username'] == 'root' \ and request.form['password'] == 'admin': return 'Hello root' else: return 'Error: Invalid username/password' # the code below is executed if the request method # was GET or the credentials were invalid return ''' <form method="POST" action="."> <label for="username">Username: <input name="username" id="username" /> </label> <label for="password">Password: <input name="password" id="password" type="password" /> </label> <input type="Submit" /> </form> ''' class TestWsgi(callbacks.Plugin): """Test Flask""" def __init__(self, irc): self.__parent = super(TestWsgi, self) callbacks.Plugin.__init__(self, irc) httpserver.hook('testwsgi', app) def die(self): self.__parent.die() httpserver.unhook('testwsgi') Class = TestWsgi ```
This commit is contained in:
parent
4da1291876
commit
ffb2e8488f
@ -34,7 +34,10 @@ An embedded and centralized HTTP server for Supybot's plugins.
|
|||||||
import os
|
import os
|
||||||
import cgi
|
import cgi
|
||||||
import socket
|
import socket
|
||||||
|
import sys
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
from wsgiref.handlers import BaseHandler, SimpleHandler
|
||||||
|
from wsgiref.simple_server import WSGIRequestHandler
|
||||||
|
|
||||||
import supybot.log as log
|
import supybot.log as log
|
||||||
import supybot.conf as conf
|
import supybot.conf as conf
|
||||||
@ -181,6 +184,22 @@ class SupyHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
callback = Supy404()
|
callback = Supy404()
|
||||||
|
|
||||||
|
if not isinstance(callback, SupyHTTPServerCallback):
|
||||||
|
# WSGI-based callback
|
||||||
|
environ = WSGIRequestHandler.get_environ(self)
|
||||||
|
environ.update({
|
||||||
|
'SERVER_NAME': '0.0.0.0', # TODO
|
||||||
|
'SERVER_PORT': '80', # TODO
|
||||||
|
'PATH_INFO': '/' + environ['PATH_INFO'].split('/', 2)[2]
|
||||||
|
})
|
||||||
|
SimpleHandler(
|
||||||
|
stdin=self.rfile, stdout=self.wfile, stderr=sys.stderr, environ=environ,
|
||||||
|
multithread=False
|
||||||
|
).run(callback)
|
||||||
|
return
|
||||||
|
|
||||||
|
# BaseHTTPRequestHandler-based callback
|
||||||
|
|
||||||
# Some shortcuts
|
# Some shortcuts
|
||||||
for name in ('send_response', 'send_header', 'end_headers', 'rfile',
|
for name in ('send_response', 'send_header', 'end_headers', 'rfile',
|
||||||
'wfile', 'headers'):
|
'wfile', 'headers'):
|
||||||
@ -189,6 +208,22 @@ class SupyHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||||||
path = self.path
|
path = self.path
|
||||||
if not callback.fullpath:
|
if not callback.fullpath:
|
||||||
path = '/' + path.split('/', 2)[-1]
|
path = '/' + path.split('/', 2)[-1]
|
||||||
|
|
||||||
|
if callback == 'doPost':
|
||||||
|
if 'Content-Type' not in self.headers:
|
||||||
|
self.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||||
|
if self.headers['Content-Type'] == 'application/x-www-form-urlencoded':
|
||||||
|
form = cgi.FieldStorage(
|
||||||
|
fp=self.rfile,
|
||||||
|
headers=self.headers,
|
||||||
|
environ={'REQUEST_METHOD':'POST',
|
||||||
|
'CONTENT_TYPE':self.headers['Content-Type'],
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
content_length = int(self.headers.get('Content-Length', '0'))
|
||||||
|
form = self.rfile.read(content_length)
|
||||||
|
kwargs['form'] = form
|
||||||
|
|
||||||
getattr(callback, callbackMethod)(self, path,
|
getattr(callback, callbackMethod)(self, path,
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
|
|
||||||
@ -196,19 +231,7 @@ class SupyHTTPRequestHandler(BaseHTTPRequestHandler):
|
|||||||
self.do_X('doGet')
|
self.do_X('doGet')
|
||||||
|
|
||||||
def do_POST(self):
|
def do_POST(self):
|
||||||
if 'Content-Type' not in self.headers:
|
self.do_X('doPost')
|
||||||
self.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
||||||
if self.headers['Content-Type'] == 'application/x-www-form-urlencoded':
|
|
||||||
form = cgi.FieldStorage(
|
|
||||||
fp=self.rfile,
|
|
||||||
headers=self.headers,
|
|
||||||
environ={'REQUEST_METHOD':'POST',
|
|
||||||
'CONTENT_TYPE':self.headers['Content-Type'],
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
content_length = int(self.headers.get('Content-Length', '0'))
|
|
||||||
form = self.rfile.read(content_length)
|
|
||||||
self.do_X('doPost', form=form)
|
|
||||||
|
|
||||||
def do_HEAD(self):
|
def do_HEAD(self):
|
||||||
self.do_X('doHead')
|
self.do_X('doHead')
|
||||||
@ -312,7 +335,7 @@ class SupyIndex(SupyHTTPServerCallback):
|
|||||||
plugins = [
|
plugins = [
|
||||||
(name, cb)
|
(name, cb)
|
||||||
for (name, cb) in handler.server.callbacks.items()
|
for (name, cb) in handler.server.callbacks.items()
|
||||||
if cb.public]
|
if getattr(cb, 'public', True)]
|
||||||
if plugins == []:
|
if plugins == []:
|
||||||
plugins = _('No plugins available.')
|
plugins = _('No plugins available.')
|
||||||
else:
|
else:
|
||||||
@ -417,6 +440,9 @@ class RealSupyHTTPServer(HTTPServer):
|
|||||||
timeout = 0.5
|
timeout = 0.5
|
||||||
running = False
|
running = False
|
||||||
|
|
||||||
|
|
||||||
|
base_environ = {}
|
||||||
|
|
||||||
def __init__(self, address, protocol, callback):
|
def __init__(self, address, protocol, callback):
|
||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
if protocol == 4:
|
if protocol == 4:
|
||||||
@ -441,10 +467,11 @@ class RealSupyHTTPServer(HTTPServer):
|
|||||||
'reloaded the plugin and it didn\'t properly unhook. '
|
'reloaded the plugin and it didn\'t properly unhook. '
|
||||||
'Forced unhook.') % subdir)
|
'Forced unhook.') % subdir)
|
||||||
self.callbacks[subdir] = callback
|
self.callbacks[subdir] = callback
|
||||||
callback.doHook(self, subdir)
|
if hasattr(callback, 'doHook'):
|
||||||
|
callback.doHook(self, subdir)
|
||||||
def unhook(self, subdir):
|
def unhook(self, subdir):
|
||||||
callback = self.callbacks.pop(subdir, None)
|
callback = self.callbacks.pop(subdir, None)
|
||||||
if callback:
|
if callback and hasattr(callback, 'doUnhook'):
|
||||||
callback.doUnhook(self)
|
callback.doUnhook(self)
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
@ -452,6 +479,8 @@ class RealSupyHTTPServer(HTTPServer):
|
|||||||
return 'server at %s %i' % self.server_address[0:2]
|
return 'server at %s %i' % self.server_address[0:2]
|
||||||
|
|
||||||
class TestSupyHTTPServer(RealSupyHTTPServer):
|
class TestSupyHTTPServer(RealSupyHTTPServer):
|
||||||
|
base_environ = {}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.callbacks = {}
|
self.callbacks = {}
|
||||||
self.server_address = ("0.0.0.0", 0)
|
self.server_address = ("0.0.0.0", 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user