Everyone, can you give me a star for my project or my previous article? It’s so bitter. Github.com Nuggets article

Introduction to the

Http2.0 this bar is certainly really fragrant, which especially binary frame and multiplexing.

But I have been a little bit wondering why Http2.0 backend support front-end can directly access version 2.0, Okhttp how to enable Http2.0?

A quick word about Http2.0

Binary Framing Layer

Frame is the smallest unit of data transmission. The original plaintext transmission is replaced by binary transmission. The original message is divided into smaller data frames.

MultiPlexing

On a TCP connection, we can continuously send frames to each other. The Stream identifier of each frame identifies which stream the frame belongs to, and then, when received by the other party, we can concatenate all frames of each stream according to the Stream identifier to form a whole block of data. With HTTP/1.1 treating each request as a stream, multiple requests become multiple streams, the request response data is divided into multiple frames, and frames from different streams are sent to each other interleaved. This is multiplexing in HTTP/2. The flow concept implements multiple request-response parallelism on a single connection, solves the problem of blocked headers, and reduces the number of TCP connections and slow start of TCP connections. Http2 requires only one connection for the same domain, rather than six to eight connections as HTTP /1.1 does.

Server Push

The browser sends a request, and the server actively pushes resources associated with the request to the browser so that the browser doesn’t have to make subsequent requests.

The Header compression (HPACK)

Use HPACK algorithm to compress header content

Little secrets you must know about Http2.0

IIS currently supports HTTP/2 only over TLS. When making an HTTPS connection to a web server running IIS on Windows 10, HTTP/2 is used if the client and server both support it. In IIS, we’ve implemented HTTP/2 as transparently as possible – you shouldn’t need to change anything in your application for HTTP/2 to work. Certain HTTP/1.1 optimizations (domain sharding, inlining, etc.) are no longer recommended in HTTP/2, though, so you should plan to remove these in the future.

Http2.0 must build on TLS, that is, requests that must be Https.

TLS

Http2.0 presupposes HTTPS. Https adds a layer of Tls on the basis of Http. This thing in the big factory interview is actually a high frequency test point, simply said that Tls is a back and forth end of the process of good follow-up encryption. This article is very well written, please refer to the portal for details, and the whole process is shown below.

  1. The client initiates the first Client Hello, requests an Https connection, and sends the available TLS version and the available password suite.
  2. The server initiates the first Server Hello process and returns the certificate, password suite, and TLS version.
  3. Generate a random symmetric key, encrypt it using the server’s public key in the certificate, and send it to the server
  4. The server uses private key decryption to obtain the symmetric key

Have you ever wondered why the client can automatically switch all requests to Http2.0 once the backend interface is upgraded to support Http2.0? And what does 2.0 have to do with Tls?

ALPN(Application Layer Protocol Negotiation) Protocol

Application Layer Protocol Negotiation (ALPN) is an extension of TLS and allows Negotiation of Application Layer protocols based on secure connections. ALPN supports negotiation of any application layer protocol, currently most commonly HTTP2 negotiation. Currently, most browsers only support HTTP/2 based on HTTPS deployment, because browsers use the ALPN protocol to determine whether the server supports HTTP2.

ALPN is the TLS extension protocol, and the role of ALPN is to tell the client, the current server supported interface protocol version which, of course, there will be a variety of. The answers to all the above questions are basically visible, and I want to post a picture of my friend hitting me. The reason 2.0 must use TLS is because of the ALPN extension protocol.

OkHttp Connection analysis

I’ve drawn a rough flowchart for how Okhttp works.

ConnectInterceptor


/** Opens a connection to the target server and proceeds to the next interceptor. */
public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    booleandoExtensiveHealthChecks = ! request.method().equals("GET");
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();

    returnrealChain.proceed(request, streamAllocation, httpCodec, connection); }}Copy the code

Here’s another tidbit: How many HTTP requests can a TCP connection have?

As you can see from the interceptor implementation, Okhttp implements a connection pool. When the ConnectionInterceptor is called, it determines if there are any free and healthy connections available in the pool, and then uses the connection to schedule the next interceptor. In other words, the lifetime of a TCP connection is longer than that of an Http request. Therefore, a TCP connection can correspond to multiple Http requests.

The role of the interceptor is built before launch the actual request connection, and then use this link to access, and the core of here is called streamAllocation. NewStream (client, chain, doExtensiveHealthChecks); Gets a connection object.

RealConnection

We’ll focus on the Connet method, which is key to the entire Http2.0 startup process.

 public void connect(int connectTimeout, int readTimeout, int writeTimeout,
      int pingIntervalMillis, boolean connectionRetryEnabled, Call call,
      EventListener eventListener) {
    if(protocol ! =null) throw new IllegalStateException("already connected");

    RouteException routeException = null;
    List<ConnectionSpec> connectionSpecs = route.address().connectionSpecs();
    ConnectionSpecSelector connectionSpecSelector = new ConnectionSpecSelector(connectionSpecs);

    if (route.address().sslSocketFactory() == null) {
      if(! connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) {throw new RouteException(new UnknownServiceException(
            "CLEARTEXT communication not enabled for client"));
      }
      String host = route.address().url().host();
      if(! Platform.get().isCleartextTrafficPermitted(host)) {throw new RouteException(new UnknownServiceException(
            "CLEARTEXT communication to " + host + " not permitted by network security policy")); }}else {
      if (route.address().protocols().contains(Protocol.H2_PRIOR_KNOWLEDGE)) {
        throw new RouteException(new UnknownServiceException(
            "H2_PRIOR_KNOWLEDGE cannot be used with HTTPS")); }}while (true) {
      try {
        if (route.requiresTunnel()) {
          connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener);
          if (rawSocket == null) {
            // We were unable to connect the tunnel but properly closed down our resources.
            break; }}else {
          connectSocket(connectTimeout, readTimeout, call, eventListener);
        }
        establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener);
        eventListener.connectEnd(call, route.socketAddress(), route.proxy(), protocol);
        break;
      } catch (IOException e) {
        closeQuietly(socket);
        closeQuietly(rawSocket);
        socket = null;
        rawSocket = null;
        source = null;
        sink = null;
        handshake = null;
        protocol = null;
        http2Connection = null;

        eventListener.connectFailed(call, route.socketAddress(), route.proxy(), null, e);

        if (routeException == null) {
          routeException = new RouteException(e);
        } else {
          routeException.addConnectException(e);
        }

        if(! connectionRetryEnabled || ! connectionSpecSelector.connectionFailed(e)) {throwrouteException; }}}if (route.requiresTunnel() && rawSocket == null) {
      ProtocolException exception = new ProtocolException("Too many tunnel connections attempted: "
          + MAX_TUNNEL_ATTEMPTS);
      throw new RouteException(exception);
    }

    if(http2Connection ! =null) {
      synchronized(connectionPool) { allocationLimit = http2Connection.maxConcurrentStreams(); }}}Copy the code

The while True loop constructs a socket connection. When the socket connection is successfully constructed, EstablishProtocol (connectionSpecSelector, pingIntervalMillis, Call, eventListener) is called; Method, this is the main character of the whole article.

  private void establishProtocol(ConnectionSpecSelector connectionSpecSelector,
      int pingIntervalMillis, Call call, EventListener eventListener) throws IOException {
    if (route.address().sslSocketFactory() == null) {
      if (route.address().protocols().contains(Protocol.H2_PRIOR_KNOWLEDGE)) {
        socket = rawSocket;
        protocol = Protocol.H2_PRIOR_KNOWLEDGE;
        startHttp2(pingIntervalMillis);
        return;
      }

      socket = rawSocket;
      protocol = Protocol.HTTP_1_1;
      return;
    }

    eventListener.secureConnectStart(call);
    connectTls(connectionSpecSelector);
    eventListener.secureConnectEnd(call, handshake);

    if(protocol == Protocol.HTTP_2) { startHttp2(pingIntervalMillis); }}Copy the code

If you look at the last few lines of code, you already know. OKhttp will enable Http2.0 mode as long as the current protocol contains HTTP_2, otherwise it will degrade to 1.1 code. How to obtain the protocol is connectTls method, and the Tls process is in the method.

private void connectTls(ConnectionSpecSelector connectionSpecSelector) throws IOException {
    Address address = route.address();
    SSLSocketFactory sslSocketFactory = address.sslSocketFactory();
    boolean success = false;
    SSLSocket sslSocket = null;
    try {
      // Create the wrapper over the connected socket.
      sslSocket = (SSLSocket) sslSocketFactory.createSocket(
          rawSocket, address.url().host(), address.url().port(), true /* autoClose */);

      // Configure the socket's ciphers, TLS versions, and extensions.
      ConnectionSpec connectionSpec = connectionSpecSelector.configureSecureSocket(sslSocket);
      if (connectionSpec.supportsTlsExtensions()) {
        Platform.get().configureTlsExtensions(
            sslSocket, address.url().host(), address.protocols());
      }

      // Force handshake. This can throw!
      sslSocket.startHandshake();
      // block for session establishment
      SSLSession sslSocketSession = sslSocket.getSession();
      // Get HandShake information
      Handshake unverifiedHandshake = Handshake.get(sslSocketSession);

      // Verify that the socket's certificates are acceptable for the target host.
      if(! address.hostnameVerifier().verify(address.url().host(), sslSocketSession)) { List<Certificate> peerCertificates = unverifiedHandshake.peerCertificates();if(! peerCertificates.isEmpty()) { X509Certificate cert = (X509Certificate) peerCertificates.get(0);
          throw new SSLPeerUnverifiedException(
              "Hostname " + address.url().host() + " not verified:"
                  + "\n certificate: " + CertificatePinner.pin(cert)
                  + "\n DN: " + cert.getSubjectDN().getName()
                  + "\n subjectAltNames: " + OkHostnameVerifier.allSubjectAltNames(cert));
        } else {
          throw new SSLPeerUnverifiedException(
              "Hostname " + address.url().host() + " not verified (no certificates)"); }}// Check that the certificate pinner is satisfied by the certificates presented.
      address.certificatePinner().check(address.url().host(),
          unverifiedHandshake.peerCertificates());

      // Success! Save the handshake and the ALPN protocol.
      // Save HandShake and ALPN after success.
      String maybeProtocol = connectionSpec.supportsTlsExtensions()
          ? Platform.get().getSelectedProtocol(sslSocket)
          : null; socket = sslSocket; source = Okio.buffer(Okio.source(socket)); sink = Okio.buffer(Okio.sink(socket)); handshake = unverifiedHandshake; protocol = maybeProtocol ! =null
          ? Protocol.get(maybeProtocol)
          : Protocol.HTTP_1_1;
      success = true;
    } catch (AssertionError e) {
      if (Util.isAndroidGetsocknameError(e)) throw new IOException(e);
      throw e;
    } finally {
      if(sslSocket ! =null) {
        Platform.get().afterHandshake(sslSocket);
      }
      if(! success) { closeQuietly(sslSocket); }}}Copy the code

Okhttp was originally designed as a universal web library for the Java platform, and the underlying adaptation logic for Android is different for different Versions of Java. Okhttp abstracts all Tls and SSLSocket-related code, and then uses a Platform to reflect and call different implementation classes based on the current environment. This abstract class then calls Platform implementation class code to achieve multi-platform compatibility.

When SSLSocket is generated, client say Hello and server say Hello will be implemented in Tls, which is exactly the same as HTTPS. Handshake will bring back the Tls version supported by the server, encryption method, etc., and then use X509Certificate to verify the validity of the certificate with the unauthenticated Handshake. Platform is then used to obtain ALPN protocol support information from SSLSocket, and when the backend protocol contains Http2.0, the request is upgraded to the Http2.0 phase.

conclusion

In the learning process, it is best to think with questions, and then to do part of the source traceability, so that twice the result with half the effort, but also to eliminate part of the previous confusion, while deepening the memory.

I learned a lot about Https from blogs and stuff like that, and it was pretty much forgotten in a couple of days. It was also a slow process to get to 2.0. Basically, my former backend colleagues said we were already 2.0, and I could only say one thing.

Another point to note is that this article only covers front-facing operations, but you can read this article on HTTP 2.0 and OkHttp for framing operations.

In recent years, HTTPS and Http2.0 are basically high frequency interview questions. Hope the article can be helpful to everyone’s understanding. Finally, can you give me a thumbs up for my hot chicken project at Gayhub?