88"""
99
1010try :
11- from typing import Callable , Protocol
11+ from typing import Callable , Protocol , Union
12+ from socket import socket
13+ from socketpool import SocketPool
1214except ImportError :
1315 pass
1416
@@ -92,6 +94,40 @@ def start(self, host: str, port: int = 80, root_path: str = "") -> None:
9294 self ._sock .listen (10 )
9395 self ._sock .setblocking (False ) # non-blocking socket
9496
97+ def _receive_header_bytes (
98+ self , sock : Union ["SocketPool.Socket" , "socket.socket" ]
99+ ) -> bytes :
100+ """Receive bytes until a empty line is received."""
101+ received_bytes = bytes ()
102+ while b"\r \n \r \n " not in received_bytes :
103+ try :
104+ length = sock .recv_into (self ._buffer , len (self ._buffer ))
105+ received_bytes += self ._buffer [:length ]
106+ except OSError as ex :
107+ if ex .errno == ETIMEDOUT :
108+ break
109+ except Exception as ex :
110+ raise ex
111+ return received_bytes
112+
113+ def _receive_body_bytes (
114+ self ,
115+ sock : Union ["SocketPool.Socket" , "socket.socket" ],
116+ received_body_bytes : bytes ,
117+ content_length : int ,
118+ ) -> bytes :
119+ """Receive bytes until the given content length is received."""
120+ while len (received_body_bytes ) < content_length :
121+ try :
122+ length = sock .recv_into (self ._buffer , len (self ._buffer ))
123+ received_body_bytes += self ._buffer [:length ]
124+ except OSError as ex :
125+ if ex .errno == ETIMEDOUT :
126+ break
127+ except Exception as ex :
128+ raise ex
129+ return received_body_bytes [:content_length ]
130+
95131 def poll (self ):
96132 """
97133 Call this method inside your main event loop to get the server to
@@ -102,25 +138,23 @@ def poll(self):
102138 conn , _ = self ._sock .accept ()
103139 with conn :
104140 conn .settimeout (self ._timeout )
105- received_data = bytearray ()
106-
107- # Receiving data until timeout
108- while "Receiving data" :
109- try :
110- length = conn .recv_into (self ._buffer , len (self ._buffer ))
111- received_data += self ._buffer [:length ]
112- except OSError as ex :
113- if ex .errno == ETIMEDOUT :
114- break
115- except Exception as ex :
116- raise ex
141+
142+ # Receiving data until empty line
143+ header_bytes = self ._receive_header_bytes (conn )
117144
118145 # Return if no data received
119- if not received_data :
146+ if not header_bytes :
120147 return
121148
122- # Parsing received data
123- request = HTTPRequest (raw_request = received_data )
149+ request = HTTPRequest (header_bytes )
150+
151+ content_length = int (request .headers .get ("content-length" , 0 ))
152+ received_body_bytes = request .body
153+
154+ # Receiving remaining body bytes
155+ request .body = self ._receive_body_bytes (
156+ conn , received_body_bytes , content_length
157+ )
124158
125159 handler = self .route_handlers .get (
126160 _HTTPRoute (request .path , request .method ), None
0 commit comments