8
8
"""
9
9
10
10
try :
11
- from typing import Callable , Protocol
11
+ from typing import Callable , Protocol , Union
12
+ from socket import socket
13
+ from socketpool import SocketPool
12
14
except ImportError :
13
15
pass
14
16
@@ -92,6 +94,40 @@ def start(self, host: str, port: int = 80, root_path: str = "") -> None:
92
94
self ._sock .listen (10 )
93
95
self ._sock .setblocking (False ) # non-blocking socket
94
96
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
+
95
131
def poll (self ):
96
132
"""
97
133
Call this method inside your main event loop to get the server to
@@ -102,25 +138,23 @@ def poll(self):
102
138
conn , _ = self ._sock .accept ()
103
139
with conn :
104
140
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 )
117
144
118
145
# Return if no data received
119
- if not received_data :
146
+ if not header_bytes :
120
147
return
121
148
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
+ )
124
158
125
159
handler = self .route_handlers .get (
126
160
_HTTPRoute (request .path , request .method ), None
0 commit comments