DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Accelerating Connection Handshakes in Trusted Network Environments
  • AWS Serverless Lambda Resiliency: Part 1
  • Load-Balancing Minecraft Servers with Kong Gateway
  • Build Reactive REST APIs With Spring WebFlux

Trending

  • A Deep Dive Into Firmware Over the Air for IoT Devices
  • Cosmos DB Disaster Recovery: Multi-Region Write Pitfalls and How to Evade Them
  • Immutable Secrets Management: A Zero-Trust Approach to Sensitive Data in Containers
  • Dropwizard vs. Micronaut: Unpacking the Best Framework for Microservices
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Getting Started With HTTP/2

Getting Started With HTTP/2

See why HTTP/2 might be for you!

By 
Randhir Singh user avatar
Randhir Singh
·
Oct. 15, 19 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
24.5K Views

Join the DZone community and get the full member experience.

Join For Free

server-with-wires

The web is built on small HTTP exchanges. HTTP runs on TCP, which is aimed at long running transfers — it is not cut out for small exchanges that are common with HTTP.  There is a lot of overhead caused by TCP in a modern website where only a fraction of time is spent downloading content. HTTP/2 addresses these performance problems. In this article, we will review how HTTP/2 works under the hood and introduce tools to get started with HTTP/2.

You may also like: TLS/SSL Explained: TLS/SSL Terminology and Basics.

TCP

The Internet consists of five layers of TCP/IP. All applications run on the Transport layer, which, for HTTP, is TCP.

Five layers of TCP/IP

Five layers of TCP/IP

The first thing that takes place when establishing a TCP connection is what is known as Three-Way handshake.

Three-Way handshake

Three-Way handshake

Every time a new HTTP request is made, the TCP Three-Way handshake adds this overhead before HTTP Request can be made. Every TCP connection is then closed with a Three-Way handshake too. This adds latency in order of tens of milliseconds for every HTTP request.  The HTTP Header Connection: Keep-Alive introduced in HTTP/1.1 solves this problem to some extent.

TCP is a reliable protocol — every packet sent by the client is acknowledged. This relieves applications from the complex problems of loosing packets or receiving them out-of-order. This, however, introduces another problem — Head-of-line blocking in addition to increasing the overhead. 

TCP deals with network congestion using flow control. TCP slow start is a flow control mechanism where it gradually increases the TCP window size until it finds the network's maximum carrying capacity. The TCP slow start adds to the latency in HTTP requests and responses.

HTTP/2

HTTP/2 addresses the shortcomings of TCP. It is a binary protocol that keeps the same semantics as HTTP 1.x, meaning that all the headers, verbs, resources, etc. work in the same way. It is more about solving issues with TCP than fixing problems with HTTP 1.x.

HTTP/2 Connection

There are two ways to make an HTTP/2 connection

  1. Establishing an h2c connection. HTTP/2 can work over HTTP connection over plain text.Establishing an h2c connection

    Establishing an h2c connection
  2. Establishing an h2 connection. Predominant way of using HTTP/2 is to establish connection over HTTPS.Establishing h2c connection

    Establishing h2c connection

Frames constitute the basic protocol unit in HTTP/2 and are used to communicate data — request, reponse, header, or body.

Image title

The header frames are compressed using HPACK.

Streams

Streams represent a logical single request/response communication. A stream is just a bidirectional sequence of frames that share a common identifier. This enables interleaving of frames from multiple streams together that allows for multiplexed communication over a single connection.Stream workflow

Stream workflow

HTTP/2 uses single TCP connection per host. It provides bi-directional multiplexing via streams allowing for concurrent requests and responses. Streams can be prioritized as well as subjected to flow control.

Server Push

Server push is a function available in HTTP/2 whereby a server can push resources to the client without having client request them. It still provides clients with control whether it wants to accept the data or not.  Although, server push eliminates the need to inline resources, e.g., JavaScript, CSS, it does not replace other technologies, e.g., WebSockets.

Tools

We will use tools that support HTTP/2 to investigate HTTP/2 connections.

1. cURL. HTTP/2 support was added in version 7.33+. It uses nghttp2 library under the covers. The command line parameter --http2 can be used to make HTTP/2 requests, e.g., curl --http2 domain.com. Alternatively, a Docker image can be used for cURL that supports HTTP/2.

 docker run -t --rm badouralix/curl-http2 \
--http2-prior-knowledge -i -k \
    https://http2.golang.org



 2. Chrome Tools
. Chrome provides protocol information under the Network tab.Monitoring feedback from Chrome

Monitoring feedback from Chrome

Chrome also provides chrome://net-export  to save netlogs that can be used to view HTTP/2 sessions using external netlog viewer — https://netlog-viewer.appspot.com.

3. Wireshark. Wireshark can be used to view HTTP/2 exchanges, as it supports decrypting of SSL. To do so, we need to export the environment variable SSHKEYLOGFILE from the browser and configure Wireshark to use this sslkeylog file.

HTTP/2 in Action

We will use tools to do exercises that will help us understand HTTP/2 better.

1. HTTP/2 demo. Let us start by checking if our browser supports HTTP/2. Open the Akamai website in your Chrome browser. Check out the demo that shows how HTTP/2 improves performance and load time.

2. HTTP/2 Connection. Use cURL to connect to an HTTP/2 server serving plain text. The client first connects to the server over HTTP/1.1 and sends an upgrade request. The server responds with 101 Switching Protocols, and then the connection upgrades to HTTP/2.

> curl -vs -o /dev/null --http2 http://nghttp2.org
*   Trying 139.162.123.134...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x66aba0)
* Connected to nghttp2.org (139.162.123.134) port 80 (#0)
> GET / HTTP/1.1
> Host: nghttp2.org
> User-Agent: curl/7.64.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
>
< HTTP/1.1 101 Switching Protocols
< Connection: Upgrade
< Upgrade: h2c
* Received 101
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=33
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 200
< date: Sat, 05 Oct 2019 04:59:34 GMT
< content-type: text/html
< last-modified: Mon, 19 Aug 2019 13:20:36 GMT
< etag: "5d5aa224-19d8"
< accept-ranges: bytes
< content-length: 6616
< x-backend-header-rtt: 0.001353
< server: nghttpx
< via: 2 nghttpx
< alt-svc: h3-23=":4433"; ma=3600
< x-frame-options: SAMEORIGIN
< x-xss-protection: 1; mode=block
< x-content-type-options: nosniff
<
{ [6616 bytes data]
* Failed writing body (0 != 6616)
* stopped the pause stream!
* Connection #0 to host nghttp2.org left intact


Next, let's connect to an HTTP/2 server over TLS. To decrypt TLS traffic in Wireshark, set the environment variable 

set SSHKEYLOGFILE=%USERPROFILE%\tools\ssl\keylog.log


or, launch Chrome Canary with flag  --ssl-key-log-file.

>"AppData\Local\Google\Chrome SxS\Application\chrome.exe" \
--ssl-key-log-file=%USERPROFILE%\tools\ssl\keylog.log


To launch Wireshark, go to Edit->Preferences->Protocols. Select TLS, and set the logfile name to the same file as set in the environment variable SSHKEYLOGFILE. With this set, we'll be able to decrypt TLS traffic. Start traffic capture in Wireshark, and in your Chrome browser, open https://http2.golang.org/. 

Capturing TLS traffic

Capturing TLS traffic


3. HTTP/2 Stream Exchange.  Go to https://http2.golang.org/gophertiles in Chrome browser and see the HTTP/2 Streams in Wireshark. You can also use Chrome Developer Tools to see the HTTP/2 exchanges under Network tab.

Checking changes under Network tab in Chrome

Checking changes under Network tab in Chrome


4. HTTP/2 Priorities. nghttp2 not only provides a library that cURL uses, but it also provides an HTTP/2 server that implements HTTP/2 priorities based on content-type — it first serves HTML, followed by CSS, and then JavaScript. It is available as a Docker image.

>docker run --rm -it svagi/nghttp2 nghttpd
Usage: nghttpd [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]
HTTP/2 server
Too few arguments


The nghttp client can be used to connect to an HTTP/2 server.

>docker run --rm -ti svagi/nghttp2 nghttp -nv https://nghttp2.org
[  0.604] Connected
The negotiated protocol: h2
[  1.326] recv SETTINGS frame <length=24, flags=0x00, stream_id=0>
          (niv=4)
          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):1048576]
          [UNKNOWN(0x08):1]
          [SETTINGS_HEADER_TABLE_SIZE(0x01):8192]
[  1.326] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
          (niv=2)
          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[  1.326] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
          ; ACK
          (niv=0)
[  1.326] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
          (dep_stream_id=0, weight=201, exclusive=0)
[  1.326] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
          (dep_stream_id=0, weight=101, exclusive=0)
[  1.326] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
          (dep_stream_id=0, weight=1, exclusive=0)
[  1.326] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
          (dep_stream_id=7, weight=1, exclusive=0)
[  1.326] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
          (dep_stream_id=3, weight=1, exclusive=0)
[  1.326] send HEADERS frame <length=39, flags=0x25, stream_id=13>
          ; END_STREAM | END_HEADERS | PRIORITY
          (padlen=0, dep_stream_id=11, weight=16, exclusive=0)
          ; Open new stream
          :method: GET
          :path: /
          :scheme: https
          :authority: nghttp2.org
          accept: */*
          accept-encoding: gzip, deflate
          user-agent: nghttp2/1.12.0
[  1.629] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
          ; ACK
          (niv=0)
[  1.629] recv (stream_id=13) :method: GET
[  1.629] recv (stream_id=13) :scheme: https
[  1.629] recv (stream_id=13) :path: /stylesheets/screen.css
[  1.629] recv (stream_id=13) :authority: nghttp2.org
[  1.629] recv (stream_id=13) accept-encoding: gzip, deflate
[  1.629] recv (stream_id=13) user-agent: nghttp2/1.12.0
[  1.629] recv PUSH_PROMISE frame <length=47, flags=0x04, stream_id=13>
          ; END_HEADERS
          (padlen=0, promised_stream_id=2)
[  1.683] recv (stream_id=13) :status: 200
[  1.683] recv (stream_id=13) date: Sat, 05 Oct 2019 11:12:30 GMT
[  1.683] recv (stream_id=13) content-type: text/html
[  1.683] recv (stream_id=13) last-modified: Mon, 19 Aug 2019 13:20:36 GMT
[  1.683] recv (stream_id=13) etag: "5d5aa224-19d8"
[  1.683] recv (stream_id=13) accept-ranges: bytes
[  1.683] recv (stream_id=13) content-length: 6616
[  1.684] recv (stream_id=13) x-backend-header-rtt: 0.001768
[  1.684] recv (stream_id=13) strict-transport-security: max-age=31536000
[  1.684] recv (stream_id=13) server: nghttpx
[  1.684] recv (stream_id=13) via: 2 nghttpx
[  1.684] recv (stream_id=13) alt-svc: h3-23=":4433"; ma=3600
[  1.684] recv (stream_id=13) x-frame-options: SAMEORIGIN
[  1.684] recv (stream_id=13) x-xss-protection: 1; mode=block
[  1.684] recv (stream_id=13) x-content-type-options: nosniff
[  1.684] recv HEADERS frame <length=238, flags=0x04, stream_id=13>
          ; END_HEADERS
          (padlen=0)
          ; First response header
[  1.684] recv (stream_id=2) :status: 200
[  1.684] recv (stream_id=2) date: Sat, 05 Oct 2019 11:12:30 GMT
[  1.684] recv (stream_id=2) content-type: text/css
[  1.684] recv (stream_id=2) last-modified: Mon, 19 Aug 2019 13:20:36 GMT
[  1.684] recv (stream_id=2) etag: "5d5aa224-98aa"
[  1.684] recv (stream_id=2) accept-ranges: bytes
[  1.684] recv (stream_id=2) content-length: 39082
[  1.684] recv (stream_id=2) x-backend-header-rtt: 0.001364
[  1.684] recv (stream_id=2) strict-transport-security: max-age=31536000
[  1.684] recv (stream_id=2) server: nghttpx
[  1.684] recv (stream_id=2) via: 2 nghttpx
[  1.684] recv (stream_id=2) alt-svc: h3-23=":4433"; ma=3600
[  1.684] recv (stream_id=2) x-frame-options: SAMEORIGIN
[  1.684] recv (stream_id=2) x-xss-protection: 1; mode=block
[  1.685] recv (stream_id=2) x-content-type-options: nosniff
[  1.685] recv (stream_id=2) x-http2-push: 1
[  1.685] recv HEADERS frame <length=63, flags=0x04, stream_id=2>
          ; END_HEADERS
          (padlen=0)
          ; First push response header
[  1.685] recv DATA frame <length=6616, flags=0x01, stream_id=13>
          ; END_STREAM
[  1.685] recv DATA frame <length=9431, flags=0x00, stream_id=2>
[  1.972] recv DATA frame <length=15732, flags=0x00, stream_id=2>
[  2.259] recv DATA frame <length=13919, flags=0x01, stream_id=2>
          ; END_STREAM
[  2.259] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
          (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])


We'll create a simple application consisting of HTML, CSS and JavaScript and will have nghttpd server, which is a HTTP/2 server, serve it over TLS.  Create folders — certs and docs. The certs folder will store private key and certificate; docs will store the application.

Generate a self-signed certificate.

openssl req -newkey rsa:2048 -nodes -keyout certs/nghttpd.key \
-x509 -days 365 -out certs/nghttpd.crt


Create the application.

<!DOCTYPE html>
<html>
<head>
  <title>HTTP/2</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<h1>I am a headline made with HTML</h1>
<p>And I am a simple text paragraph. The color of this text is styled with CSS. 
      Click the button below to remove me through the power JavaScript.</p>
<button>Toggle the text above</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="script.js"></script>
</body>
</html>


body {
font-family: sans-serif;
text-align: center;
padding: 3rem;
font-size: 1.125rem;
line-height: 1.5;
transition: all 725ms ease-in-out;
}

h1 {
font-size: 2rem;
font-weight: bolder;
margin-bottom: 1rem;
}

p {
margin-bottom: 1rem;
color: tomato;
}

button {
cursor: pointer;
appearance: none;
border-radius: 4px;
font-size: 1.25rem;
padding: 0.75rem 1rem;
border: 1px solid navy;
background-color: dodgerblue;
color: white;
}


$('button').on('click', function() {
$('p').toggle();
});


Now launch nghttpd.

>docker run --rm -it -p 443:443 -v D:\nghttpd\certs\nghttpd.crt:/ssl/nghttpd.crt \
-v D:\nghttpd\certs\nghttpd.key:/ssl/nghttpd.key \
    -v D:\nghttpd\docs:/docs svagi/nghttp2 nghttpd 443 \
    /ssl/nghttpd.key /ssl/nghttpd.crt -d /docs


Open the browser and hit https://127.0.0.1/index.html. Usechrome://net-export  to save netlogs and then view the netlog file using netlog viewer — https://netlog-viewer.appspot.com. We can see that HTML is served first, followed by CSS, and then JavaScript — the priority determined by the nghttpd server.

5. Server Push. We can configure server to push a resource when it gets request for another resource. Let us push CSS file when we get request for HTML.

Start nghttpd server with -p  option to indicate that it should push style.css when a request is made for index.html file. Export the netlog file and view using netlog viewer to see the session showing PUSH details.

>docker run --rm -it -p 443:443 -v D:\nghttpd\certs\nghttpd.crt:/ssl/nghttpd.crt \
-v D:\nghttpd\certs\nghttpd.key:/ssl/nghttpd.key \
    -v D:\nghttpd\docs:/docs \
    svagi/nghttp2 nghttpd 443 /ssl/nghttpd.key /ssl/nghttpd.crt \
    -d /docs -p/index.html=/style.css


 6. Working with HTTP/2 Library
. Java library okhttp can be used to connect to an HTTP/2 server. Code illustrating HTTP/2 Request using okhttp can be downloaded from my GitHub. Remember to  pass-Xbootclasspath/p:alpn-boot-8.1.13.v20181017.jar  as VM Option in IntelliJ Run Configuration if you are using Java version 8. Java 9 and above has native ALPN support and this VM option is not supported. 

Conclusion

In this article, we looked at how HTTP/2 addresses some of the performance issues seen in modern web applications. We introduced few tools to get up to speed with HTTP/2.  There are many resources on the web to learn more. 


Further Reading

  • Introduction to HTTP.
Connection (dance) Transmission Control Protocol Requests application push Stream (computing)

Opinions expressed by DZone contributors are their own.

Related

  • Accelerating Connection Handshakes in Trusted Network Environments
  • AWS Serverless Lambda Resiliency: Part 1
  • Load-Balancing Minecraft Servers with Kong Gateway
  • Build Reactive REST APIs With Spring WebFlux

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!