/circuits/web/servers.py
https://bitbucket.org/prologic/circuits/ · Python · 178 lines · 159 code · 9 blank · 10 comment · 0 complexity · b3e6dc5f24f60afef70631c60f3b05dc MD5 · raw file
- # Module: server
- # Date: 6th November 2008
- # Author: James Mills, prologic at shortcircuit dot net dot au
- """Web Servers
- This module implements the several Web Server components.
- """
- from sys import stderr
- from circuits import io
- from circuits.net.events import close, read, write
- from circuits.net.sockets import TCPServer, UNIXServer
- from circuits.core import handler, BaseComponent, Timer
- from .http import HTTP
- from .events import terminate
- from .dispatchers import Dispatcher
- class BaseServer(BaseComponent):
- """Create a Base Web Server
- Create a Base Web Server (HTTP) bound to the IP Address / Port or
- UNIX Socket specified by the 'bind' parameter.
- :ivar server: Reference to underlying Server Component
- :param bind: IP Address / Port or UNIX Socket to bind to.
- :type bind: Instance of int, list, tuple or str
- The 'bind' parameter is quite flexible with what valid values it accepts.
- If an int is passed, a TCPServer will be created. The Server will be
- bound to the Port given by the 'bind' argument and the bound interface
- will default (normally to "0.0.0.0").
- If a list or tuple is passed, a TCPServer will be created. The
- Server will be bound to the Port given by the 2nd item in the 'bind'
- argument and the bound interface will be the 1st item.
- If a str is passed and it contains the ':' character, this is
- assumed to be a request to bind to an IP Address / Port. A TCpServer
- will thus be created and the IP Address and Port will be determined
- by splitting the string given by the 'bind' argument.
- Otherwise if a str is passed and it does not contain the ':'
- character, a file path is assumed and a UNIXServer is created and
- bound to the file given by the 'bind' argument.
- """
- channel = "web"
- def __init__(self, bind, encoding="utf-8", secure=False, certfile=None,
- channel=channel):
- "x.__init__(...) initializes x; see x.__class__.__doc__ for signature"
- super(BaseServer, self).__init__(channel=channel)
- if isinstance(bind, (int, list, tuple,)):
- SocketType = TCPServer
- else:
- SocketType = TCPServer if ":" in bind else UNIXServer
- self.server = SocketType(
- bind,
- secure=secure,
- certfile=certfile,
- channel=channel
- ).register(self)
- self.http = HTTP(
- self, encoding=encoding, channel=channel
- ).register(self)
- @property
- def host(self):
- if hasattr(self, "server"):
- return self.server.host
- @property
- def port(self):
- if hasattr(self, "server"):
- return self.server.port
- @property
- def secure(self):
- if hasattr(self, "server"):
- return self.server.secure
- @handler("connect")
- def _on_connect(self, *args, **kwargs):
- """Dummy Event Handler for connect"""
- @handler("closed")
- def _on_closed(self, *args, **kwargs):
- """Dummy Event Handler for closed"""
- @handler("signal")
- def _on_signal(self, *args, **kwargs):
- """signal Event Handler"""
- self.fire(close())
- Timer(3, terminate()).register(self)
- @handler("terminate")
- def _on_terminate(self):
- raise SystemExit(0)
- @handler("ready")
- def _on_ready(self, server, bind):
- stderr.write(
- "{0:s} ready! Listening on: {1:s}\n".format(
- self.http.version, self.http.base
- )
- )
- class Server(BaseServer):
- """Create a Web Server
- Create a Web Server (HTTP) complete with the default Dispatcher to
- parse requests and posted form data dispatching to appropriate
- Controller(s).
- See: circuits.web.servers.BaseServer
- """
- def __init__(self, bind, **kwargs):
- "x.__init__(...) initializes x; see x.__class__.__doc__ for signature"
- super(Server, self).__init__(bind, **kwargs)
- Dispatcher(channel=self.channel).register(self.http)
- class FakeSock():
- def getpeername(self):
- return (None, None)
- class StdinServer(BaseComponent):
- channel = "web"
- def __init__(self, encoding="utf-8", channel=channel):
- super(StdinServer, self).__init__(channel=channel)
- self.server = (io.stdin + io.stdout).register(self)
- self.http = HTTP(
- self, encoding=encoding, channel=channel
- ).register(self)
- Dispatcher(channel=self.channel).register(self)
- @property
- def host(self):
- return io.stdin.filename
- @property
- def port(self):
- return 0
- @property
- def secure(self):
- return False
- @handler("read", channel="stdin")
- def read(self, data):
- self.fire(read(FakeSock(), data))
- @handler("write")
- def write(self, sock, data):
- self.fire(write(data))