Beispiel #1
0
    def get_connection(self, event: GetHttpConnection, *, reuse: bool = True) -> layer.CommandGenerator[None]:
        # Do we already have a connection we can re-use?
        if reuse:
            for connection in self.connections:
                # see "tricky multiplexing edge case" in make_http_connection for an explanation
                conn_is_pending_or_h2 = (
                    connection.alpn == b"h2"
                    or connection in self.waiting_for_establishment
                )
                h2_to_h1 = self.context.client.alpn == b"h2" and not conn_is_pending_or_h2
                connection_suitable = (
                    event.connection_spec_matches(connection)
                    and not h2_to_h1
                )
                if connection_suitable:
                    if connection in self.waiting_for_establishment:
                        self.waiting_for_establishment[connection].append(event)
                        return
                    elif connection.connected:
                        stream = self.command_sources.pop(event)
                        yield from self.event_to_child(stream, GetHttpConnectionCompleted(event, (connection, None)))
                        return
                    else:
                        pass  # the connection is at least half-closed already, we want a new one.

        can_use_context_connection = (
            self.context.server not in self.connections and
            self.context.server.connected and
            event.connection_spec_matches(self.context.server)
        )
        context = self.context.fork()

        stack = tunnel.LayerStack()

        if not can_use_context_connection:

            context.server = Server(event.address)
            if event.tls:
                context.server.sni = event.address[0]

            if event.via:
                assert event.via.scheme in ("http", "https")
                http_proxy = Server(event.via.address)

                if event.via.scheme == "https":
                    http_proxy.alpn_offers = tls.HTTP_ALPNS
                    http_proxy.sni = event.via.address[0]
                    stack /= tls.ServerTLSLayer(context, http_proxy)

                send_connect = not (self.mode == HTTPMode.upstream and not event.tls)
                stack /= _upstream_proxy.HttpUpstreamProxy(context, http_proxy, send_connect)
            if event.tls:
                stack /= tls.ServerTLSLayer(context)

        stack /= HttpClient(context)

        self.connections[context.server] = stack[0]
        self.waiting_for_establishment[context.server].append(event)

        yield from self.event_to_child(stack[0], events.Start())
Beispiel #2
0
    def handle_connect_upstream(self):
        assert self.context.server.via.scheme in ("http", "https")

        http_proxy = Server(self.context.server.via.address)

        stack = tunnel.LayerStack()
        if self.context.server.via.scheme == "https":
            http_proxy.sni = self.context.server.via.address[0]
            stack /= tls.ServerTLSLayer(self.context, http_proxy)
        stack /= _upstream_proxy.HttpUpstreamProxy(self.context, http_proxy, True)

        self.child_layer = stack[0]
        yield from self.handle_connect_finish()