| 140 | return length |
| 141 | |
| 142 | def read_request_payload(self, length: int) -> dict[str, Any] | None: |
| 143 | try: |
| 144 | raw_body = self.rfile.read(length) |
| 145 | except TimeoutError: |
| 146 | self.reject(408, "timed out reading request body") |
| 147 | return None |
| 148 | if len(raw_body) != length: |
| 149 | self.reject(400, "request body ended before content-length") |
| 150 | return None |
| 151 | try: |
| 152 | payload = json.loads(raw_body) |
| 153 | except json.JSONDecodeError as err: |
| 154 | self.reject(400, str(err)) |
| 155 | return None |
| 156 | if not isinstance(payload, dict): |
| 157 | self.reject(400, "request body must be a JSON object") |
| 158 | return None |
| 159 | return payload |
| 160 | |
| 161 | def do_POST(self) -> None: |
| 162 | if self.path != "/run": |