/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. """Web Servers
  5. This module implements the several Web Server components.
  6. """
  7. from sys import stderr
  8. from circuits import io
  9. from circuits.net.events import close, read, write
  10. from circuits.net.sockets import TCPServer, UNIXServer
  11. from circuits.core import handler, BaseComponent, Timer
  12. from .http import HTTP
  13. from .events import terminate
  14. from .dispatchers import Dispatcher
  15. class BaseServer(BaseComponent):
  16. """Create a Base Web Server
  17. Create a Base Web Server (HTTP) bound to the IP Address / Port or
  18. UNIX Socket specified by the 'bind' parameter.
  19. :ivar server: Reference to underlying Server Component
  20. :param bind: IP Address / Port or UNIX Socket to bind to.
  21. :type bind: Instance of int, list, tuple or str
  22. The 'bind' parameter is quite flexible with what valid values it accepts.
  23. If an int is passed, a TCPServer will be created. The Server will be
  24. bound to the Port given by the 'bind' argument and the bound interface
  25. will default (normally to "0.0.0.0").
  26. If a list or tuple is passed, a TCPServer will be created. The
  27. Server will be bound to the Port given by the 2nd item in the 'bind'
  28. argument and the bound interface will be the 1st item.
  29. If a str is passed and it contains the ':' character, this is
  30. assumed to be a request to bind to an IP Address / Port. A TCpServer
  31. will thus be created and the IP Address and Port will be determined
  32. by splitting the string given by the 'bind' argument.
  33. Otherwise if a str is passed and it does not contain the ':'
  34. character, a file path is assumed and a UNIXServer is created and
  35. bound to the file given by the 'bind' argument.
  36. """
  37. channel = "web"
  38. def __init__(self, bind, encoding="utf-8", secure=False, certfile=None,
  39. channel=channel):
  40. "x.__init__(...) initializes x; see x.__class__.__doc__ for signature"
  41. super(BaseServer, self).__init__(channel=channel)
  42. if isinstance(bind, (int, list, tuple,)):
  43. SocketType = TCPServer
  44. else:
  45. SocketType = TCPServer if ":" in bind else UNIXServer
  46. self.server = SocketType(
  47. bind,
  48. secure=secure,
  49. certfile=certfile,
  50. channel=channel
  51. ).register(self)
  52. self.http = HTTP(
  53. self, encoding=encoding, channel=channel
  54. ).register(self)
  55. @property
  56. def host(self):
  57. if hasattr(self, "server"):
  58. return self.server.host
  59. @property
  60. def port(self):
  61. if hasattr(self, "server"):
  62. return self.server.port
  63. @property
  64. def secure(self):
  65. if hasattr(self, "server"):
  66. return self.server.secure
  67. @handler("connect")
  68. def _on_connect(self, *args, **kwargs):
  69. """Dummy Event Handler for connect"""
  70. @handler("closed")
  71. def _on_closed(self, *args, **kwargs):
  72. """Dummy Event Handler for closed"""
  73. @handler("signal")
  74. def _on_signal(self, *args, **kwargs):
  75. """signal Event Handler"""
  76. self.fire(close())
  77. Timer(3, terminate()).register(self)
  78. @handler("terminate")
  79. def _on_terminate(self):
  80. raise SystemExit(0)
  81. @handler("ready")
  82. def _on_ready(self, server, bind):
  83. stderr.write(
  84. "{0:s} ready! Listening on: {1:s}\n".format(
  85. self.http.version, self.http.base
  86. )
  87. )
  88. class Server(BaseServer):
  89. """Create a Web Server
  90. Create a Web Server (HTTP) complete with the default Dispatcher to
  91. parse requests and posted form data dispatching to appropriate
  92. Controller(s).
  93. See: circuits.web.servers.BaseServer
  94. """
  95. def __init__(self, bind, **kwargs):
  96. "x.__init__(...) initializes x; see x.__class__.__doc__ for signature"
  97. super(Server, self).__init__(bind, **kwargs)
  98. Dispatcher(channel=self.channel).register(self.http)
  99. class FakeSock():
  100. def getpeername(self):
  101. return (None, None)
  102. class StdinServer(BaseComponent):
  103. channel = "web"
  104. def __init__(self, encoding="utf-8", channel=channel):
  105. super(StdinServer, self).__init__(channel=channel)
  106. self.server = (io.stdin + io.stdout).register(self)
  107. self.http = HTTP(
  108. self, encoding=encoding, channel=channel
  109. ).register(self)
  110. Dispatcher(channel=self.channel).register(self)
  111. @property
  112. def host(self):
  113. return io.stdin.filename
  114. @property
  115. def port(self):
  116. return 0
  117. @property
  118. def secure(self):
  119. return False
  120. @handler("read", channel="stdin")
  121. def read(self, data):
  122. self.fire(read(FakeSock(), data))
  123. @handler("write")
  124. def write(self, sock, data):
  125. self.fire(write(data))