import http.cookies import logging import json import collections from . import httpd from . import sse from . import fire, get_context from . import sessions # Logging logger = logging.getLogger(__name__) # bring some external handlers into this module's scope # (now you can just import eca.http and have access to all standard handlers) StaticContent = httpd.StaticContent SessionManager = sessions.SessionManager class Cookies(httpd.Filter): """Filter to read cookies from request.""" def handle(self): # process available cookies cookies = http.cookies.SimpleCookie() if 'cookie' in self.request.headers: cookies.load(self.request.headers['cookie']) # set cookies on request self.request.cookies = cookies class HelloWorld(httpd.Handler): """The mandatory Hello World example.""" def handle_GET(self): self.request.send_response(200) self.request.send_header('content-type','text/html; charset=utf-8') self.request.end_headers() output = "

Hello world!

eca-session: {}

" try: if not hasattr(self.request, 'cookies'): raise KeyError() cookie = self.request.cookies['eca-session'].value except KeyError: cookie = 'no cookie'; self.request.wfile.write(output.format(cookie).encode('utf-8')) def Redirect(realpath): """ Factory for redirection handlers. """ class RedirectHandler(httpd.Handler): def handle_GET(self): location = None # check for absolute paths if realpath.startswith("http://") or realpath.startswith('https://'): location = realpath else: host = self.request.server.server_address[0] if self.request.server.server_address[1] != 80: host += ":{}".format(self.request.server.server_address[1]) if 'host' in self.request.headers: host = self.request.headers['host'] location = "http://{}{}".format(host, realpath) self.request.send_response(302) self.request.send_header('content-type','text/html; charset=utf-8') self.request.send_header('location',location) self.request.end_headers() output = "

Redirect to {0}

" self.request.wfile.write(output.format(location).encode('utf-8')) return RedirectHandler def GenerateEvent(name): """ This function returns a handler class that creates the named event based on the posted JSON data. """ class EventGenerationHandler(httpd.Handler): def handle_POST(self): # handle weirdness if 'content-length' not in self.request.headers: self.request.send_error(411) return # read content-length header length = int(self.request.headers['content-length']) # grab data data = self.request.rfile.read(length) try: structured = json.loads(data.decode('utf-8')) except ValueError as e: self.request.send_error(400, "Bad request: "+str(e)) return if not isinstance(structured, collections.abc.Mapping): self.request.send_error(400, "Bad request: expect a JSON object") return try: fire(name, structured) except NotImplementedError: logger.warn("Event generated by HTTP request without active session. Do you have a SessionManager configured?") self.request.send_error(500, "No current context available.") return self.request.send_response(202) self.request.send_header('content-type', 'text/plain; charset=utf-8') self.request.send_header('content-length', 0) self.request.end_headers() return EventGenerationHandler class EventStream(sse.ServerSideEvents): def go_subscribe(self): def receiver(name, event): self.send_event(event.data.get('json'), event.name, event.data.get('id')) self.receiver = receiver context = get_context() context.channel.subscribe(self.receiver, 'emit') def go_unsubscribe(self): context = get_context() context.channel.unsubscribe(self.receiver, 'emit')