Upgrade to Pro — share decks privately, control downloads, hide ads and more …

unRESTful Web Services with HTTP/2

unRESTful Web Services with HTTP/2

HTTP/2, the new version of the HTTP protocol, provides a lot of new features for server-to-server communication:

* bidirectional communication using push requests
* multiplexing within a single TCP connection
* long running connections
* stateful connections

HTTP/2 does not define a JavaScript API, so JavaScript clients running in a Web browser can make only limited use of the new capabilities. However, for server-to-server communication, HTTP/2 provides a lot of ways to go beyond existing REST APIs.

This talk shows HTTP/2's potential for new server-to-server APIs.

---

HTTP/2 client used in demos: https://github.com/fstab/h2c

---

Devoxx 2015, http://cfp.devoxx.be/2015/agenda/conf/friday

Fabian Stäber

November 13, 2015
Tweet

More Decks by Fabian Stäber

Other Decks in Programming

Transcript

  1. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Contents • HTTP/2 Intro -> My First

    HTTP/2 Request • HTTP/2 new Features and how to use them in Java •  Multiplexing •  Server Push •  Stream Priorization and Flow Control • Testing HTTP/2-based REST services
  2. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Why HTTP/2? HTTP/2 is all about

    reducing latency: • Less protocol overhead • Header compression • Multiplexing • Request Priorization • Server Push
  3. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Compatibility with HTTP/1 HTTP/2 does not

    break the Web • Same semantics as HTTP/1 •  Request/response based communication •  HTTP Sessions and cookies • Goal: Any HTTP/1 application can be deployed on an HTTP/2 server without code change.
  4. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Switching Protocol with HTTP/1 Client Server

    TCP Connection SSL Handshake Ilya Grigorik hpbn.co HTTP/1 Upgrade Other Protocol, e.g. WebSocket
  5. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Switching Protocol with HTTP/2 Client Server

    TCP Connection SSL Handshake + ALPN Ilya Grigorik hpbn.co Other Protocol, e.g. HTTP/2
  6. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c • SSL is implemented in the JRE

    in package sun.security.ssl • Jetty provides ALPN version of sun.security.ssl for many OpenJDK 7 and 8 releases • Must start Java with VM parameter -Xbootclasspath/p:alpn-boot-VERSION.jar • ALPN will be part of Java 9 with JEP 244 Application Layer Protocol Negotiation ALPN
  7. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c @Override protected void doGet(HttpServletRequest req, HttpServletResponse

    resp) { resp.setContentType("text/plain"); resp.getWriter().write("Hello, World!"); } demo My First HTTP/2 Request: Example Servlet
  8. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c demo My First HTTP/2 Request: Server

    git clone https://github.com/fstab/http2-examples cd http2-examples/jetty-http2-server-example mvn package wget http://repo1.maven.org/maven2/org/mortbay/jetty/alpn/\ > alpn-boot/8.1.5.v20150921/alpn-boot-8.1.5.v20150921.jar java -Xbootclasspath/p:alpn-boot-8.1.5.v20150921.jar \ > -jar target/jetty-http2-server-example.jar
  9. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c • HTTP/2 is binary – telnet won‘t

    help • The curl command doesn‘t support server push messages yet. • Wrote my own little tool: https://github.com/fstab/h2c • h2c start –dump • h2c get https://localhost:8443 demo My First HTTP/2 Request: Client
  10. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c HTTP/2 output vs HTTP/1 output GET

    / HTTP/1.1 Host: localhost:8443 HTTP/1.1 200 OK Server: Jetty(9.3.3v20150827) Date: Fri, 16 Oct 2015 16:30:35 GMT Content-Type: text/plain;charset=iso-8859-1 {13 bytes}
  11. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c HTTP/2 output vs HTTP/1 output ->

    HEADERS(3) + END_STREAM + END_HEADERS :method: GET :scheme: https :authority: localhost:8443 :path: / <- HEADERS(3) - END_STREAM + END_HEADERS :status: 200 server: Jetty(9.3.3.v20150827) date: Fri, 16 Oct 2015 16:30:35 GMT content-type: text/plain;charset=iso-8859-1 <- DATA(3) + END_STREAM {13 bytes}
  12. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c GET /8-things-about-couchbase/ HTTP/1.1 Host: blog.arungupta.me Connection:

    keep-alive Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36 Referer: http://blog.arungupta.me/couchbase-javaone-2015/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed% 3A+MilesToGo+%28Miles+to+go+2.0%29 Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8,de;q=0.6,fr;q=0.4 Cookie: PHPSESSID=trr42cnr1u2ugekervdnkb4kc2; NCS_INENTIM=1445065465; JCS_INENREF=http%3A//t.co/UlzEpBg7wx; J CS_INENTIM=1445065466166; 1919598ddf048ef8060898ffee630b16=7bc66ae543ca8e475a2ec85a9c2e7d49; SJECT15=CKON1 5; __utma=202419266.948108038.1445065466.1445065466.1445065466.1; __utmb=202419266.2.10.1445065466; __utmc=202 419266; __utmz=202419266.1445065466.1.1.utmcsr=feedburner|utmccn=Feed:%20MilesToGo%20(Miles%20to%20go%202.0)|ut mcmd=feed Header Compression HPACK
  13. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Contents • HTTP/2 Intro -> My First

    HTTP/2 Request • HTTP/2 new Features and how to use them in Java •  Multiplexing •  Server Push •  Stream Priorization and Flow Control • Testing HTTP/2-based REST services
  14. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c demo Multiplexing for REST: Non-Blocking Services

    git clone https://github.com/fstab/http2-examples.git cd http2-examples/multiplexing-examples mvn package wget http://repo1.maven.org/maven2/org/mortbay/jetty/alpn/\ > alpn-boot/8.1.5.v20150921/alpn-boot-8.1.5.v20150921.jar java -Xbootclasspath/p:alpn-boot-8.1.5.v20150921.jar \ > -jar server/target/server.jar java -Xbootclasspath/p:alpn-boot-8.1.5.v20150921.jar \ > -jar okhttp-client/target/okhttp-client.jar
  15. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c @Override protected void doGet(HttpServletRequest req, HttpServletResponse

    resp) { // ... sleep(SECONDS.toMillis(6)); // ... } demo Multiplexing for REST: Non-Blocking Services
  16. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c HTTP URL Connection ... and is

    synchronous! Does not support HTTP/2 ... private void sendGet() throws Exception { URL url = new URL("https://www.twitter.com"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); try (BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream()))) { String line; while ((line = in.readLine()) != null) { System.out.println(line); } } }
  17. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c OkHttp Request request = new Request.Builder()

    .url("https://localhost:8443") .build(); client.newCall(request).enqueue(new Callback() { public void onResponse(Response response) throws IOException { // do something with response.body() } });
  18. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Netty FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1,

    GET, ""); request.headers().addObject(HOST, URI.create("https://localhost:8443")); channel.writeAndFlush(request); public class HttpResponseHandler extends SimpleChannelInboundHandler<FullHttpResponse> { @Override protected void messageReceived( ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception { // Do something with msg.content() ChannelPromise promise = streamidPromiseMap.get(streamId); promise.setSuccess(); } }
  19. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Jetty MetaData.Request request = new MetaData.Request(

    "GET", new HttpURI("https://localhost:8443/"), HTTP_2, requestFields); HeadersFrame headersFrame = new HeadersFrame(request, null, true); session.newStream(headersFrame, new FuturePromise<>(), responseListener); f Stream.Listener responseListener = new Stream.Listener.Adapter() { @Override public void onData(Stream stream, DataFrame frame, Callback callback) { // do something with frame.getData() callback.succeeded(); } };
  20. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Contents • HTTP/2 Intro -> My First

    HTTP/2 Request • HTTP/2 new Features and how to use them in Java •  Multiplexing •  Server Push •  Stream Priorization and Flow Control • HTTP/2 Client How-To
  21. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Push What it looks like: • 

    Request sent from client to server What actually happens: •  Push promise sent from server to client HTTP/2 is not a replacement for WebSockets.
  22. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Implicit Push for Web Servers How

    Web Servers use Push for delivering Web Pages: • For generated content (JSF): Should be possible to know which resources need to be pushed <h:graphicImage library="images" name=“awww.png" /> • For static content (HTML, Angular, ...): Learn from REFERER header (example included in Jetty as servlet filter).
  23. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Push and REST Example: How to

    trigger a push request in the Jetty server: Will be standardized with Servlet 4.0 !!! Request baseRequest = Request.getBaseRequest(req); if (baseRequest.isPushSupported()) { baseRequest .getPushBuilder() .method("GET") .path("/data") .push(); }
  24. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Push and REST Receive push request

    in client: Perform regular GET request, will be responded from the cache. HOWEVER: Client can be notified about the available response in an onPush() callback.
  25. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Push and REST Efficient Polling with

    HTTP/2 Server Push: • REST interface where client polls a resource • In case Server Push is supported, client polls not by time interval but polling is triggered by push message. • Fully compatible with REST semantics but much more efficient than polling with HTTP/1. • Makes workarounds like long polling, websockets, etc. obosolete.
  26. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c demo Push and REST git clone

    https://github.com/fstab/http2-examples.git cd http2-examples/jetty-http2-echo-server mvn package java -Xbootclasspath/p:alpn-boot-8.1.5.v20150921.jar \ > -jar target/jetty-http2-echo-server.jar h2c start --dump h2c post --data 'hello' https://localhost:8443/data h2c get https://localhost:8443/data
  27. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Push Demo <- PUSH_PROMISE(1) + END_HEADERS

    Promised Stream Id: 2 :scheme: https :method: GET :authority: localhost:8443 :path: /data content-length: 12 host: localhost:8443 x-http2-push: PushBuilder referer: https://localhost:8443/data demo
  28. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Contents • HTTP/2 Intro -> My First

    HTTP/2 Request • HTTP/2 new Features and how to use them in Java •  Multiplexing •  Server Push •  Stream Priorization and Flow Control • Testing HTTP/2-based REST services
  29. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Stream Priorization • HEADERS frame may contain

    stream dependency • PRIORITY frame contains Weight field • Api planned in Servlet 4.0 A B C
  30. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Flow Control • Based on WINDOW_UPDATE frames

    • Send up to n Bytes, then wait for WINDOW_UPDATE public interface FlowControlStrategy { public static int DEFAULT_WINDOW_SIZE = 65535; public void onDataReceived(ISession session, IStream stream, int length); public void onDataConsumed(ISession session, IStream stream, int length); public void onDataSent(IStream stream, int length); public void onSessionStalled(ISession session); public void onStreamStalled(IStream stream); // ... }
  31. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Contents • HTTP/2 Intro -> My First

    HTTP/2 Request • HTTP/2 new Features and how to use them in Java •  Multiplexing •  Server Push •  Stream Priorization and Flow Control • Testing HTTP/2-based REST services
  32. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Testing with Arquillian Cube <arquillian ...

    > <extension qualifier="docker"> <!-- REMOVE THE serverUri IF RUNNING ON LINUX --> <property name="serverUri">https://dockerHost:2376</property> <property name="dockerContainers"> wildfly-docker: image: fstab/wildfly-http2:9.0.1.Final await: strategy: polling sleepPollingTime: 1000 iterations: 120 portBindings: ["8443", "9990"] </property> </extension>
  33. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Testing with Arquillian Cube <container qualifier="wildfly-docker"

    default="true"> <configuration> <property name="managementAddress">dockerServerIp</property> <property name="managementPort">9990</property> <property name="username">admin</property> <property name="password">admin</property> </configuration> </container> </arquillian>
  34. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Testing with rhuss/docker-maven-plugin <plugin> <groupId>org.jolokia</groupId> <artifactId>docker-maven-plugin</artifactId>

    <version>${project.version}</version> <configuration> <images> <!-- Docker image to use --> </images> </configuration> <!-- . . . -->
  35. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Testing with rhuss/docker-maven-plugin <!-- . .

    . --> <executions> <execution> <phase>pre-integration-test</phase> <!– start the container --> </execution> <execution> <id>stop</id> <phase>post-integration-test</phase> <!– stop the container --> </execution> </executions> </plugin>
  36. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Testing with OkHttp MockWebServer @Test public

    void test() throws Exception { MockWebServer server = new MockWebServer(); SSLContext sslContext = new SslContextBuilder(getLocalHost().getHostName()).build(); server.useHttps(sslContext.getSocketFactory(), false); server.enqueue(new MockResponse().setBody("hello, world!")); server.enqueue(new MockResponse().setBody("sup, bra?")); server.enqueue(new MockResponse().setBody("yo dog")); server.start(); HttpUrl baseUrl = server.url("/v1/chat/"); // Start the client, connect to baseURL, run some tests. }
  37. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c Testing with OkHttp MockWebServer <plugin> <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-surefire-plugin</artifactId> <version>2.18.1</version> <configuration> <argLine>-Xbootclasspath/p:alpn-boot-8.1.5.v20150921.jar</argLine> </configuration> </plugin>
  38. @fstabr #Devoxx #unrestful https://github.com/fstab/h2c References • Adrian Cole, JavaZone 2015 https://vimeo.com/138955225

    • Simone Bordet, Voxxed Days Belgrade 2015 https://www.youtube.com/watch?v=ve3u00pw4V4 • Ilya Grigorik: High Performance Browser Networking, http://hpbn.co