A connection between mitmproxy and an upstream server.
| 261 | |
| 262 | @dataclass(eq=False, repr=False, kw_only=True) |
| 263 | class Server(Connection): |
| 264 | """A connection between mitmproxy and an upstream server.""" |
| 265 | |
| 266 | address: Address | None # type: ignore |
| 267 | """ |
| 268 | The server's `(host, port)` address tuple. |
| 269 | |
| 270 | The host can either be a domain or a plain IP address. |
| 271 | Which of those two will be present depends on the proxy mode and the client. |
| 272 | For explicit proxies, this value will reflect what the client instructs mitmproxy to connect to. |
| 273 | For example, if the client starts off a connection with `CONNECT example.com HTTP/1.1`, it will be `example.com`. |
| 274 | For transparent proxies such as WireGuard mode, this value will be an IP address. |
| 275 | """ |
| 276 | |
| 277 | peername: Address | None = None |
| 278 | """ |
| 279 | The server's resolved `(ip, port)` tuple. Will be set during connection establishment. |
| 280 | May be `None` in upstream proxy mode when the address is resolved by the upstream proxy only. |
| 281 | """ |
| 282 | sockname: Address | None = None |
| 283 | |
| 284 | timestamp_start: float | None = None |
| 285 | """ |
| 286 | *Timestamp:* Connection establishment started. |
| 287 | |
| 288 | For IP addresses, this corresponds to sending a TCP SYN; for domains, this corresponds to starting a DNS lookup. |
| 289 | """ |
| 290 | timestamp_tcp_setup: float | None = None |
| 291 | """*Timestamp:* TCP ACK received.""" |
| 292 | |
| 293 | via: server_spec.ServerSpec | None = None |
| 294 | """An optional proxy server specification via which the connection should be established.""" |
| 295 | |
| 296 | def __str__(self): |
| 297 | if self.alpn: |
| 298 | tls_state = f", alpn={self.alpn.decode(errors='replace')}" |
| 299 | elif self.tls_established: |
| 300 | tls_state = ", tls" |
| 301 | else: |
| 302 | tls_state = "" |
| 303 | if self.sockname: |
| 304 | local_port = f", src_port={self.sockname[1]}" |
| 305 | else: |
| 306 | local_port = "" |
| 307 | state = self.state.name |
| 308 | assert state |
| 309 | return f"Server({human.format_address(self.address)}, state={state.lower()}{tls_state}{local_port})" |
| 310 | |
| 311 | def __setattr__(self, name, value): |
| 312 | if name in ("address", "via"): |
| 313 | connection_open = ( |
| 314 | self.__dict__.get("state", ConnectionState.CLOSED) |
| 315 | is ConnectionState.OPEN |
| 316 | ) |
| 317 | # assigning the current value is okay, that may be an artifact of calling .set_state(). |
| 318 | attr_changed = self.__dict__.get(name) != value |
| 319 | if connection_open and attr_changed: |
| 320 | raise RuntimeError(f"Cannot change server.{name} on open connection.") |
no outgoing calls
searching dependent graphs…