mirror of
https://github.com/progval/Limnoria.git
synced 2025-04-25 20:41:18 -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 cgi
|
||||
import socket
|
||||
import sys
|
||||
from threading import Thread
|
||||
from wsgiref.handlers import BaseHandler, SimpleHandler
|
||||
from wsgiref.simple_server import WSGIRequestHandler
|
||||
|
||||
import supybot.log as log
|
||||
import supybot.conf as conf
|
||||
@ -181,6 +184,22 @@ class SupyHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
except KeyError:
|
||||
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
|
||||
for name in ('send_response', 'send_header', 'end_headers', 'rfile',
|
||||
'wfile', 'headers'):
|
||||
@ -189,6 +208,22 @@ class SupyHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
path = self.path
|
||||
if not callback.fullpath:
|
||||
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,
|
||||
*args, **kwargs)
|
||||
|
||||
@ -196,19 +231,7 @@ class SupyHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
self.do_X('doGet')
|
||||
|
||||
def do_POST(self):
|
||||
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)
|
||||
self.do_X('doPost', form=form)
|
||||
self.do_X('doPost')
|
||||
|
||||
def do_HEAD(self):
|
||||
self.do_X('doHead')
|
||||
@ -312,7 +335,7 @@ class SupyIndex(SupyHTTPServerCallback):
|
||||
plugins = [
|
||||
(name, cb)
|
||||
for (name, cb) in handler.server.callbacks.items()
|
||||
if cb.public]
|
||||
if getattr(cb, 'public', True)]
|
||||
if plugins == []:
|
||||
plugins = _('No plugins available.')
|
||||
else:
|
||||
@ -417,6 +440,9 @@ class RealSupyHTTPServer(HTTPServer):
|
||||
timeout = 0.5
|
||||
running = False
|
||||
|
||||
|
||||
base_environ = {}
|
||||
|
||||
def __init__(self, address, protocol, callback):
|
||||
self.protocol = protocol
|
||||
if protocol == 4:
|
||||
@ -441,10 +467,11 @@ class RealSupyHTTPServer(HTTPServer):
|
||||
'reloaded the plugin and it didn\'t properly unhook. '
|
||||
'Forced unhook.') % subdir)
|
||||
self.callbacks[subdir] = callback
|
||||
callback.doHook(self, subdir)
|
||||
if hasattr(callback, 'doHook'):
|
||||
callback.doHook(self, subdir)
|
||||
def unhook(self, subdir):
|
||||
callback = self.callbacks.pop(subdir, None)
|
||||
if callback:
|
||||
if callback and hasattr(callback, 'doUnhook'):
|
||||
callback.doUnhook(self)
|
||||
return callback
|
||||
|
||||
@ -452,6 +479,8 @@ class RealSupyHTTPServer(HTTPServer):
|
||||
return 'server at %s %i' % self.server_address[0:2]
|
||||
|
||||
class TestSupyHTTPServer(RealSupyHTTPServer):
|
||||
base_environ = {}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.callbacks = {}
|
||||
self.server_address = ("0.0.0.0", 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user