PageRenderTime 98ms CodeModel.GetById 65ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/circuits/web/servers.py

https://bitbucket.org/prologic/circuits/
Python | 178 lines | 159 code | 9 blank | 10 comment | 0 complexity | b3e6dc5f24f60afef70631c60f3b05dc MD5 | raw file
  1# Module:   server
  2# Date:     6th November 2008
  3# Author:   James Mills, prologic at shortcircuit dot net dot au
  4
  5
  6"""Web Servers
  7
  8This module implements the several Web Server components.
  9"""
 10
 11
 12from sys import stderr
 13
 14
 15from circuits import io
 16from circuits.net.events import close, read, write
 17from circuits.net.sockets import TCPServer, UNIXServer
 18from circuits.core import handler, BaseComponent, Timer
 19
 20from .http import HTTP
 21from .events import terminate
 22from .dispatchers import Dispatcher
 23
 24
 25class BaseServer(BaseComponent):
 26    """Create a Base Web Server
 27
 28    Create a Base Web Server (HTTP) bound to the IP Address / Port or
 29    UNIX Socket specified by the 'bind' parameter.
 30
 31    :ivar server: Reference to underlying Server Component
 32
 33    :param bind: IP Address / Port or UNIX Socket to bind to.
 34    :type bind: Instance of int, list, tuple or str
 35
 36    The 'bind' parameter is quite flexible with what valid values it accepts.
 37
 38    If an int is passed, a TCPServer will be created. The Server will be
 39    bound to the Port given by the 'bind' argument and the bound interface
 40    will default (normally to  "0.0.0.0").
 41
 42    If a list or tuple is passed, a TCPServer will be created. The
 43    Server will be bound to the Port given by the 2nd item in the 'bind'
 44    argument and the bound interface will be the 1st item.
 45
 46    If a str is passed and it contains the ':' character, this is
 47    assumed to be a request to bind to an IP Address / Port. A TCpServer
 48    will thus be created and the IP Address and Port will be determined
 49    by splitting the string given by the 'bind' argument.
 50
 51    Otherwise if a str is passed and it does not contain the ':'
 52    character, a file path is assumed and a UNIXServer is created and
 53    bound to the file given by the 'bind' argument.
 54    """
 55
 56    channel = "web"
 57
 58    def __init__(self, bind, encoding="utf-8", secure=False, certfile=None,
 59                 channel=channel):
 60        "x.__init__(...) initializes x; see x.__class__.__doc__ for signature"
 61
 62        super(BaseServer, self).__init__(channel=channel)
 63
 64        if isinstance(bind, (int, list, tuple,)):
 65            SocketType = TCPServer
 66        else:
 67            SocketType = TCPServer if ":" in bind else UNIXServer
 68
 69        self.server = SocketType(
 70            bind,
 71            secure=secure,
 72            certfile=certfile,
 73            channel=channel
 74        ).register(self)
 75
 76        self.http = HTTP(
 77            self, encoding=encoding, channel=channel
 78        ).register(self)
 79
 80    @property
 81    def host(self):
 82        if hasattr(self, "server"):
 83            return self.server.host
 84
 85    @property
 86    def port(self):
 87        if hasattr(self, "server"):
 88            return self.server.port
 89
 90    @property
 91    def secure(self):
 92        if hasattr(self, "server"):
 93            return self.server.secure
 94
 95    @handler("connect")
 96    def _on_connect(self, *args, **kwargs):
 97        """Dummy Event Handler for connect"""
 98
 99    @handler("closed")
100    def _on_closed(self, *args, **kwargs):
101        """Dummy Event Handler for closed"""
102
103    @handler("signal")
104    def _on_signal(self, *args, **kwargs):
105        """signal Event Handler"""
106
107        self.fire(close())
108        Timer(3, terminate()).register(self)
109
110    @handler("terminate")
111    def _on_terminate(self):
112        raise SystemExit(0)
113
114    @handler("ready")
115    def _on_ready(self, server, bind):
116        stderr.write(
117            "{0:s} ready! Listening on: {1:s}\n".format(
118                self.http.version, self.http.base
119            )
120        )
121
122
123class Server(BaseServer):
124    """Create a Web Server
125
126    Create a Web Server (HTTP) complete with the default Dispatcher to
127    parse requests and posted form data dispatching to appropriate
128    Controller(s).
129
130    See: circuits.web.servers.BaseServer
131    """
132
133    def __init__(self, bind, **kwargs):
134        "x.__init__(...) initializes x; see x.__class__.__doc__ for signature"
135
136        super(Server, self).__init__(bind, **kwargs)
137
138        Dispatcher(channel=self.channel).register(self.http)
139
140
141class FakeSock():
142    def getpeername(self):
143        return (None, None)
144
145
146class StdinServer(BaseComponent):
147
148    channel = "web"
149
150    def __init__(self, encoding="utf-8", channel=channel):
151        super(StdinServer, self).__init__(channel=channel)
152
153        self.server = (io.stdin + io.stdout).register(self)
154        self.http = HTTP(
155            self, encoding=encoding, channel=channel
156        ).register(self)
157
158        Dispatcher(channel=self.channel).register(self)
159
160    @property
161    def host(self):
162        return io.stdin.filename
163
164    @property
165    def port(self):
166        return 0
167
168    @property
169    def secure(self):
170        return False
171
172    @handler("read", channel="stdin")
173    def read(self, data):
174        self.fire(read(FakeSock(), data))
175
176    @handler("write")
177    def write(self, sock, data):
178        self.fire(write(data))