uWSGI protocol request parser. The uWSGI protocol uses a 4-byte binary header: - Byte 0: modifier1 (packet type, 0 = WSGI request) - Bytes 1-2: datasize (16-bit little-endian, size of vars block) - Byte 3: modifier2 (additional flags, typically 0) After the header: 1. Vars
| 15 | |
| 16 | |
| 17 | class UWSGIRequest: |
| 18 | """uWSGI protocol request parser. |
| 19 | |
| 20 | The uWSGI protocol uses a 4-byte binary header: |
| 21 | - Byte 0: modifier1 (packet type, 0 = WSGI request) |
| 22 | - Bytes 1-2: datasize (16-bit little-endian, size of vars block) |
| 23 | - Byte 3: modifier2 (additional flags, typically 0) |
| 24 | |
| 25 | After the header: |
| 26 | 1. Vars block (datasize bytes): Key-value pairs containing WSGI environ |
| 27 | - Each pair: 2-byte key_size (LE) + key + 2-byte val_size (LE) + value |
| 28 | 2. Request body (determined by CONTENT_LENGTH in vars) |
| 29 | """ |
| 30 | |
| 31 | def __init__(self, cfg, unreader, peer_addr, req_number=1): |
| 32 | self.cfg = cfg |
| 33 | self.unreader = unreader |
| 34 | self.peer_addr = peer_addr |
| 35 | self.remote_addr = peer_addr |
| 36 | self.req_number = req_number |
| 37 | |
| 38 | # Request attributes (compatible with HTTP Request interface) |
| 39 | self.method = None |
| 40 | self.uri = None |
| 41 | self.path = None |
| 42 | self.query = None |
| 43 | self.fragment = "" |
| 44 | self.version = (1, 1) # uWSGI is HTTP/1.1 compatible |
| 45 | self.headers = [] |
| 46 | self.trailers = [] |
| 47 | self.body = None |
| 48 | self.scheme = "https" if cfg.is_ssl else "http" |
| 49 | self.must_close = False |
| 50 | |
| 51 | # uWSGI specific |
| 52 | self.uwsgi_vars = {} |
| 53 | self.modifier1 = 0 |
| 54 | self.modifier2 = 0 |
| 55 | |
| 56 | # Proxy protocol compatibility |
| 57 | self.proxy_protocol_info = None |
| 58 | |
| 59 | # 100-continue: not applicable for uWSGI as the frontend handles this |
| 60 | self._expected_100_continue = False |
| 61 | |
| 62 | # Check if the source IP is allowed |
| 63 | self._check_allowed_ip() |
| 64 | |
| 65 | # Parse the request |
| 66 | unused = self.parse(self.unreader) |
| 67 | self.unreader.unread(unused) |
| 68 | self.set_body_reader() |
| 69 | |
| 70 | def _check_allowed_ip(self): |
| 71 | """Verify source IP is in the allowed list.""" |
| 72 | allow_ips = getattr(self.cfg, 'uwsgi_allow_ips', ['127.0.0.1', '::1']) |
| 73 | |
| 74 | # UNIX sockets don't have IP addresses |
no outgoing calls