1818
1919from .authentication import Basic , Bearer , require_authentication
2020from .exceptions import (
21+ ServerStoppedError ,
2122 AuthenticationError ,
2223 FileNotExistsError ,
2324 InvalidPathError ,
@@ -47,6 +48,7 @@ def __init__(self, socket_source: Protocol, root_path: str = None) -> None:
4748 self ._socket_source = socket_source
4849 self ._sock = None
4950 self .root_path = root_path
51+ self .stopped = False
5052
5153 def route (self , path : str , methods : Union [str , List [str ]] = GET ) -> Callable :
5254 """
@@ -91,13 +93,14 @@ def serve_forever(self, host: str, port: int = 80) -> None:
9193 """
9294 Wait for HTTP requests at the given host and port. Does not return.
9395 Ignores any exceptions raised by the handler function and continues to serve.
96+ Returns only when the server is stopped by calling ``.stop()``.
9497
9598 :param str host: host name or IP address
9699 :param int port: port
97100 """
98101 self .start (host , port )
99102
100- while "Serving forever" :
103+ while not self . stopped :
101104 try :
102105 self .poll ()
103106 except : # pylint: disable=bare-except
@@ -106,17 +109,27 @@ def serve_forever(self, host: str, port: int = 80) -> None:
106109 def start (self , host : str , port : int = 80 ) -> None :
107110 """
108111 Start the HTTP server at the given host and port. Requires calling
109- poll() in a while loop to handle incoming requests.
112+ ``. poll()`` in a while loop to handle incoming requests.
110113
111114 :param str host: host name or IP address
112115 :param int port: port
113116 """
117+ self .stopped = False
114118 self ._sock = self ._socket_source .socket (
115119 self ._socket_source .AF_INET , self ._socket_source .SOCK_STREAM
116120 )
117121 self ._sock .bind ((host , port ))
118122 self ._sock .listen (10 )
119- self ._sock .setblocking (False ) # non-blocking socket
123+ self ._sock .setblocking (False ) # Non-blocking socket
124+
125+ def stop (self ) -> None :
126+ """
127+ Stops the server from listening for new connections and closes the socket.
128+ Current requests will be processed. Server can be started again by calling ``.start()``
129+ or ``.serve_forever()``.
130+ """
131+ self .stopped = True
132+ self ._sock .close ()
120133
121134 def _receive_request (
122135 self ,
@@ -230,6 +243,9 @@ def poll(self):
230243 Call this method inside your main loop to get the server to check for new incoming client
231244 requests. When a request comes in, it will be handled by the handler function.
232245 """
246+ if self .stopped :
247+ raise ServerStoppedError
248+
233249 try :
234250 conn , client_address = self ._sock .accept ()
235251 with conn :
0 commit comments