Connection Upgrade

The :upgrade plugin is a “meta-plugin”, on top of which one can leverage the HTTP/1.1-only Upgrade header to renegotiate an HTTP connection into some other protocol (it’s widely used by browser to establish websocket connections, for example).

def handle_tcp_upgrade(connection, request, response)
  steal_tcp_socket(connection.io.socket)
end

http_upgrade = HTTPX.plugin(:upgrade, upgrade_handlers: { "tcp" => method(:handle_tcp_upgrade) })
http_upgrade.get("http://socket-upgrader")

If you’re instested in how an implementation of a websocket client could look like, have a look at this unit test.

Other plugins are built on top of it:

h2c

The :h2c plugin leverages the upgrade plugin to negotiate an “upgrade” of an unencrypted HTTP/1.1 connection into an HTTP/2 connection.

require "httpx"
http = HTTPX.plugin(:h2c)
http.get("http://nghttp2.org/blog/archives/", "http://nghttp2.org/")
# Connected to nghttp2.org (139.162.123.134) port 80 (#6)
# <- HEADLINE: "GET /blog/archives/ HTTP/1.1"
# <- HEADER: User-Agent: httpx.rb/0.12.0
# <- HEADER: Accept: */*
# <- HEADER: Connection: upgrade, http2-settings
# <- HEADER: Upgrade: h2c
# <- HEADER: HTTP2-Settings: AAIAAAAA
# <- HEADER: Host: nghttp2.org
# <-
# WRITE: 170 bytes...
# READ: 1552 bytes...
# -> HEADLINE: 101 HTTP/1.1
# -> HEADER: connection: Upgrade
# -> HEADER: upgrade: h2c
# upgrading to h2c...
# 1: <- HEADER: :status: 200
# 1: <- HEADER: content-type: text/html
# 1: <- HEADER: ...
# ....
# 3: <- HEADER: :status: 200
# ...

Although it’s not recommend to use cleartext in the open internet nowadays, there are a few use cases where this scheme is useful, such as backend-to-backend connection establishment in closed intranets, and GRPC, which uses h2c to negotiate non-encrypted connections.

h2

The :upgrade/h2 plugin (which is actually automatically loaded with the :upgrade plugin) takes advantage of an Upgrade header that certain servers (such as apache) send with a response, advertising alternative protocols one can connect with (such as h2). This is useful if the client or server does not support ALPN negotiation (like having old TLS versions) and require prior knowledge to connect.

After the first request, a new connection is established using HTTP/2, through which subsequent requests will be directed.

Next: Persistent