| 134 | IOLoop.current().spawn_callback(self.handle_request, request) |
| 135 | |
| 136 | async def handle_request(self, request: httputil.HTTPServerRequest) -> None: |
| 137 | data = {} # type: Dict[str, Any] |
| 138 | response = [] # type: List[bytes] |
| 139 | |
| 140 | def start_response( |
| 141 | status: str, |
| 142 | headers: List[Tuple[str, str]], |
| 143 | exc_info: Optional[ |
| 144 | Tuple[ |
| 145 | "Optional[Type[BaseException]]", |
| 146 | Optional[BaseException], |
| 147 | Optional[TracebackType], |
| 148 | ] |
| 149 | ] = None, |
| 150 | ) -> Callable[[bytes], Any]: |
| 151 | data["status"] = status |
| 152 | data["headers"] = headers |
| 153 | return response.append |
| 154 | |
| 155 | loop = IOLoop.current() |
| 156 | app_response = await loop.run_in_executor( |
| 157 | self.executor, |
| 158 | self.wsgi_application, |
| 159 | self.environ(request), |
| 160 | start_response, |
| 161 | ) |
| 162 | try: |
| 163 | app_response_iter = iter(app_response) |
| 164 | |
| 165 | def next_chunk() -> Optional[bytes]: |
| 166 | try: |
| 167 | return next(app_response_iter) |
| 168 | except StopIteration: |
| 169 | # StopIteration is special and is not allowed to pass through |
| 170 | # coroutines normally. |
| 171 | return None |
| 172 | |
| 173 | while True: |
| 174 | chunk = await loop.run_in_executor(self.executor, next_chunk) |
| 175 | if chunk is None: |
| 176 | break |
| 177 | response.append(chunk) |
| 178 | finally: |
| 179 | if hasattr(app_response, "close"): |
| 180 | app_response.close() # type: ignore |
| 181 | body = b"".join(response) |
| 182 | if not data: |
| 183 | raise Exception("WSGI app did not call start_response") |
| 184 | |
| 185 | status_code_str, reason = data["status"].split(" ", 1) |
| 186 | status_code = int(status_code_str) |
| 187 | headers = data["headers"] # type: List[Tuple[str, str]] |
| 188 | header_set = {k.lower() for (k, v) in headers} |
| 189 | body = escape.utf8(body) |
| 190 | if status_code != 304: |
| 191 | if "content-length" not in header_set: |
| 192 | headers.append(("Content-Length", str(len(body)))) |
| 193 | if "content-type" not in header_set: |