Issue #1064 new

Patch to add a hook for dropping privileges in wsgiserver and to improve error reporting

Anonymous created an issue

I am using the wsgiserver by itself, and thank you for making the modular. However I wanted to start it as root to bind port 80/443 and then drop privileges. Normally it looks like privileges are dropped in another thread through the CherryPy bus. But if you are just doing it alone, there doesn't seem to be a good place to insert the code.

Also, I ran into issues where errors were swallowed, now it will display something like:

{{{ Traceback (most recent call last): File "/home/andy/hg/polyweb/bin/poly_cherry.py", line 93, in <module> sys.exit(main(sys.argv)) File "/home/andy/hg/polyweb/bin/poly_cherry.py", line 89, in main server.start() File "/home/andy/svn/cherrypy/py2/cherrypy/wsgiserver/init.py", line 1758, in start raise socket.error("No socket could be created: %s" % errors) socket.error: No socket could be created: ["(98, 'Address already in use')"] }}}

Prior to this it would just say "No socket could be created" which obscured the problem.

I hope this is the right place to send a patch, please let me know if not.

{{{ Index: wsgiserver/init.py =================================================================== --- wsgiserver/init.py (revision 2786) +++ wsgiserver/init.py (working copy) @@ -24,6 +24,9 @@

Want SSL support? Just set server.ssl_adapter to an SSLAdapter instance.

+If you want to listen on a privileged port, pass a function to drop privileges +as the 'post_listen_hook' argument. + This won't call the CherryPy engine (application side) at all, only the HTTP server, which is independent from the rest of CherryPy. Don't let the name "CherryPyWSGIServer" throw you; the name merely reflects @@ -1739,23 +1742,26 @@ 0, "", self.bind_addr)]

     self.socket = None
  • msg = "No socket could be created"
  • errors = [] for res in info: af, socktype, proto, canonname, sa = res try: self.bind(af, socktype, proto)
  • except socket.error:
  • except socket.error, e:
  • errors.append(str(e)) if self.socket: self.socket.close() self.socket = None continue break if not self.socket:
  • raise socket.error(msg)
  • raise socket.error("No socket could be created: %s" % errors)

     # Timeout so KeyboardInterrupt can be caught on Win32
     self.socket.settimeout(1)
     self.socket.listen(self.request_queue_size)
    

    + + self.post_listen_hook()

     # Create worker threads
     self.requests.start()
    

    @@ -1981,7 +1987,8 @@ wsgi_version = (1, 0)

    def init(self, bind_addr, wsgi_app, numthreads=10, server_name=None, - max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5): + max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5, + post_listen_hook=None): self.requests = ThreadPool(self, min=numthreads or 1, max=max) self.wsgi_app = wsgi_app self.gateway = wsgi_gateways[self.wsgi_version] @@ -1994,6 +2001,7 @@

     self.timeout = timeout
     self.shutdown_timeout = shutdown_timeout
    
    • self.post_listen_hook = post_listen_hook or (lambda: None) self.clear_stats()

    def _get_numthreads(self): }}}

Reported by andy@chubot.org

Comments (1)

  1. Log in to comment