blob: 51303584cdd4b6c4c236447e2c9cf4e8dd83cfd2 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.10">
<title>Eclipse Jetty: Programming Guide</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<link rel="stylesheet" href="./asciidoctor.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="../styles.css">
<link rel="stylesheet" href="../toc.css">
<script src="../toc.js"></script>
</head>
<body class="article toc2 toc-left">
<div id="header">
<h1><a href="https://eclipse.org/jetty">Eclipse Jetty</a>: Programming Guide</h1>
<div class="details">
<span id="author" class="author">Jetty Developers</span><br>
<span id="email" class="email"><a href="mailto:jetty-dev@eclipse.org">jetty-dev@eclipse.org</a></span><br>
<span id="revnumber">version 10.0.6,</span>
<span id="revdate">2021-06-29</span>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Jetty Programming Guide</div>
<ul class="sectlevel1">
<li><a href="#pg-eclipse-jetty-programming-guide">Eclipse Jetty Programming Guide</a></li>
<li><a href="#pg-client">Client Libraries</a>
<ul class="sectlevel2">
<li><a href="#pg-client-io-arch">Client Libraries I/O Architecture</a>
<ul class="sectlevel3">
<li><a href="#pg-client-io-arch-network">Client Libraries Network Layer</a></li>
<li><a href="#pg-client-io-arch-protocol">Client Libraries Protocol Layer</a></li>
</ul>
</li>
<li><a href="#pg-client-http">HTTP Client</a>
<ul class="sectlevel3">
<li><a href="#pg-client-http-intro">HttpClient Introduction</a></li>
<li><a href="#pg-client-http-start">Starting HttpClient</a></li>
<li><a href="#pg-client-http-stop">Stopping HttpClient</a></li>
<li><a href="#pg-client-http-arch">HttpClient Architecture</a></li>
<li><a href="#pg-client-http-connection-pool">HttpClient Connection Pooling</a></li>
<li><a href="#pg-client-http-request-processing">HttpClient Request Processing</a></li>
<li><a href="#pg-client-http-api">HttpClient API Usage</a>
<ul class="sectlevel4">
<li><a href="#pg-client-http-blocking">HttpClient Blocking APIs</a></li>
<li><a href="#pg-client-http-non-blocking">HttpClient Non-Blocking APIs</a></li>
<li><a href="#pg-client-http-content-request">Request Content Handling</a></li>
<li><a href="#pg-client-http-content-response">Response Content Handling</a></li>
</ul>
</li>
<li><a href="#pg-client-http-configuration">HttpClient Configuration</a>
<ul class="sectlevel4">
<li><a href="#pg-client-http-configuration-tls">HttpClient TLS Configuration</a>
<ul class="sectlevel5">
<li><a href="#pg-client-http-configuration-tls-truststore">HttpClient TLS TrustStore Configuration</a></li>
<li><a href="#pg-client-http-configuration-tls-client-certs">HttpClient TLS Client Certificates Configuration</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-client-http-cookie">HttpClient Cookie Support</a>
<ul class="sectlevel4">
<li><a href="#pg-special-characters-in-cookies">Special Characters in Cookies</a></li>
</ul>
</li>
<li><a href="#pg-client-http-authentication">HttpClient Authentication Support</a>
<ul class="sectlevel4">
<li><a href="#pg-client-http-authentication-spnego">HttpClient SPNEGO Authentication Support</a></li>
</ul>
</li>
<li><a href="#pg-client-http-proxy">HttpClient Proxy Support</a>
<ul class="sectlevel4">
<li><a href="#pg-client-http-proxy-authentication">Proxy Authentication Support</a></li>
</ul>
</li>
<li><a href="#pg-client-http-transport">HttpClient Pluggable Transports</a>
<ul class="sectlevel4">
<li><a href="#pg-client-http-transport-http11">HTTP/1.1 Transport</a></li>
<li><a href="#pg-client-http-transport-http2">HTTP/2 Transport</a></li>
<li><a href="#pg-client-http-transport-fcgi">FastCGI Transport</a></li>
<li><a href="#pg-client-http-transport-dynamic">Dynamic Transport</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-client-http2">HTTP/2 Client Library</a>
<ul class="sectlevel3">
<li><a href="#pg-client-http2-intro">Introducing HTTP2Client</a></li>
<li><a href="#pg-client-http2-flow-control">HTTP/2 Flow Control</a></li>
<li><a href="#pg-client-http2-connect">Connecting to the Server</a></li>
<li><a href="#pg-client-http2-configure">Configuring the Session</a></li>
<li><a href="#pg-client-http2-request">Sending a Request</a></li>
<li><a href="#pg-client-http2-response">Receiving a Response</a></li>
<li><a href="#pg-client-http2-reset">Resetting a Request or Response</a></li>
<li><a href="#pg-client-http2-push">Receiving HTTP/2 Pushes</a></li>
</ul>
</li>
<li><a href="#pg-client-websocket">WebSocket Client</a>
<ul class="sectlevel3">
<li><a href="#pg-client-websocket-start">Starting WebSocketClient</a></li>
<li><a href="#pg-client-websocket-stop">Stopping WebSocketClient</a></li>
<li><a href="#pg-client-websocket-connect">Connecting to a Remote Host</a>
<ul class="sectlevel4">
<li><a href="#pg-client-websocket-connect-http11">Using HTTP/1.1</a></li>
<li><a href="#pg-client-websocket-connect-http2">Using HTTP/2</a></li>
<li><a href="#pg-client-websocket-connect-custom-http-request">Customizing the Initial HTTP Request</a></li>
<li><a href="#pg-client-websocket-connect-inspect-http-response">Inspecting the Initial HTTP Response</a></li>
</ul>
</li>
<li><a href="#pg-websocket-architecture">WebSocket Architecture</a></li>
<li><a href="#pg-websocket-endpoints">WebSocket Endpoints</a>
<ul class="sectlevel4">
<li><a href="#pg-websocket-endpoints-listener">Listener Endpoints</a>
<ul class="sectlevel5">
<li><a href="#pg-message-streaming-reads">Message Streaming Reads</a></li>
</ul>
</li>
<li><a href="#pg-websocket-endpoints-annotated">Annotated Endpoints</a>
<ul class="sectlevel5">
<li><a href="#pg-message-streaming-reads-2">Message Streaming Reads</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-websocket-session">WebSocket Session</a>
<ul class="sectlevel4">
<li><a href="#pg-websocket-session-configure">Configuring the Session</a></li>
<li><a href="#pg-websocket-session-send">Sending Data</a>
<ul class="sectlevel5">
<li><a href="#pg-websocket-session-send-blocking">Blocking APIs</a></li>
<li><a href="#pg-websocket-session-send-non-blocking">Non-Blocking APIs</a></li>
<li><a href="#pg-websocket-session-send-stream">Streaming Send APIs</a></li>
</ul>
</li>
<li><a href="#pg-websocket-session-ping">Sending Ping/Pong</a></li>
<li><a href="#pg-websocket-session-close">Closing the Session</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-server">Server Libraries</a>
<ul class="sectlevel2">
<li><a href="#pg-server-compliance">Server Compliance Modes</a>
<ul class="sectlevel3">
<li><a href="#pg-server-compliance-http">HTTP Compliance Modes</a></li>
<li><a href="#pg-server-compliance-uri">URI Compliance Modes</a></li>
<li><a href="#pg-server-compliance-cookie">Cookie Compliance Modes</a></li>
</ul>
</li>
<li><a href="#pg-server-http">HTTP Server Libraries</a>
<ul class="sectlevel3">
<li><a href="#pg-server-http-request-processing">Server Request Processing</a>
<ul class="sectlevel4">
<li><a href="#pg-server-http-channel-events">HttpChannel Events</a></li>
</ul>
</li>
<li><a href="#pg-server-http-connector">Server Connectors</a>
<ul class="sectlevel4">
<li><a href="#pg-server-http-connector-protocol">Configuring Protocols</a>
<ul class="sectlevel5">
<li><a href="#pg-server-http-connector-protocol-http11">Clear-Text HTTP/1.1</a></li>
<li><a href="#pg-server-http-connector-protocol-http11-tls">Encrypted HTTP/1.1 (https)</a></li>
<li><a href="#pg-server-http-connector-protocol-http2">Clear-Text HTTP/2</a></li>
<li><a href="#pg-server-http-connector-protocol-http2-tls">Encrypted HTTP/2</a></li>
<li><a href="#pg-server-http-connector-protocol-proxy-http11">Jetty Behind a Load Balancer</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-server-http-handler">Server Handlers</a>
<ul class="sectlevel4">
<li><a href="#pg-server-http-handler-use">Jetty Handlers</a>
<ul class="sectlevel5">
<li><a href="#pg-server-http-handler-use-util-context">ContextHandler</a></li>
<li><a href="#pg-server-http-handler-use-util-context-collection">ContextHandlerCollection</a></li>
<li><a href="#pg-server-http-handler-use-util-resource-handler">ResourceHandler&#8201;&#8212;&#8201;Static Content</a></li>
<li><a href="#pg-server-http-handler-use-util-gzip-handler">GzipHandler</a></li>
<li><a href="#pg-server-http-handler-use-util-rewrite-handler">RewriteHandler</a></li>
<li><a href="#pg-server-http-handler-use-util-stats-handler">StatisticsHandler</a></li>
<li><a href="#pg-server-http-handler-use-util-secure-handler">SecuredRedirectHandler&#8201;&#8212;&#8201;Redirect from HTTP to HTTPS</a></li>
<li><a href="#pg-server-http-handler-use-util-default-handler">DefaultHandler</a></li>
</ul>
</li>
<li><a href="#pg-server-http-handler-use-servlet">Servlet API Handlers</a>
<ul class="sectlevel5">
<li><a href="#pg-server-http-handler-use-servlet-context">ServletContextHandler</a></li>
<li><a href="#pg-server-http-handler-use-webapp-context">WebAppContext</a></li>
<li><a href="#pg-server-http-handler-use-default-servlet">DefaultServlet&#8201;&#8212;&#8201;Static Content for Servlets</a></li>
</ul>
</li>
<li><a href="#pg-server-http-handler-implement">Implementing Handler</a>
<ul class="sectlevel5">
<li><a href="#pg-server-http-handler-impl-hello">Hello World Handler</a></li>
<li><a href="#pg-server-http-handler-impl-filter">Filtering Handler</a></li>
</ul>
</li>
<li><a href="#pg-server-http-security">Securing HTTP Server Applications</a></li>
<li><a href="#pg-server-http-application">Writing HTTP Server Applications</a>
<ul class="sectlevel5">
<li><a href="#pg-server-http-application-1xx">Sending 1xx Responses</a></li>
<li><a href="#pg-server-http-application-100">100 Continue</a></li>
<li><a href="#jetty-102-processing">102 Processing</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-server-http2">HTTP/2 Server Library</a>
<ul class="sectlevel3">
<li><a href="#pg-server-http2-intro">Introduction</a></li>
<li><a href="#pg-server-http2-flow-control">HTTP/2 Flow Control</a></li>
<li><a href="#pg-server-http2-setup">Server Setup</a></li>
<li><a href="#pg-server-http2-request">Receiving a Request</a></li>
<li><a href="#pg-server-http2-response">Sending a Response</a></li>
<li><a href="#pg-server-http2-reset">Resetting a Request</a></li>
<li><a href="#pg-server-http2-push">HTTP/2 Push of Resources</a></li>
</ul>
</li>
<li><a href="#pg-server-session">HTTP Session Management</a>
<ul class="sectlevel3">
<li><a href="#pg-server-session-architecture">Session Architecture</a></li>
<li><a href="#pg-server-session-idmgr">The SessionIdManager</a>
<ul class="sectlevel4">
<li><a href="#pg-server-session-defaultidmgr">The DefaultSessionIdManager</a></li>
</ul>
</li>
<li><a href="#pg-implementing-a-custom-sessionidmanager">Implementing a Custom SessionIdManager</a>
<ul class="sectlevel4">
<li><a href="#pg-server-session-housekeeper">The HouseKeeper</a></li>
</ul>
</li>
<li><a href="#pg-server-session-handler">The SessionHandler</a>
<ul class="sectlevel4">
<li><a href="#pg-configuration">Configuration</a></li>
<li><a href="#pg-statistics">Statistics</a></li>
</ul>
</li>
<li><a href="#pg-server-session-cache">The SessionCache</a>
<ul class="sectlevel4">
<li><a href="#pg-server-session-hash">The DefaultSessionCache</a></li>
<li><a href="#pg-server-session-null">The NullSessionCache</a></li>
<li><a href="#pg-server-session-customcache">Implementing a Custom SessionCache</a></li>
<li><a href="#pg-heterogeneous-caching">Heterogeneous Caching</a></li>
</ul>
</li>
<li><a href="#pg-server-session-datastore">The SessionDataStore</a>
<ul class="sectlevel4">
<li><a href="#pg-server-session-datastore-file">The FileSessionDataStore</a>
<ul class="sectlevel5">
<li><a href="#pg-configuration-2">Configuration</a></li>
</ul>
</li>
<li><a href="#pg-server-session-datastore-jdbc">The JDBCSessionDataStore</a>
<ul class="sectlevel5">
<li><a href="#pg-configuration-3">Configuration</a></li>
</ul>
</li>
<li><a href="#pg-server-session-datastore-mongo">The MongoSessionDataStore</a>
<ul class="sectlevel5">
<li><a href="#pg-configuration-4">Configuration</a></li>
</ul>
</li>
<li><a href="#pg-server-session-cachingsessiondatastore">The CachingSessionDataStore</a>
<ul class="sectlevel5">
<li><a href="#pg-configuration-5">Configuration</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-server-websocket">WebSocket Server Libraries</a></li>
<li><a href="#pg-server-io-arch">Server Libraries I/O Architecture</a>
<ul class="sectlevel3">
<li><a href="#pg-server-io-arch-connection-factory">Creating Connections with <code>ConnectionFactory</code></a></li>
<li><a href="#pg-server-io-arch-connection-factory-wrapping">Wrapping a <code>ConnectionFactory</code></a></li>
<li><a href="#pg-server-io-arch-connection-factory-detecting">Choosing <code>ConnectionFactory</code> via Bytes Detection</a></li>
<li><a href="#pg-server-io-arch-connection-factory-custom">Writing a Custom <code>ConnectionFactory</code></a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#maven-and-jetty">Maven and Jetty</a>
<ul class="sectlevel2">
<li><a href="#jetty-maven-helloworld">Using Maven</a>
<ul class="sectlevel3">
<li><a href="#configuring-embedded-jetty-with-maven">Using Embedded Jetty with Maven</a>
<ul class="sectlevel4">
<li><a href="#creating-helloworld-class">Creating the HelloWorld Class</a></li>
<li><a href="#creating-embedded-pom-descriptor">Creating the POM Descriptor</a></li>
<li><a href="#buildng-and-running-embedded-helloworld">Building and Running Embedded HelloWorld</a></li>
</ul>
</li>
<li><a href="#developing-standard-webapp-with-jetty-and-maven">Developing a Standard WebApp with Jetty and Maven</a>
<ul class="sectlevel4">
<li><a href="#creating-servlet">Creating a Servlet</a></li>
<li><a href="#creating-plugin-pom-descriptor">Creating the POM Descriptor</a></li>
<li><a href="#building-and-running-web-application">Building and Running the Web Application</a></li>
<li><a href="#building-war-file">Building a WAR file</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#jetty-maven-plugin">Using the Jetty Maven Plugin</a>
<ul class="sectlevel3">
<li><a href="#get-up-and-running">Get Up and Running</a></li>
<li><a href="#supported-goals">Supported Goals</a></li>
<li><a href="#deployment-modes">Deployment Modes</a>
<ul class="sectlevel4">
<li><a href="#pg-embedded">Embedded</a></li>
<li><a href="#pg-forked">Forked</a></li>
<li><a href="#pg-in-a-jetty-distribution">In a jetty distribution</a></li>
</ul>
</li>
<li><a href="#common-configuration">Common Configuration</a></li>
<li><a href="#container-classpath">Container Classpath vs WebApp Classpath</a></li>
<li><a href="#jetty-run-goal">jetty:run</a>
<ul class="sectlevel4">
<li><a href="#pg-configuration-6">Configuration</a></li>
</ul>
</li>
<li><a href="#jetty-run-war-goal">jetty:run-war</a>
<ul class="sectlevel4">
<li><a href="#pg-configuration-7">Configuration</a></li>
</ul>
</li>
<li><a href="#jetty-start-goal">jetty:start</a>
<ul class="sectlevel4">
<li><a href="#pg-configuration-8">Configuration</a></li>
</ul>
</li>
<li><a href="#jetty-start-war-goal">jetty:start-war</a>
<ul class="sectlevel4">
<li><a href="#pg-configuration-9">Configuration</a></li>
</ul>
</li>
<li><a href="#jetty-stop-goal">jetty:stop</a>
<ul class="sectlevel4">
<li><a href="#pg-configuration-10">Configuration</a></li>
</ul>
</li>
<li><a href="#jetty-effective-web-xml-goal">jetty:effective-web-xml</a>
<ul class="sectlevel4">
<li><a href="#pg-configuration-11">Configuration</a></li>
</ul>
</li>
<li><a href="#using-overlaid-wars">Using Overlaid wars</a>
<ul class="sectlevel4">
<li><a href="#pg-with-maven-war-plugin">With maven-war-plugin</a></li>
<li><a href="#pg-without-maven-war-plugin">Without maven-war-plugin</a></li>
</ul>
</li>
<li><a href="#configuring-security-settings">Configuring Security Settings</a></li>
<li><a href="#using-multiple-webapp-root-directories">Using Multiple Webapp Root Directories</a></li>
<li><a href="#running-more-than-one-webapp">Running More than One Webapp</a>
<ul class="sectlevel4">
<li><a href="#pg-with-jettyrun">With jetty:run</a></li>
</ul>
</li>
<li><a href="#setting-system-properties">Setting System Properties</a>
<ul class="sectlevel4">
<li><a href="#specifying-properties-in-pom">Specifying System Properties in the POM</a></li>
<li><a href="#specifying-properties-in-file">Specifying System Properties in a File</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#jetty-jspc-maven-plugin">Jetty Jspc Maven Plugin</a>
<ul class="sectlevel3">
<li><a href="#jspc-config">Configuration</a></li>
<li><a href="#jspc-production-precompile">Precompiling only for Production Build</a></li>
<li><a href="#jspc-overlay-precompile">Precompiling Jsps with Overlaid Wars</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-arch">Appendix A: Jetty Architecture</a>
<ul class="sectlevel2">
<li><a href="#pg-arch-bean">Jetty Component Architecture</a>
<ul class="sectlevel3">
<li><a href="#pg-arch-bean-lifecycle">Jetty Component Lifecycle</a></li>
<li><a href="#pg-arch-bean-listener">Jetty Component Listeners</a>
<ul class="sectlevel4">
<li><a href="#pg-arch-bean-listener-lifecycle">LifeCycle.Listener</a></li>
<li><a href="#pg-arch-bean-listener-container">Container.Listener</a></li>
<li><a href="#pg-arch-bean-listener-inherited">Container.InheritedListener</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-arch-io">Jetty I/O Architecture</a>
<ul class="sectlevel3">
<li><a href="#pg-arch-io-selector-manager">Jetty I/O: <code>SelectorManager</code></a></li>
<li><a href="#pg-arch-io-endpoint-connection">Jetty I/O: <code>EndPoint</code> and <code>Connection</code></a></li>
<li><a href="#pg-arch-io-endpoint">Jetty I/O: <code>EndPoint</code></a></li>
<li><a href="#pg-arch-io-connection">Jetty I/O: <code>Connection</code></a>
<ul class="sectlevel4">
<li><a href="#pg-arch-io-connection-listener">Jetty I/O: <code>Connection.Listener</code></a></li>
</ul>
</li>
<li><a href="#pg-arch-io-echo">Jetty I/O: Network Echo</a></li>
</ul>
</li>
<li><a href="#pg-arch-listener">Jetty Listeners</a></li>
<li><a href="#pg-arch-jmx">Jetty JMX Support</a>
<ul class="sectlevel3">
<li><a href="#pg-enabling-jmx-support">Enabling JMX Support</a></li>
<li><a href="#pg-arch-jmx-remote">Enabling JMX Remote Access</a>
<ul class="sectlevel4">
<li><a href="#pg-arch-jmx-remote-authorization">JMX Remote Access Authorization</a></li>
<li><a href="#pg-securing-jmx-remote-access-with-tls">Securing JMX Remote Access with TLS</a></li>
<li><a href="#pg-arch-jmx-remote-ssh-tunnel">JMX Remote Access with Port Forwarding via SSH Tunnel</a></li>
</ul>
</li>
<li><a href="#pg-arch-jmx-annotation">Jetty JMX Annotations</a>
<ul class="sectlevel4">
<li><a href="#pg-managedobject">@ManagedObject</a></li>
<li><a href="#pg-managedattribute">@ManagedAttribute</a></li>
<li><a href="#pg-managedoperation">@ManagedOperation</a></li>
<li><a href="#pg-name">@Name</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a href="#pg-troubleshooting">Appendix B: Troubleshooting Jetty</a>
<ul class="sectlevel2">
<li><a href="#pg-troubleshooting-logging">Logging</a>
<ul class="sectlevel3">
<li><a href="#pg-jetty-slf4j-binding">Jetty SLF4J Binding</a></li>
</ul>
</li>
<li><a href="#pg-troubleshooting-thread-dump">JVM Thread Dump</a></li>
<li><a href="#pg-troubleshooting-component-dump">Jetty Component Tree Dump</a></li>
<li><a href="#pg-troubleshooting-debugging">Debugging</a></li>
</ul>
</li>
<li><a href="#pg-migration">Appendix C: Migration Guides</a>
<ul class="sectlevel2">
<li><a href="#pg-migration-94-to-10">Migrating from Jetty 9.4.x to Jetty 10.0.x</a>
<ul class="sectlevel3">
<li><a href="#pg-migration-94-to-10-java-version">Required Java Version Changes</a></li>
<li><a href="#pg-migration-94-to-10-websocket">WebSocket Migration Guide</a>
<ul class="sectlevel4">
<li><a href="#pg-migration-94-to-10-websocket-maven-artifact-changes">Maven Artifacts Changes</a></li>
<li><a href="#pg-migration-94-to-10-websocket-class-name-changes">Class Names Changes</a></li>
<li><a href="#pg-migration-94-to-10-websocket-example-code">Example Code</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div id="content">
<div class="sect1">
<h2 id="pg-eclipse-jetty-programming-guide"><a class="anchor" href="#pg-eclipse-jetty-programming-guide"></a><a class="link" href="#pg-eclipse-jetty-programming-guide">Eclipse Jetty Programming Guide</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Eclipse Jetty Programming Guide targets developers who want to use the Eclipse Jetty libraries in their applications.</p>
</div>
<div class="paragraph">
<p>The Eclipse Jetty libraries provide the client-side and server-side APIs to work with various web protocols such as HTTP/1.1, HTTP/2, WebSocket and FastCGI.</p>
</div>
<div class="paragraph">
<p>You may use the <a href="#pg-client">Eclipse Jetty client-side library</a> in your application to make calls to third party REST services, or to other REST microservices in your system.</p>
</div>
<div class="paragraph">
<p>Likewise, you may use the <a href="#pg-server">Eclipse Jetty server-side library</a> to quickly create an HTTP or REST service without having to create a web application archive file (a <code>*.war</code> file) and without having to deploy it a Jetty standalone server that you would have to download and install.</p>
</div>
<div class="paragraph">
<p>This guide will walk you through the design of the Eclipse Jetty libraries and how to use its classes to write your applications.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="pg-client"><a class="anchor" href="#pg-client"></a><a class="link" href="#pg-client">Client Libraries</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Eclipse Jetty Project provides client-side libraries that allow you to embed a client in your applications.
A typical example is a client application that needs to contact a third party service via HTTP (for example a REST service).
Another example is a proxy application that receives HTTP requests and forwards them as FCGI requests to a PHP application such as WordPress, or receives HTTP/1.1 requests and converts them to HTTP/2.
Yet another example is a client application that needs to receive events from a WebSocket server.</p>
</div>
<div class="paragraph">
<p>The client libraries are designed to be non-blocking and offer both synchronous and asynchronous APIs and come with many configuration options.</p>
</div>
<div class="paragraph">
<p>These are the available client libraries:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#pg-client-http">The High-Level HTTP Client Library</a> for HTTP/1.1, HTTP/2 and FastCGI</p>
</li>
<li>
<p><a href="#pg-client-http2">The Low-Level HTTP/2 Client Library</a> for low-level HTTP/2</p>
</li>
<li>
<p><a href="#pg-client-websocket">The WebSocket client library</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If you are interested in the low-level details of how the Eclipse Jetty client libraries work, or are interested in writing a custom protocol, look at the <a href="#pg-client-io-arch">Client I/O Architecture</a>.</p>
</div>
<div class="sect2">
<h3 id="pg-client-io-arch"><a class="anchor" href="#pg-client-io-arch"></a><a class="link" href="#pg-client-io-arch">Client Libraries I/O Architecture</a></h3>
<div class="paragraph">
<p>The Jetty client libraries provide the basic components and APIs to implement a network client.</p>
</div>
<div class="paragraph">
<p>They build on the common <a href="#pg-arch-io">Jetty I/O Architecture</a> and provide client specific concepts (such as establishing a connection to a server).</p>
</div>
<div class="paragraph">
<p>There are conceptually two layers that compose the Jetty client libraries:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><a href="#pg-client-io-arch-network">The network layer</a>, that handles the low level I/O and deals with buffers, threads, etc.</p>
</li>
<li>
<p><a href="#pg-client-io-arch-protocol">The protocol layer</a>, that handles the parsing of bytes read from the network and the generation of bytes to write to the network.</p>
</li>
</ol>
</div>
<div class="sect3">
<h4 id="pg-client-io-arch-network"><a class="anchor" href="#pg-client-io-arch-network"></a><a class="link" href="#pg-client-io-arch-network">Client Libraries Network Layer</a></h4>
<div class="paragraph">
<p>The Jetty client libraries use the common I/O design described in <a href="#pg-arch-io">this section</a>.
The main client-side component is the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/ClientConnector.html"><code>ClientConnector</code></a>.</p>
</div>
<div class="paragraph">
<p>The <code>ClientConnector</code> primarily wraps the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/SelectorManager.html"><code>SelectorManager</code></a> and aggregates other four components:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>a thread pool (in form of an <code>java.util.concurrent.Executor</code>)</p>
</li>
<li>
<p>a scheduler (in form of <code>org.eclipse.jetty.util.thread.Scheduler</code>)</p>
</li>
<li>
<p>a byte buffer pool (in form of <code>org.eclipse.jetty.io.ByteBufferPool</code>)</p>
</li>
<li>
<p>a TLS factory (in form of <code>org.eclipse.jetty.util.ssl.SslContextFactory.Client</code>)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>ClientConnector</code> is where you want to set those components after you have configured them.
If you don&#8217;t explicitly set those components on the <code>ClientConnector</code>, then appropriate defaults will be chosen when the <code>ClientConnector</code> starts.</p>
</div>
<div class="paragraph">
<p>The simplest example that creates and starts a <code>ClientConnector</code> is the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ClientConnector clientConnector = <span class="keyword">new</span> ClientConnector();
clientConnector.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>A more typical example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create and configure the SslContextFactory.</span>
SslContextFactory.Client sslContextFactory = <span class="keyword">new</span> SslContextFactory.Client();
sslContextFactory.addExcludeProtocols(<span class="string"><span class="delimiter">&quot;</span><span class="content">TLSv1</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">TLSv1.1</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Create and configure the thread pool.</span>
QueuedThreadPool threadPool = <span class="keyword">new</span> QueuedThreadPool();
threadPool.setName(<span class="string"><span class="delimiter">&quot;</span><span class="content">client</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Create and configure the ClientConnector.</span>
ClientConnector clientConnector = <span class="keyword">new</span> ClientConnector();
clientConnector.setSslContextFactory(sslContextFactory);
clientConnector.setExecutor(threadPool);
clientConnector.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>A more advanced example that customizes the <code>ClientConnector</code> by overriding some of its methods:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">CustomClientConnector</span> <span class="directive">extends</span> ClientConnector
{
<span class="annotation">@Override</span>
<span class="directive">protected</span> SelectorManager newSelectorManager()
{
<span class="keyword">return</span> <span class="keyword">new</span> ClientSelectorManager(getExecutor(), getScheduler(), getSelectors())
{
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> endPointOpened(EndPoint endpoint)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">endpoint</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">opened %s</span><span class="delimiter">&quot;</span></span>, endpoint);
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> endPointClosed(EndPoint endpoint)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">endpoint</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">closed %s</span><span class="delimiter">&quot;</span></span>, endpoint);
}
};
}
}
<span class="comment">// Create and configure the thread pool.</span>
QueuedThreadPool threadPool = <span class="keyword">new</span> QueuedThreadPool();
threadPool.setName(<span class="string"><span class="delimiter">&quot;</span><span class="content">client</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Create and configure the scheduler.</span>
Scheduler scheduler = <span class="keyword">new</span> ScheduledExecutorScheduler(<span class="string"><span class="delimiter">&quot;</span><span class="content">scheduler-client</span><span class="delimiter">&quot;</span></span>, <span class="predefined-constant">false</span>);
<span class="comment">// Create and configure the custom ClientConnector.</span>
CustomClientConnector clientConnector = <span class="keyword">new</span> CustomClientConnector();
clientConnector.setExecutor(threadPool);
clientConnector.setScheduler(scheduler);
clientConnector.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Since <code>ClientConnector</code> is the component that handles the low-level network, it is also the component where you want to configure the low-level network configuration.</p>
</div>
<div class="paragraph">
<p>The most common parameters are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>ClientConnector.selectors</code>: the number of <code>java.nio.Selector</code>s components (defaults to <code>1</code>) that are present to handle the <code>SocketChannel</code>s opened by the <code>ClientConnector</code>.
You typically want to increase the number of selectors only for those use cases where each selector should handle more than few hundreds <em>concurrent</em> socket events.
For example, one selector typically runs well for <code>250</code> <em>concurrent</em> socket events; as a rule of thumb, you can multiply that number by <code>10</code> to obtain the number of opened sockets a selector can handle (<code>2500</code>), based on the assumption that not all the <code>2500</code> sockets will be active <em>at the same time</em>.</p>
</li>
<li>
<p><code>ClientConnector.idleTimeout</code>: the duration of time after which <code>ClientConnector</code> closes a socket due to inactivity (defaults to <code>30</code> seconds).
This is an important parameter to configure, and you typically want the client idle timeout to be shorter than the server idle timeout, to avoid race conditions where the client attempts to use a socket just before the client-side idle timeout expires, but the server-side idle timeout has already expired and the is already closing the socket.</p>
</li>
<li>
<p><code>ClientConnector.connectBlocking</code>: whether the operation of connecting a socket to the server (i.e. <code>SocketChannel.connect(SocketAddress)</code>) must be a blocking or a non-blocking operation (defaults to <code>false</code>).
For <code>localhost</code> or same datacenter hosts you want to set this parameter to
<code>true</code> because DNS resolution will be immediate (and likely never fail).
For generic Internet hosts (e.g. when you are implementing a web spider) you want to set this parameter to <code>false</code>.</p>
</li>
<li>
<p><code>ClientConnector.connectTimeout</code>: the duration of time after which <code>ClientConnector</code> aborts a connection attempt to the server (defaults to <code>5</code> seconds).
This time includes the DNS lookup time <em>and</em> the TCP connect time.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Please refer to the <code>ClientConnector</code> <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/ClientConnector.html">javadocs</a> for the complete list of configurable parameters.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-io-arch-protocol"><a class="anchor" href="#pg-client-io-arch-protocol"></a><a class="link" href="#pg-client-io-arch-protocol">Client Libraries Protocol Layer</a></h4>
<div class="paragraph">
<p>The protocol layer builds on top of the network layer to generate the bytes to be written to the network and to parse the bytes read from the network.</p>
</div>
<div class="paragraph">
<p>Recall from <a href="#pg-arch-io-connection">this section</a> that Jetty uses the <code>Connection</code> abstraction to produce and interpret the network bytes.</p>
</div>
<div class="paragraph">
<p>On the client side, a <code>ClientConnectionFactory</code> implementation is the component that creates <code>Connection</code> instances based on the protocol that the client wants to "speak" with the server.</p>
</div>
<div class="paragraph">
<p>Applications use <code>ClientConnector.connect(SocketAddress, Map&lt;String, Object&gt;)</code> to establish a TCP connection to the server, and must tell <code>ClientConnector</code> how to create the <code>Connection</code> for that particular TCP connection, and how to notify back the application when the connection creation succeeds or fails.</p>
</div>
<div class="paragraph">
<p>This is done by passing a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/ClientConnectionFactory.html"><code>ClientConnectionFactory</code></a> (that creates <code>Connection</code> instances) and a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/util/Promise.html"><code>Promise</code></a> (that is notified of connection creation success or failure) in the context <code>Map</code> as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">CustomConnection</span> <span class="directive">extends</span> AbstractConnection
{
<span class="directive">public</span> CustomConnection(EndPoint endPoint, <span class="predefined-type">Executor</span> executor)
{
<span class="local-variable">super</span>(endPoint, executor);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onOpen()
{
<span class="local-variable">super</span>.onOpen();
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">connection</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Opened connection {0}</span><span class="delimiter">&quot;</span></span>, <span class="local-variable">this</span>);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onFillable()
{
}
}
ClientConnector clientConnector = <span class="keyword">new</span> ClientConnector();
clientConnector.start();
<span class="predefined-type">String</span> host = <span class="string"><span class="delimiter">&quot;</span><span class="content">serverHost</span><span class="delimiter">&quot;</span></span>;
<span class="type">int</span> port = <span class="integer">8080</span>;
<span class="predefined-type">SocketAddress</span> address = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(host, port);
<span class="comment">// The ClientConnectionFactory that creates CustomConnection instances.</span>
ClientConnectionFactory connectionFactory = (endPoint, context) -&gt;
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">connection</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Creating connection for {0}</span><span class="delimiter">&quot;</span></span>, endPoint);
<span class="keyword">return</span> <span class="keyword">new</span> CustomConnection(endPoint, clientConnector.getExecutor());
};
<span class="comment">// The Promise to notify of connection creation success or failure.</span>
CompletableFuture&lt;CustomConnection&gt; connectionPromise = <span class="keyword">new</span> Promise.Completable&lt;&gt;();
<span class="comment">// Populate the context with the mandatory keys to create and obtain connections.</span>
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; context = <span class="keyword">new</span> <span class="predefined-type">HashMap</span>&lt;&gt;();
context.put(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, connectionFactory);
context.put(ClientConnector.CONNECTION_PROMISE_CONTEXT_KEY, connectionPromise);
clientConnector.connect(address, context);
<span class="comment">// Use the Connection when it's available.</span>
<span class="comment">// Use it in a non-blocking way via CompletableFuture APIs.</span>
connectionPromise.whenComplete((connection, failure) -&gt;
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">connection</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Created connection for {0}</span><span class="delimiter">&quot;</span></span>, connection);
});
<span class="comment">// Alternatively, you can block waiting for the connection (or a failure).</span>
<span class="comment">// CustomConnection connection = connectionPromise.get();</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>When a <code>Connection</code> is created successfully, its <code>onOpen()</code> method is invoked, and then the promise is completed successfully.</p>
</div>
<div class="paragraph">
<p>It is now possible to write a super-simple <code>telnet</code> client that reads and writes string lines:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">TelnetConnection</span> <span class="directive">extends</span> AbstractConnection
{
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">ByteArrayOutputStream</span> bytes = <span class="keyword">new</span> <span class="predefined-type">ByteArrayOutputStream</span>();
<span class="directive">private</span> Consumer&lt;<span class="predefined-type">String</span>&gt; consumer;
<span class="directive">public</span> TelnetConnection(EndPoint endPoint, <span class="predefined-type">Executor</span> executor)
{
<span class="local-variable">super</span>(endPoint, executor);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onOpen()
{
<span class="local-variable">super</span>.onOpen();
<span class="comment">// Declare interest for fill events.</span>
fillInterested();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onFillable()
{
<span class="keyword">try</span>
{
<span class="predefined-type">ByteBuffer</span> buffer = BufferUtil.allocate(<span class="integer">1024</span>);
<span class="keyword">while</span> (<span class="predefined-constant">true</span>)
{
<span class="type">int</span> filled = getEndPoint().fill(buffer);
<span class="keyword">if</span> (filled &gt; <span class="integer">0</span>)
{
<span class="keyword">while</span> (buffer.hasRemaining())
{
<span class="comment">// Search for newline.</span>
<span class="type">byte</span> read = buffer.get();
<span class="keyword">if</span> (read == <span class="string"><span class="delimiter">'</span><span class="content">\n</span><span class="delimiter">'</span></span>)
{
<span class="comment">// Notify the consumer of the line.</span>
consumer.accept(bytes.toString(StandardCharsets.UTF_8));
bytes.reset();
}
<span class="keyword">else</span>
{
bytes.write(read);
}
}
}
<span class="keyword">else</span> <span class="keyword">if</span> (filled == <span class="integer">0</span>)
{
<span class="comment">// No more bytes to fill, declare</span>
<span class="comment">// again interest for fill events.</span>
fillInterested();
<span class="keyword">return</span>;
}
<span class="keyword">else</span>
{
<span class="comment">// The other peer closed the</span>
<span class="comment">// connection, close it back.</span>
getEndPoint().close();
<span class="keyword">return</span>;
}
}
}
<span class="keyword">catch</span> (<span class="exception">Exception</span> x)
{
getEndPoint().close(x);
}
}
<span class="directive">public</span> <span class="type">void</span> onLine(Consumer&lt;<span class="predefined-type">String</span>&gt; consumer)
{
<span class="local-variable">this</span>.consumer = consumer;
}
<span class="directive">public</span> <span class="type">void</span> writeLine(<span class="predefined-type">String</span> line, <span class="predefined-type">Callback</span> callback)
{
line = line + <span class="string"><span class="delimiter">&quot;</span><span class="char">\r</span><span class="char">\n</span><span class="delimiter">&quot;</span></span>;
getEndPoint().write(callback, <span class="predefined-type">ByteBuffer</span>.wrap(line.getBytes(StandardCharsets.UTF_8)));
}
}
ClientConnector clientConnector = <span class="keyword">new</span> ClientConnector();
clientConnector.start();
<span class="predefined-type">String</span> host = <span class="string"><span class="delimiter">&quot;</span><span class="content">wikipedia.org</span><span class="delimiter">&quot;</span></span>;
<span class="type">int</span> port = <span class="integer">80</span>;
<span class="predefined-type">SocketAddress</span> address = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(host, port);
ClientConnectionFactory connectionFactory = (endPoint, context) -&gt;
<span class="keyword">new</span> TelnetConnection(endPoint, clientConnector.getExecutor());
CompletableFuture&lt;TelnetConnection&gt; connectionPromise = <span class="keyword">new</span> Promise.Completable&lt;&gt;();
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; context = <span class="keyword">new</span> <span class="predefined-type">HashMap</span>&lt;&gt;();
context.put(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, connectionFactory);
context.put(ClientConnector.CONNECTION_PROMISE_CONTEXT_KEY, connectionPromise);
clientConnector.connect(address, context);
connectionPromise.whenComplete((connection, failure) -&gt;
{
<span class="keyword">if</span> (failure == <span class="predefined-constant">null</span>)
{
<span class="comment">// Register a listener that receives string lines.</span>
connection.onLine(line -&gt; <span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">app</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">line: {0}</span><span class="delimiter">&quot;</span></span>, line));
<span class="comment">// Write a line.</span>
connection.writeLine(<span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">GET / HTTP/1.0</span><span class="char">\r</span><span class="char">\n</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span>, <span class="predefined-type">Callback</span>.NOOP);
}
<span class="keyword">else</span>
{
failure.printStackTrace();
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how a very basic "telnet" API that applications could use is implemented in the form of the <code>onLine(Consumer&lt;String&gt;)</code> for the non-blocking receiving side and <code>writeLine(String, Callback)</code> for the non-blocking sending side.
Note also how the <code>onFillable()</code> method implements some basic "parsing" by looking up the <code>\n</code> character in the buffer.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The "telnet" client above looks like a super-simple HTTP client because HTTP/1.0 can be seen as a line-based protocol.
HTTP/1.0 was used just as an example, but we could have used any other line-based protocol such as <a href="https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">SMTP</a>, provided that the server was able to understand it.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This is very similar to what the Jetty client implementation does for real network protocols.
Real network protocols are of course more complicated and so is the implementation code that handles them, but the general ideas are similar.</p>
</div>
<div class="paragraph">
<p>The Jetty client implementation provides a number of <code>ClientConnectionFactory</code> implementations that can be composed to produce and interpret the network bytes.</p>
</div>
<div class="paragraph">
<p>For example, it is simple to modify the above example to use the TLS protocol so that you will be able to connect to the server on port <code>443</code>, typically reserved for the encrypted HTTP protocol.</p>
</div>
<div class="paragraph">
<p>The differences between the clear-text version and the TLS encrypted version are minimal:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">TelnetConnection</span> <span class="directive">extends</span> AbstractConnection
{
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">ByteArrayOutputStream</span> bytes = <span class="keyword">new</span> <span class="predefined-type">ByteArrayOutputStream</span>();
<span class="directive">private</span> Consumer&lt;<span class="predefined-type">String</span>&gt; consumer;
<span class="directive">public</span> TelnetConnection(EndPoint endPoint, <span class="predefined-type">Executor</span> executor)
{
<span class="local-variable">super</span>(endPoint, executor);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onOpen()
{
<span class="local-variable">super</span>.onOpen();
<span class="comment">// Declare interest for fill events.</span>
fillInterested();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onFillable()
{
<span class="keyword">try</span>
{
<span class="predefined-type">ByteBuffer</span> buffer = BufferUtil.allocate(<span class="integer">1024</span>);
<span class="keyword">while</span> (<span class="predefined-constant">true</span>)
{
<span class="type">int</span> filled = getEndPoint().fill(buffer);
<span class="keyword">if</span> (filled &gt; <span class="integer">0</span>)
{
<span class="keyword">while</span> (buffer.hasRemaining())
{
<span class="comment">// Search for newline.</span>
<span class="type">byte</span> read = buffer.get();
<span class="keyword">if</span> (read == <span class="string"><span class="delimiter">'</span><span class="content">\n</span><span class="delimiter">'</span></span>)
{
<span class="comment">// Notify the consumer of the line.</span>
consumer.accept(bytes.toString(StandardCharsets.UTF_8));
bytes.reset();
}
<span class="keyword">else</span>
{
bytes.write(read);
}
}
}
<span class="keyword">else</span> <span class="keyword">if</span> (filled == <span class="integer">0</span>)
{
<span class="comment">// No more bytes to fill, declare</span>
<span class="comment">// again interest for fill events.</span>
fillInterested();
<span class="keyword">return</span>;
}
<span class="keyword">else</span>
{
<span class="comment">// The other peer closed the</span>
<span class="comment">// connection, close it back.</span>
getEndPoint().close();
<span class="keyword">return</span>;
}
}
}
<span class="keyword">catch</span> (<span class="exception">Exception</span> x)
{
getEndPoint().close(x);
}
}
<span class="directive">public</span> <span class="type">void</span> onLine(Consumer&lt;<span class="predefined-type">String</span>&gt; consumer)
{
<span class="local-variable">this</span>.consumer = consumer;
}
<span class="directive">public</span> <span class="type">void</span> writeLine(<span class="predefined-type">String</span> line, <span class="predefined-type">Callback</span> callback)
{
line = line + <span class="string"><span class="delimiter">&quot;</span><span class="char">\r</span><span class="char">\n</span><span class="delimiter">&quot;</span></span>;
getEndPoint().write(callback, <span class="predefined-type">ByteBuffer</span>.wrap(line.getBytes(StandardCharsets.UTF_8)));
}
}
ClientConnector clientConnector = <span class="keyword">new</span> ClientConnector();
clientConnector.start();
<span class="comment">// Use port 443 to contact the server using encrypted HTTP.</span>
<span class="predefined-type">String</span> host = <span class="string"><span class="delimiter">&quot;</span><span class="content">wikipedia.org</span><span class="delimiter">&quot;</span></span>;
<span class="type">int</span> port = <span class="integer">443</span>;
<span class="predefined-type">SocketAddress</span> address = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(host, port);
ClientConnectionFactory connectionFactory = (endPoint, context) -&gt;
<span class="keyword">new</span> TelnetConnection(endPoint, clientConnector.getExecutor());
<span class="comment">// Wrap the &quot;telnet&quot; ClientConnectionFactory with the SslClientConnectionFactory.</span>
connectionFactory = <span class="keyword">new</span> SslClientConnectionFactory(clientConnector.getSslContextFactory(),
clientConnector.getByteBufferPool(), clientConnector.getExecutor(), connectionFactory);
<span class="comment">// We will obtain a SslConnection now.</span>
CompletableFuture&lt;SslConnection&gt; connectionPromise = <span class="keyword">new</span> Promise.Completable&lt;&gt;();
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; context = <span class="keyword">new</span> <span class="predefined-type">HashMap</span>&lt;&gt;();
context.put(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, connectionFactory);
context.put(ClientConnector.CONNECTION_PROMISE_CONTEXT_KEY, connectionPromise);
clientConnector.connect(address, context);
connectionPromise.whenComplete((sslConnection, failure) -&gt;
{
<span class="keyword">if</span> (failure == <span class="predefined-constant">null</span>)
{
<span class="comment">// Unwrap the SslConnection to access the &quot;line&quot; APIs in TelnetConnection.</span>
TelnetConnection connection = (TelnetConnection)sslConnection.getDecryptedEndPoint().getConnection();
<span class="comment">// Register a listener that receives string lines.</span>
connection.onLine(line -&gt; <span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">app</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">line: {0}</span><span class="delimiter">&quot;</span></span>, line));
<span class="comment">// Write a line.</span>
connection.writeLine(<span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">GET / HTTP/1.0</span><span class="char">\r</span><span class="char">\n</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span>, <span class="predefined-type">Callback</span>.NOOP);
}
<span class="keyword">else</span>
{
failure.printStackTrace();
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>The differences with the clear-text version are only:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Change the port from <code>80</code> to <code>443</code>.</p>
</li>
<li>
<p>Wrap the <code>ClientConnectionFactory</code> with <code>SslClientConnectionFactory</code>.</p>
</li>
<li>
<p>Unwrap the <code>SslConnection</code> to access <code>TelnetConnection</code>.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-client-http"><a class="anchor" href="#pg-client-http"></a><a class="link" href="#pg-client-http">HTTP Client</a></h3>
<div class="sect3">
<h4 id="pg-client-http-intro"><a class="anchor" href="#pg-client-http-intro"></a><a class="link" href="#pg-client-http-intro">HttpClient Introduction</a></h4>
<div class="paragraph">
<p>The Jetty HTTP client module provides easy-to-use APIs and utility classes to perform HTTP (or HTTPS) requests.</p>
</div>
<div class="paragraph">
<p>Jetty&#8217;s HTTP client is non-blocking and asynchronous.
It offers an asynchronous API that never blocks for I/O, making it very efficient in thread utilization and well suited for high performance scenarios such as load testing or parallel computation.</p>
</div>
<div class="paragraph">
<p>However, when all you need to do is to perform a <code>GET</code> request to a resource, Jetty&#8217;s HTTP client offers also a synchronous API; a programming interface where the thread that issued the request blocks until the request/response conversation is complete.</p>
</div>
<div class="paragraph">
<p>Jetty&#8217;s HTTP client supports <a href="#pg-client-http-transport">different transports</a>: HTTP/1.1, FastCGI and HTTP/2. This means that the semantic of an HTTP request: " <code>GET</code> the resource <code>/index.html</code> " can be carried over the network in different formats.
The most common and default format is HTTP/1.1. That said, Jetty&#8217;s HTTP client can carry the same request using the FastCGI format or the HTTP/2 format.</p>
</div>
<div class="paragraph">
<p>The <a href="#pg-client-http-transport-fcgi">FastCGI transport</a> is heavily used in Jetty&#8217;s <a href="#fastcgi">FastCGI support</a> that allows Jetty to work as a reverse proxy to PHP (exactly like Apache or Nginx do) and therefore be able to serve, for example, WordPress websites.</p>
</div>
<div class="paragraph">
<p>The HTTP/2 transport allows Jetty&#8217;s HTTP client to perform requests using HTTP/2 to HTTP/2 enabled web sites, see also Jetty&#8217;s <a href="#pg-client-http2">HTTP/2 support</a>.</p>
</div>
<div class="paragraph">
<p>Out of the box features that you get with the Jetty HTTP client include:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Redirect support&#8201;&#8212;&#8201;redirect codes such as 302 or 303 are automatically followed.</p>
</li>
<li>
<p>Cookies support&#8201;&#8212;&#8201;cookies sent by servers are stored and sent back to servers in matching requests.</p>
</li>
<li>
<p>Authentication support&#8201;&#8212;&#8201;HTTP "Basic", "Digest" and "SPNEGO" authentications are supported, others are pluggable.</p>
</li>
<li>
<p>Forward proxy support&#8201;&#8212;&#8201;HTTP proxying and SOCKS4 proxying.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-start"><a class="anchor" href="#pg-client-http-start"></a><a class="link" href="#pg-client-http-start">Starting HttpClient</a></h4>
<div class="paragraph">
<p>The Jetty artifact that provides the main HTTP client implementation is <code>jetty-client</code>.
The Maven artifact coordinates are the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-client<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The main class is named <code>org.eclipse.jetty.client.HttpClient</code>.</p>
</div>
<div class="paragraph">
<p>You can think of a <code>HttpClient</code> instance as a browser instance.
Like a browser it can make requests to different domains, it manages redirects, cookies and authentication, you can configure it with a proxy, and it provides you with the responses to the requests you make.</p>
</div>
<div class="paragraph">
<p>In order to use <code>HttpClient</code>, you must instantiate it, configure it, and then start it:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Instantiate HttpClient.</span>
HttpClient httpClient = <span class="keyword">new</span> HttpClient();
<span class="comment">// Configure HttpClient, for example:</span>
httpClient.setFollowRedirects(<span class="predefined-constant">false</span>);
<span class="comment">// Start HttpClient.</span>
httpClient.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>You may create multiple instances of <code>HttpClient</code>, but typically one instance is enough for an application.
There are several reasons for having multiple <code>HttpClient</code> instances including, but not limited to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>You want to specify different configuration parameters (for example, one instance is configured with a forward proxy while another is not).</p>
</li>
<li>
<p>You want the two instances to behave like two different browsers and hence have different cookies, different authentication credentials, etc.</p>
</li>
<li>
<p>You want to use <a href="#pg-client-http-transport">different transports</a>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Like browsers, HTTPS requests are supported out-of-the-box (see <a href="#pg-client-http-configuration-tls">this section</a> for the TLS configuration), as long as the server provides a valid certificate.
In case the server does not provide a valid certificate (or in case it is self-signed) you want to customize <code>HttpClient</code>'s TLS configuration as described in <a href="#pg-client-http-configuration-tls">this section</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-stop"><a class="anchor" href="#pg-client-http-stop"></a><a class="link" href="#pg-client-http-stop">Stopping HttpClient</a></h4>
<div class="paragraph">
<p>It is recommended that when your application stops, you also stop the <code>HttpClient</code> instance (or instances) that you are using.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Stop HttpClient.</span>
httpClient.stop();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Stopping <code>HttpClient</code> makes sure that the memory it holds (for example, authentication credentials, cookies, etc.) is released, and that the thread pool and scheduler are properly stopped allowing all threads used by <code>HttpClient</code> to exit.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>You cannot call <code>HttpClient.stop()</code> from one of its own threads, as it would cause a deadlock.
It is recommended that you stop <code>HttpClient</code> from an unrelated thread, or from a newly allocated thread, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Stop HttpClient from a new thread.</span>
<span class="comment">// Use LifeCycle.stop(...) to rethrow checked exceptions as unchecked.</span>
<span class="keyword">new</span> <span class="predefined-type">Thread</span>(() -&gt; LifeCycle.stop(httpClient)).start();</code></pre>
</div>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-arch"><a class="anchor" href="#pg-client-http-arch"></a><a class="link" href="#pg-client-http-arch">HttpClient Architecture</a></h4>
<div class="paragraph">
<p>A <code>HttpClient</code> instance can be thought as a browser instance, and it manages the following components:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>a <code>CookieStore</code> (see <a href="#pg-client-http-cookie">this section</a>).</p>
</li>
<li>
<p>a <code>AuthenticationStore</code> (see <a href="#pg-client-http-authentication">this section</a>).</p>
</li>
<li>
<p>a <code>ProxyConfiguration</code> (see <a href="#pg-client-http-proxy">this section</a>).</p>
</li>
<li>
<p>a set of <em>destinations</em>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>A <em>destination</em> is the client-side component that represents an <em>origin</em> server, and manages a queue of requests for that origin, and a <a href="#pg-client-http-connection-pool">pool of TCP connections</a> to that origin.</p>
</div>
<div class="paragraph">
<p>An <em>origin</em> may be simply thought as the tuple <code>(scheme, host, port)</code> and it is where the client connects to in order to communicate with the server.
However, this is not enough.</p>
</div>
<div class="paragraph">
<p>If you use <code>HttpClient</code> to write a proxy you may have different clients that want to contact the same server.
In this case, you may not want to use the same proxy-to-server connection to proxy requests for both clients, for example for authentication reasons: the server may associate the connection with authentication credentials and you do not want to use the same connection for two different users that have different credentials.
Instead, you want to use different connections for different clients and this can be achieved by "tagging" a destination with a tag object that represents the remote client (for example, it could be the remote client IP address).</p>
</div>
<div class="paragraph">
<p>Two origins with the same <code>(scheme, host, port)</code> but different <code>tag</code> create two different destinations and therefore two different connection pools.
However, also this is not enough.</p>
</div>
<div class="paragraph">
<p>It is possible for a server to speak different protocols on the same <code>port</code>.
A connection may start by speaking one protocol, for example HTTP/1.1, but then be upgraded to speak a different protocol, for example HTTP/2. After a connection has been upgraded to a second protocol, it cannot speak the first protocol anymore, so it can only be used to communicate using the second protocol.</p>
</div>
<div class="paragraph">
<p>Two origins with the same <code>(scheme, host, port)</code> but different <code>protocol</code> create two different destinations and therefore two different connection pools.</p>
</div>
<div class="paragraph">
<p>Therefore an origin is identified by the tuple <code>(scheme, host, port, tag, protocol)</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-connection-pool"><a class="anchor" href="#pg-client-http-connection-pool"></a><a class="link" href="#pg-client-http-connection-pool">HttpClient Connection Pooling</a></h4>
<div class="paragraph">
<p>A destination manages a <code>org.eclipse.jetty.client.ConnectionPool</code>, where connections to a particular origin are pooled for performance reasons:
opening a connection is a costly operation and it&#8217;s better to reuse them for multiple requests.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Remember that to select a specific destination you must select a specific origin, and that an origin is identified by the tuple <code>(scheme, host, port, tag, protocol)</code>, so you can have multiple destinations for the same <code>host</code> and <code>port</code>.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>You can access the <code>ConnectionPool</code> in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpClient httpClient = <span class="keyword">new</span> HttpClient();
httpClient.start();
ConnectionPool connectionPool = httpClient.getDestinations().stream()
<span class="comment">// Cast to HttpDestination.</span>
.map(HttpDestination.class::cast)
<span class="comment">// Find the destination by filtering on the Origin.</span>
.filter(destination -&gt; destination.getOrigin().getAddress().getHost().equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">domain.com</span><span class="delimiter">&quot;</span></span>))
.findAny()
<span class="comment">// Get the ConnectionPool.</span>
.map(HttpDestination::getConnectionPool)
.orElse(<span class="predefined-constant">null</span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Jetty&#8217;s client library provides the following <code>ConnectionPool</code> implementations:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>DuplexConnectionPool</code>, historically the first implementation, only used by the HTTP/1.1 transport.</p>
</li>
<li>
<p><code>MultiplexConnectionPool</code>, the generic implementation valid for any transport where connections are reused with a MRU (most recently used) algorithm (that is, the connections most recently returned to the connection pool are the more likely to be used again).</p>
</li>
<li>
<p><code>RoundRobinConnectionPool</code>, similar to <code>MultiplexConnectionPool</code> but where connections are reused with a round-robin algorithm.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>ConnectionPool</code> implementation can be customized for each destination in by setting a <code>ConnectionPool.Factory</code> on the <code>HttpClientTransport</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpClient httpClient = <span class="keyword">new</span> HttpClient();
httpClient.start();
<span class="comment">// The max number of connections in the pool.</span>
<span class="type">int</span> maxConnectionsPerDestination = httpClient.getMaxConnectionsPerDestination();
<span class="comment">// The max number of requests per connection (multiplexing).</span>
<span class="comment">// Start with 1, since this value is dynamically set to larger values if</span>
<span class="comment">// the transport supports multiplexing requests on the same connection.</span>
<span class="type">int</span> maxRequestsPerConnection = <span class="integer">1</span>;
HttpClientTransport transport = httpClient.getTransport();
<span class="comment">// Set the ConnectionPool.Factory using a lambda.</span>
transport.setConnectionPoolFactory(destination -&gt;
<span class="keyword">new</span> RoundRobinConnectionPool(destination,
maxConnectionsPerDestination,
destination,
maxRequestsPerConnection));</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-request-processing"><a class="anchor" href="#pg-client-http-request-processing"></a><a class="link" href="#pg-client-http-request-processing">HttpClient Request Processing</a></h4>
<div class="imageblock">
<div class="content">
<img src="diag-4760564aad148998e116357e8f3a5450.png" alt="Diagram" width="679" height="520">
</div>
</div>
<div class="paragraph">
<p>When a request is sent, an origin is computed from the request; <code>HttpClient</code> uses that origin to find (or create if it does not exist) the correspondent destination.
The request is then queued onto the destination, and this causes the destination to ask its connection pool for a free connection.
If a connection is available, it is returned, otherwise a new connection is created.
Once the destination has obtained the connection, it dequeues the request and sends it over the connection.</p>
</div>
<div class="paragraph">
<p>The first request to a destination triggers the opening of the first connection.
A second request with the same origin sent <em>after</em> the first request/response cycle is completed may reuse the same connection, depending on the connection pool implementation.
A second request with the same origin sent <em>concurrently</em> with the first request will likely cause the opening of a second connection, depending on the connection pool implementation.
The configuration parameter <code>HttpClient.maxConnectionsPerDestination</code> (see also the <a href="#pg-client-http-configuration">configuration section</a>) controls the max number of connections that can be opened for a destination.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If opening connections to a given origin takes a long time, then requests for that origin will queue up in the corresponding destination until the connections are established.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Each connection can handle a limited number of concurrent requests.
For HTTP/1.1, this number is always <code>1</code>: there can only be one outstanding request for each connection.
For HTTP/2 this number is determined by the server <code>max_concurrent_stream</code> setting (typically around <code>100</code>, i.e. there can be up to <code>100</code> outstanding requests for every connection).</p>
</div>
<div class="paragraph">
<p>When a destination has maxed out its number of connections, and all connections have maxed out their number of outstanding requests, more requests sent to that destination will be queued.
When the request queue is full, the request will be failed.
The configuration parameter <code>HttpClient.maxRequestsQueuedPerDestination</code> (see also the <a href="#pg-client-http-configuration">configuration section</a>) controls the max number of requests that can be queued for a destination.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-api"><a class="anchor" href="#pg-client-http-api"></a><a class="link" href="#pg-client-http-api">HttpClient API Usage</a></h4>
<div class="paragraph">
<p><code>HttpClient</code> provides two types of APIs: a blocking API and a non-blocking API.</p>
</div>
<div class="sect4">
<h5 id="pg-client-http-blocking"><a class="anchor" href="#pg-client-http-blocking"></a><a class="link" href="#pg-client-http-blocking">HttpClient Blocking APIs</a></h5>
<div class="paragraph">
<p>The simpler way to perform a HTTP request is the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpClient httpClient = <span class="keyword">new</span> HttpClient();
httpClient.start();
<span class="comment">// Perform a simple GET and wait for the response.</span>
ContentResponse response = httpClient.GET(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path?query</span><span class="delimiter">&quot;</span></span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The method <code>HttpClient.GET(&#8230;&#8203;)</code> performs a HTTP <code>GET</code> request to the given URI and returns a <code>ContentResponse</code> when the request/response conversation completes successfully.</p>
</div>
<div class="paragraph">
<p>The <code>ContentResponse</code> object contains the HTTP response information: status code, headers and possibly content.
The content length is limited by default to 2 MiB; for larger content see <a href="#pg-client-http-content-response">the section on response content handling</a>.</p>
</div>
<div class="paragraph">
<p>If you want to customize the request, for example by issuing a <code>HEAD</code> request instead of a <code>GET</code>, and simulating a browser user agent, you can do it in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse response = httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path?query</span><span class="delimiter">&quot;</span></span>)
.method(HttpMethod.HEAD)
.agent(<span class="string"><span class="delimiter">&quot;</span><span class="content">Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0</span><span class="delimiter">&quot;</span></span>)
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is a shorthand for:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Request request = httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path?query</span><span class="delimiter">&quot;</span></span>);
request.method(HttpMethod.HEAD);
request.agent(<span class="string"><span class="delimiter">&quot;</span><span class="content">Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0</span><span class="delimiter">&quot;</span></span>);
ContentResponse response = request.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>You first create a request object using <code>httpClient.newRequest(&#8230;&#8203;)</code>, and then you customize it using the fluent API style (that is, a chained invocation of methods on the request object).
When the request object is customized, you call <code>request.send()</code> that produces the <code>ContentResponse</code> when the request/response conversation is complete.</p>
</div>
<div class="paragraph">
<p>Simple <code>POST</code> requests also have a shortcut method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse response = httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/entity/1</span><span class="delimiter">&quot;</span></span>)
.param(<span class="string"><span class="delimiter">&quot;</span><span class="content">p</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">value</span><span class="delimiter">&quot;</span></span>)
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>POST</code> parameter values added via the <code>param()</code> method are automatically URL-encoded.</p>
</div>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> automatically follows redirects, so it handles the typical web pattern <a href="http://en.wikipedia.org/wiki/Post/Redirect/Get">POST/Redirect/GET</a>, and the response object contains the content of the response of the <code>GET</code> request.
Following redirects is a feature that you can enable/disable on a per-request basis or globally.</p>
</div>
<div class="paragraph">
<p>File uploads also require one line, and make use of <code>java.nio.file</code> classes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse response = httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/upload</span><span class="delimiter">&quot;</span></span>)
.file(Paths.get(<span class="string"><span class="delimiter">&quot;</span><span class="content">file_to_upload.txt</span><span class="delimiter">&quot;</span></span>), <span class="string"><span class="delimiter">&quot;</span><span class="content">text/plain</span><span class="delimiter">&quot;</span></span>)
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>It is possible to impose a total timeout for the request/response conversation using the <code>Request.timeout(&#8230;&#8203;)</code> method as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse response = httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path?query</span><span class="delimiter">&quot;</span></span>)
.timeout(<span class="integer">5</span>, <span class="predefined-type">TimeUnit</span>.SECONDS)
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>In the example above, when the 5 seconds expire, the request/response cycle is aborted and a <code>java.util.concurrent.TimeoutException</code> is thrown.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-http-non-blocking"><a class="anchor" href="#pg-client-http-non-blocking"></a><a class="link" href="#pg-client-http-non-blocking">HttpClient Non-Blocking APIs</a></h5>
<div class="paragraph">
<p>So far we have shown how to use Jetty HTTP client in a blocking style&#8201;&#8212;&#8201;that is, the thread that issues the request blocks until the request/response conversation is complete.</p>
</div>
<div class="paragraph">
<p>This section will look at Jetty&#8217;s <code>HttpClient</code> non-blocking, asynchronous APIs that are perfectly suited for large content downloads, for parallel processing of requests/responses and in cases where performance and efficient thread and resource utilization is a key factor.</p>
</div>
<div class="paragraph">
<p>The asynchronous APIs rely heavily on listeners that are invoked at various stages of request and response processing.
These listeners are implemented by applications and may perform any kind of logic.
The implementation invokes these listeners in the same thread that is used to process the request or response.
Therefore, if the application code in these listeners takes a long time to execute, the request or response processing is delayed until the listener returns.</p>
</div>
<div class="paragraph">
<p>If you need to execute application code that takes long time inside a listener, you must spawn your own thread.</p>
</div>
<div class="paragraph">
<p>Request and response processing are executed by two different threads and therefore may happen concurrently.
A typical example of this concurrent processing is an echo server, where a large upload may be concurrent with the large download echoed back.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Remember that responses may be processed and completed <em>before</em> requests; a typical example is a large upload that triggers a quick response, for example an error, by the server: the response may arrive and be completed while the request content is still being uploaded.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The application thread that calls <code>Request.send(Response.CompleteListener)</code> performs the <a href="#pg-client-http-request-processing">processing of the request</a> until either the request is fully sent over the network or until it would block on I/O, then it returns (and therefore never blocks).
If it would block on I/O, the thread asks the I/O system to emit an event when the I/O will be ready to continue, then returns.
When such an event is fired, a thread taken from the <code>HttpClient</code> thread pool will resume the processing of the request.</p>
</div>
<div class="paragraph">
<p>Response are processed from the I/O thread taken from the <code>HttpClient</code> thread pool that processes the event that bytes are ready to be read.
Response processing continues until either the response is fully processed or until it would block for I/O.
If it would block for I/O, the thread asks the I/O system to emit an event when the I/O will be ready to continue, then returns.
When such an event is fired, a (possibly different) thread taken from the <code>HttpClient</code> thread pool will resume the processing of the response.</p>
</div>
<div class="paragraph">
<p>When the request and the response are both fully processed, the thread that finished the last processing (usually the thread that processes the response, but may also be the thread that processes the request&#8201;&#8212;&#8201;if the request takes more time than the response to be processed) is used to dequeue the next request for the same destination and to process it.</p>
</div>
<div class="paragraph">
<p>A simple non-blocking <code>GET</code> request that discards the response content can be written in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>)
.send(result -&gt;
{
<span class="comment">// Your logic here</span>
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>Method <code>Request.send(Response.CompleteListener)</code> returns <code>void</code> and does not block; the <code>Response.CompleteListener</code> lambda provided as a parameter is notified when the request/response conversation is complete, and the <code>Result</code> parameter allows you to access the request and response objects as well as failures, if any.</p>
</div>
<div class="paragraph">
<p>You can impose a total timeout for the request/response conversation in the same way used by the synchronous API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>)
.timeout(<span class="integer">3</span>, <span class="predefined-type">TimeUnit</span>.SECONDS)
.send(result -&gt;
{
<span class="comment">/* Your logic here */</span>
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>The example above will impose a total timeout of 3 seconds on the request/response conversation.</p>
</div>
<div class="paragraph">
<p>The HTTP client APIs use listeners extensively to provide hooks for all possible request and response events:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>)
<span class="comment">// Add request hooks.</span>
.onRequestQueued(request -&gt; { <span class="comment">/* ... */</span> })
.onRequestBegin(request -&gt; { <span class="comment">/* ... */</span> })
.onRequestHeaders(request -&gt; { <span class="comment">/* ... */</span> })
.onRequestCommit(request -&gt; { <span class="comment">/* ... */</span> })
.onRequestContent((request, content) -&gt; { <span class="comment">/* ... */</span> })
.onRequestFailure((request, failure) -&gt; { <span class="comment">/* ... */</span> })
.onRequestSuccess(request -&gt; { <span class="comment">/* ... */</span> })
<span class="comment">// Add response hooks.</span>
.onResponseBegin(response -&gt; { <span class="comment">/* ... */</span> })
.onResponseHeader((response, field) -&gt; <span class="predefined-constant">true</span>)
.onResponseHeaders(response -&gt; { <span class="comment">/* ... */</span> })
.onResponseContentAsync((response, buffer, callback) -&gt; callback.succeeded())
.onResponseFailure((response, failure) -&gt; { <span class="comment">/* ... */</span> })
.onResponseSuccess(response -&gt; { <span class="comment">/* ... */</span> })
<span class="comment">// Result hook.</span>
.send(result -&gt; { <span class="comment">/* ... */</span> });</code></pre>
</div>
</div>
<div class="paragraph">
<p>This makes Jetty HTTP client suitable for HTTP load testing because, for example, you can accurately time every step of the request/response conversation (thus knowing where the request/response time is really spent).</p>
</div>
<div class="paragraph">
<p>Have a look at the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/client/api/Request.Listener.html"><code>Request.Listener</code></a> class to know about request events, and to the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/client/api/Response.Listener.html"><code>Response.Listener</code></a> class to know about response events.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-http-content-request"><a class="anchor" href="#pg-client-http-content-request"></a><a class="link" href="#pg-client-http-content-request">Request Content Handling</a></h5>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> provides a number of utility classes off the shelf to handle request content.</p>
</div>
<div class="paragraph">
<p>You can provide request content as <code>String</code>, <code>byte[]</code>, <code>ByteBuffer</code>, <code>java.nio.file.Path</code>, <code>InputStream</code>, and provide your own implementation of <code>org.eclipse.jetty.client.api.Request.Content</code>.
Here’s an example that provides the request content using <code>java.nio.file.Paths</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse response = httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/upload</span><span class="delimiter">&quot;</span></span>)
.body(<span class="keyword">new</span> PathRequestContent(<span class="string"><span class="delimiter">&quot;</span><span class="content">text/plain</span><span class="delimiter">&quot;</span></span>, Paths.get(<span class="string"><span class="delimiter">&quot;</span><span class="content">file_to_upload.txt</span><span class="delimiter">&quot;</span></span>)))
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively, you can use <code>FileInputStream</code> via the <code>InputStreamRequestContent</code> utility class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse response = httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/upload</span><span class="delimiter">&quot;</span></span>)
.body(<span class="keyword">new</span> InputStreamRequestContent(<span class="string"><span class="delimiter">&quot;</span><span class="content">text/plain</span><span class="delimiter">&quot;</span></span>, <span class="keyword">new</span> <span class="predefined-type">FileInputStream</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">file_to_upload.txt</span><span class="delimiter">&quot;</span></span>)))
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Since <code>InputStream</code> is blocking, then also the send of the request will block if the input stream blocks, even in case of usage of the non-blocking <code>HttpClient</code> APIs.</p>
</div>
<div class="paragraph">
<p>If you have already read the content in memory, you can pass it as a <code>byte[]</code> (or a <code>String</code>) using the <code>BytesRequestContent</code> (or <code>StringRequestContent</code>) utility class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse bytesResponse = httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/upload</span><span class="delimiter">&quot;</span></span>)
.body(<span class="keyword">new</span> BytesRequestContent(<span class="string"><span class="delimiter">&quot;</span><span class="content">text/plain</span><span class="delimiter">&quot;</span></span>, bytes))
.send();
ContentResponse stringResponse = httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/upload</span><span class="delimiter">&quot;</span></span>)
.body(<span class="keyword">new</span> StringRequestContent(<span class="string"><span class="delimiter">&quot;</span><span class="content">text/plain</span><span class="delimiter">&quot;</span></span>, string))
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>If the request content is not immediately available, but your application will be notified of the content to send, you can use <code>AsyncRequestContent</code> in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">AsyncRequestContent content = <span class="keyword">new</span> AsyncRequestContent();
httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/upload</span><span class="delimiter">&quot;</span></span>)
.body(content)
.send(result -&gt;
{
<span class="comment">// Your logic here</span>
});
<span class="comment">// Content not available yet here.</span>
<span class="comment">// An event happens in some other class, in some other thread.</span>
<span class="type">class</span> <span class="class">ContentPublisher</span>
{
<span class="type">void</span> publish(ByteBufferPool bufferPool, <span class="type">byte</span><span class="type">[]</span> bytes, <span class="type">boolean</span> lastContent)
{
<span class="comment">// Wrap the bytes into a new ByteBuffer.</span>
<span class="predefined-type">ByteBuffer</span> buffer = <span class="predefined-type">ByteBuffer</span>.wrap(bytes);
<span class="comment">// Offer the content, and release the ByteBuffer</span>
<span class="comment">// to the pool when the Callback is completed.</span>
content.offer(buffer, <span class="predefined-type">Callback</span>.from(() -&gt; bufferPool.release(buffer)));
<span class="comment">// Close AsyncRequestContent when all the content is arrived.</span>
<span class="keyword">if</span> (lastContent)
content.close();
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>While the request content is awaited and consequently uploaded by the client application, the server may be able to respond (at least with the response headers) completely asynchronously.
In this case, <code>Response.Listener</code> callbacks will be invoked before the request is fully sent.
This allows fine-grained control of the request/response conversation: for example the server may reject contents that are too big, send a response to the client, which in turn may stop the content upload.</p>
</div>
<div class="paragraph">
<p>Another way to provide request content is by using an <code>OutputStreamRequestContent</code>, which allows applications to write request content when it is available to the <code>OutputStream</code> provided by <code>OutputStreamRequestContent</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">OutputStreamRequestContent content = <span class="keyword">new</span> OutputStreamRequestContent();
<span class="comment">// Use try-with-resources to close the OutputStream when all content is written.</span>
<span class="keyword">try</span> (<span class="predefined-type">OutputStream</span> output = content.getOutputStream())
{
httpClient.POST(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://localhost:8080/</span><span class="delimiter">&quot;</span></span>)
.body(content)
.send(result -&gt;
{
<span class="comment">// Your logic here</span>
});
<span class="comment">// Content not available yet here.</span>
<span class="comment">// Content is now available.</span>
<span class="type">byte</span><span class="type">[]</span> bytes = <span class="keyword">new</span> <span class="type">byte</span><span class="type">[]</span>{<span class="string"><span class="delimiter">'</span><span class="content">h</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">e</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">l</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">l</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">o</span><span class="delimiter">'</span></span>};
output.write(bytes);
}
<span class="comment">// End of try-with-resource, output.close() called automatically to signal end of content.</span></code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-http-content-response"><a class="anchor" href="#pg-client-http-content-response"></a><a class="link" href="#pg-client-http-content-response">Response Content Handling</a></h5>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> allows applications to handle response content in different ways.</p>
</div>
<div class="paragraph">
<p>You can buffer the response content in memory; this is done when using the <a href="#pg-client-http-blocking">blocking APIs</a> and the content is buffered within a <code>ContentResponse</code> up to 2 MiB.</p>
</div>
<div class="paragraph">
<p>If you want to control the length of the response content (for example limiting to values smaller than the default of 2 MiB), then you can use a <code>org.eclipse.jetty.client.util.FutureResponseListener</code> in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Request request = httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Limit response content buffer to 512 KiB.</span>
FutureResponseListener listener = <span class="keyword">new</span> FutureResponseListener(request, <span class="integer">512</span> * <span class="integer">1024</span>);
request.send(listener);
<span class="comment">// Wait at most 5 seconds for request+response to complete.</span>
ContentResponse response = listener.get(<span class="integer">5</span>, <span class="predefined-type">TimeUnit</span>.SECONDS);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If the response content length is exceeded, the response will be aborted, and an exception will be thrown by method <code>get(&#8230;&#8203;)</code>.</p>
</div>
<div class="paragraph">
<p>You can buffer the response content in memory also using the <a href="#pg-client-http-non-blocking">non-blocking APIs</a>, via the <code>BufferingResponseListener</code> utility class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>)
<span class="comment">// Buffer response content up to 8 MiB</span>
.send(<span class="keyword">new</span> BufferingResponseListener(<span class="integer">8</span> * <span class="integer">1024</span> * <span class="integer">1024</span>)
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onComplete(<span class="predefined-type">Result</span> result)
{
<span class="keyword">if</span> (!result.isFailed())
{
<span class="type">byte</span><span class="type">[]</span> responseContent = getContent();
<span class="comment">// Your logic here</span>
}
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you want to avoid buffering, you can wait for the response and then stream the content using the <code>InputStreamResponseListener</code> utility class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">InputStreamResponseListener listener = <span class="keyword">new</span> InputStreamResponseListener();
httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>)
.send(listener);
<span class="comment">// Wait for the response headers to arrive.</span>
Response response = listener.get(<span class="integer">5</span>, <span class="predefined-type">TimeUnit</span>.SECONDS);
<span class="comment">// Look at the response before streaming the content.</span>
<span class="keyword">if</span> (response.getStatus() == HttpStatus.OK_200)
{
<span class="comment">// Use try-with-resources to close input stream.</span>
<span class="keyword">try</span> (<span class="predefined-type">InputStream</span> responseContent = listener.getInputStream())
{
<span class="comment">// Your logic here</span>
}
}
<span class="keyword">else</span>
{
response.abort(<span class="keyword">new</span> <span class="exception">IOException</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">Unexpected HTTP response</span><span class="delimiter">&quot;</span></span>));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Finally, let&#8217;s look at the advanced usage of the response content handling.</p>
</div>
<div class="paragraph">
<p>The response content is provided by the <code>HttpClient</code> implementation to application listeners following a reactive model similar to that of <code>java.util.concurrent.Flow</code>.</p>
</div>
<div class="paragraph">
<p>The listener that follows this model is <code>Response.DemandedContentListener</code>.</p>
</div>
<div class="paragraph">
<p>After the response headers have been processed by the <code>HttpClient</code> implementation, <code>Response.DemandedContentListener.onBeforeContent(response, demand)</code> is invoked.
This allows the application to control whether to demand the first content or not.
The default implementation of this method calls <code>demand.accept(1)</code>, which demands one chunk of content to the implementation.
The implementation will deliver the chunk of content as soon as it is available.</p>
</div>
<div class="paragraph">
<p>The chunks of content are delivered to the application by invoking <code>Response.DemandedContentListener.onContent(response, demand, buffer, callback)</code>.
Applications implement this method to process the content bytes in the <code>buffer</code>.
Succeeding the <code>callback</code> signals to the implementation that the application has consumed the <code>buffer</code> so that the implementation can dispose/recycle the <code>buffer</code>.
Failing the <code>callback</code> signals to the implementation to fail the response (no more content will be delivered, and the <em>response failed</em> event will be emitted).</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Succeeding the <code>callback</code> must be done only after the <code>buffer</code> bytes have been consumed.
When the <code>callback</code> is succeeded, the <code>HttpClient</code> implementation may reuse the <code>buffer</code> and overwrite the bytes with different bytes; if the application looks at the <code>buffer</code> <em>after</em> having succeeded the <code>callback</code> is may see other, unrelated, bytes.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The application uses the <code>demand</code> object to demand more content chunks.
Applications will typically demand for just one more content via <code>demand.accept(1)</code>, but may decide to demand for more via <code>demand.accept(2)</code> or demand "infinitely" once via <code>demand.accept(Long.MAX_VALUE)</code>.
Applications that demand for more than 1 chunk of content must be prepared to receive all the content that they have demanded.</p>
</div>
<div class="paragraph">
<p>Demanding for content and consuming the content are orthogonal activities.</p>
</div>
<div class="paragraph">
<p>An application can demand "infinitely" and store aside the pairs <code>(buffer, callback)</code> to consume them later.
If not done carefully, this may lead to excessive memory consumption, since the <code>buffer</code>s are not consumed.
Succeeding the <code>callback</code>s will result in the <code>buffer</code>s to be disposed/recycled and may be performed at any time.</p>
</div>
<div class="paragraph">
<p>An application can also demand one chunk of content, consume it (by succeeding the associated <code>callback</code>) and then <em>not</em> demand for more content until a later time.</p>
</div>
<div class="paragraph">
<p>Subclass <code>Response.AsyncContentListener</code> overrides the behavior of <code>Response.DemandedContentListener</code>; when an application implementing its <code>onContent(response, buffer, callback)</code> succeeds the <code>callback</code>, it will have <em>both</em> the effect of disposing/recycling the <code>buffer</code> <em>and</em> the effect of demanding one more chunk of content.</p>
</div>
<div class="paragraph">
<p>Subclass <code>Response.ContentListener</code> overrides the behavior of <code>Response.AsyncContentListener</code>; when an application implementing its <code>onContent(response, buffer)</code> returns from the method itself, it will <em>both</em> the effect of disposing/recycling the <code>buffer</code> <em>and</em> the effect of demanding one more chunk of content.</p>
</div>
<div class="paragraph">
<p>Previous examples of response content handling were inefficient because they involved copying the <code>buffer</code> bytes, either to accumulate them aside so that the application could use them when the request was completed, or because they were provided to an API such as <code>InputStream</code> that made use of <code>byte[]</code> (and therefore a copy from <code>ByteBuffer</code> to <code>byte[]</code> is necessary).</p>
</div>
<div class="paragraph">
<p>An application that implements a forwarder between two servers can be implemented efficiently by handling the response content without copying the <code>buffer</code> bytes as in the following example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Prepare a request to server1, the source.</span>
Request request1 = httpClient.newRequest(host1, port1)
.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/source</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Prepare a request to server2, the sink.</span>
AsyncRequestContent content2 = <span class="keyword">new</span> AsyncRequestContent();
Request request2 = httpClient.newRequest(host2, port2)
.path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/sink</span><span class="delimiter">&quot;</span></span>)
.body(content2);
request1.onResponseContentDemanded(<span class="keyword">new</span> Response.DemandedContentListener()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onBeforeContent(Response response, LongConsumer demand)
{
request2.onRequestCommit(request -&gt;
{
<span class="comment">// Only when the request to server2 has been sent,</span>
<span class="comment">// then demand response content from server1.</span>
demand.accept(<span class="integer">1</span>);
});
<span class="comment">// Send the request to server2.</span>
request2.send(result -&gt; <span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">forwarder</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Forwarding to server2 complete</span><span class="delimiter">&quot;</span></span>));
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onContent(Response response, LongConsumer demand, <span class="predefined-type">ByteBuffer</span> content, <span class="predefined-type">Callback</span> callback)
{
<span class="comment">// When response content is received from server1, forward it to server2.</span>
content2.offer(content, <span class="predefined-type">Callback</span>.from(() -&gt;
{
<span class="comment">// When the request content to server2 is sent,</span>
<span class="comment">// succeed the callback to recycle the buffer.</span>
callback.succeeded();
<span class="comment">// Then demand more response content from server1.</span>
demand.accept(<span class="integer">1</span>);
}, callback::failed));
}
});
<span class="comment">// When the response content from server1 is complete,</span>
<span class="comment">// complete also the request content to server2.</span>
request1.onResponseSuccess(response -&gt; content2.close());
<span class="comment">// Send the request to server1.</span>
request1.send(result -&gt; <span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">forwarder</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Sourcing from server1 complete</span><span class="delimiter">&quot;</span></span>));</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-configuration"><a class="anchor" href="#pg-client-http-configuration"></a><a class="link" href="#pg-client-http-configuration">HttpClient Configuration</a></h4>
<div class="paragraph">
<p><code>HttpClient</code> has a quite large number of configuration parameters.
Please refer to the <code>HttpClient</code> <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/client/HttpClient.html">javadocs</a> for the complete list of configurable parameters.</p>
</div>
<div class="paragraph">
<p>The most common parameters are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>HttpClient.idleTimeout</code>: same as <code>ClientConnector.idleTimeout</code> described in <a href="#pg-client-io-arch-network">this section</a>.</p>
</li>
<li>
<p><code>HttpClient.connectBlocking</code>: same as <code>ClientConnector.connectBlocking</code> described in <a href="#pg-client-io-arch-network">this section</a>.</p>
</li>
<li>
<p><code>HttpClient.connectTimeout</code>: same as <code>ClientConnector.connectTimeout</code> described in <a href="#pg-client-io-arch-network">this section</a>.</p>
</li>
<li>
<p><code>HttpClient.maxConnectionsPerDestination</code>: the max number of TCP connections that are opened for a particular destination (defaults to 64).</p>
</li>
<li>
<p><code>HttpClient.maxRequestsQueuedPerDestination</code>: the max number of requests queued (defaults to 1024).</p>
</li>
</ul>
</div>
<div class="sect4">
<h5 id="pg-client-http-configuration-tls"><a class="anchor" href="#pg-client-http-configuration-tls"></a><a class="link" href="#pg-client-http-configuration-tls">HttpClient TLS Configuration</a></h5>
<div class="paragraph">
<p><code>HttpClient</code> supports HTTPS requests out-of-the-box like a browser does.</p>
</div>
<div class="paragraph">
<p>The support for HTTPS request is provided by a <code>SslContextFactory.Client</code>, typically configured in the <code>ClientConnector</code>.
If not explicitly configured, the <code>ClientConnector</code> will allocate a default one when started.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">SslContextFactory.Client sslContextFactory = <span class="keyword">new</span> SslContextFactory.Client();
ClientConnector clientConnector = <span class="keyword">new</span> ClientConnector();
clientConnector.setSslContextFactory(sslContextFactory);
HttpClient httpClient = <span class="keyword">new</span> HttpClient(<span class="keyword">new</span> HttpClientTransportDynamic(clientConnector));
httpClient.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The default <code>SslContextFactory.Client</code> verifies the certificate sent by the server by verifying the certificate chain.
This means that requests to public websites that have a valid certificate (such as <code><a href="https://google.com" class="bare">https://google.com</a></code>) will work out-of-the-box.</p>
</div>
<div class="paragraph">
<p>However, requests made to sites (typically <code>localhost</code>) that have an invalid (for example, expired or with a wrong host) or self-signed certificate will fail (like they will in a browser).</p>
</div>
<div class="paragraph">
<p>Certificate validation is performed at two levels: at the TLS implementation level (in the JDK) and, optionally, at the application level.</p>
</div>
<div class="paragraph">
<p>By default, certificate validation at the TLS level is enabled, while certificate validation at the application level is disabled.</p>
</div>
<div class="paragraph">
<p>You can configure the <code>SslContextFactory.Client</code> to skip certificate validation at the TLS level:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">SslContextFactory.Client sslContextFactory = <span class="keyword">new</span> SslContextFactory.Client();
<span class="comment">// Disable certificate validation at the TLS level.</span>
sslContextFactory.setEndpointIdentificationAlgorithm(<span class="predefined-constant">null</span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can enable certificate validation at the application level:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">SslContextFactory.Client sslContextFactory = <span class="keyword">new</span> SslContextFactory.Client();
<span class="comment">// Only allow subdomains of domain.com.</span>
sslContextFactory.setHostnameVerifier((hostName, session) -&gt; hostName.endsWith(<span class="string"><span class="delimiter">&quot;</span><span class="content">.domain.com</span><span class="delimiter">&quot;</span></span>));</code></pre>
</div>
</div>
<div class="paragraph">
<p>Please refer to the <code>SslContextFactory.Client</code> <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/util/ssl/SslContextFactory.Client.html">javadocs</a> for the complete list of configurable parameters.</p>
</div>
<div class="sect5">
<h6 id="pg-client-http-configuration-tls-truststore"><a class="anchor" href="#pg-client-http-configuration-tls-truststore"></a><a class="link" href="#pg-client-http-configuration-tls-truststore">HttpClient TLS TrustStore Configuration</a></h6>
<div class="paragraph">
<p>TODO</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-client-http-configuration-tls-client-certs"><a class="anchor" href="#pg-client-http-configuration-tls-client-certs"></a><a class="link" href="#pg-client-http-configuration-tls-client-certs">HttpClient TLS Client Certificates Configuration</a></h6>
<div class="paragraph">
<p>TODO</p>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-cookie"><a class="anchor" href="#pg-client-http-cookie"></a><a class="link" href="#pg-client-http-cookie">HttpClient Cookie Support</a></h4>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> supports cookies out of the box.</p>
</div>
<div class="paragraph">
<p>The <code>HttpClient</code> instance receives cookies from HTTP responses and stores them in a <code>java.net.CookieStore</code>, a class that is part of the JDK.
When new requests are made, the cookie store is consulted and if there are matching cookies (that is, cookies that are not expired and that match domain and path of the request) then they are added to the requests.</p>
</div>
<div class="paragraph">
<p>Applications can programmatically access the cookie store to find the cookies that have been set:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">CookieStore cookieStore = httpClient.getCookieStore();
<span class="predefined-type">List</span>&lt;HttpCookie&gt; cookies = cookieStore.get(<span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>));</code></pre>
</div>
</div>
<div class="paragraph">
<p>Applications can also programmatically set cookies as if they were returned from a HTTP response:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">CookieStore cookieStore = httpClient.getCookieStore();
HttpCookie cookie = <span class="keyword">new</span> HttpCookie(<span class="string"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">bar</span><span class="delimiter">&quot;</span></span>);
cookie.setDomain(<span class="string"><span class="delimiter">&quot;</span><span class="content">domain.com</span><span class="delimiter">&quot;</span></span>);
cookie.setPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/</span><span class="delimiter">&quot;</span></span>);
cookie.setMaxAge(<span class="predefined-type">TimeUnit</span>.DAYS.toSeconds(<span class="integer">1</span>));
cookieStore.add(<span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com</span><span class="delimiter">&quot;</span></span>), cookie);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Cookies may be added explicitly only for a particular request:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ContentResponse response = httpClient.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>)
.cookie(<span class="keyword">new</span> HttpCookie(<span class="string"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">bar</span><span class="delimiter">&quot;</span></span>))
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can remove cookies that you do not want to be sent in future HTTP requests:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">CookieStore cookieStore = httpClient.getCookieStore();
<span class="predefined-type">URI</span> uri = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com</span><span class="delimiter">&quot;</span></span>);
<span class="predefined-type">List</span>&lt;HttpCookie&gt; cookies = cookieStore.get(uri);
<span class="keyword">for</span> (HttpCookie cookie : cookies)
{
cookieStore.remove(uri, cookie);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you want to totally disable cookie handling, you can install a <code>HttpCookieStore.Empty</code>.
This must be done when <code>HttpClient</code> is used in a proxy application, in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">httpClient.setCookieStore(<span class="keyword">new</span> HttpCookieStore.Empty());</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can enable cookie filtering by installing a cookie store that performs the filtering logic in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">GoogleOnlyCookieStore</span> <span class="directive">extends</span> HttpCookieStore
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> add(<span class="predefined-type">URI</span> uri, HttpCookie cookie)
{
<span class="keyword">if</span> (uri.getHost().endsWith(<span class="string"><span class="delimiter">&quot;</span><span class="content">google.com</span><span class="delimiter">&quot;</span></span>))
<span class="local-variable">super</span>.add(uri, cookie);
}
}
httpClient.setCookieStore(<span class="keyword">new</span> GoogleOnlyCookieStore());</code></pre>
</div>
</div>
<div class="paragraph">
<p>The example above will retain only cookies that come from the <code>google.com</code> domain or sub-domains.</p>
</div>
<div class="sect4">
<h5 id="pg-special-characters-in-cookies"><a class="anchor" href="#pg-special-characters-in-cookies"></a><a class="link" href="#pg-special-characters-in-cookies">Special Characters in Cookies</a></h5>
<div class="paragraph">
<p>Jetty is compliant with <a href="https://tools.ietf.org/html/rfc6265">RFC6265</a>, and as such care must be taken when setting a cookie value that includes special characters such as <code>;</code>.</p>
</div>
<div class="paragraph">
<p>Previously, <code>Version=1</code> cookies defined in <a href="https://tools.ietf.org/html/rfc2109">RFC2109</a> (and continued in <a href="https://tools.ietf.org/html/rfc2965">RFC2965</a>) allowed for special/reserved characters to be enclosed within double quotes when declared in a <code>Set-Cookie</code> response header:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Set-Cookie: foo=&quot;bar;baz&quot;;Version=1;Path=&quot;/secur&quot;</code></pre>
</div>
</div>
<div class="paragraph">
<p>This was added to the HTTP Response as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">protected</span> <span class="type">void</span> service(HttpServletRequest request, HttpServletResponse response)
{
javax.servlet.http.Cookie cookie = <span class="keyword">new</span> Cookie(<span class="string"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">bar;baz</span><span class="delimiter">&quot;</span></span>);
cookie.setPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/secure</span><span class="delimiter">&quot;</span></span>);
response.addCookie(cookie);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The introduction of RFC6265 has rendered this approach no longer possible; users are now required to encode cookie values that use these special characters.
This can be done utilizing <code>javax.servlet.http.Cookie</code> as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">javax.servlet.http.Cookie cookie = <span class="keyword">new</span> Cookie(<span class="string"><span class="delimiter">&quot;</span><span class="content">foo</span><span class="delimiter">&quot;</span></span>, <span class="predefined-type">URLEncoder</span>.encode(<span class="string"><span class="delimiter">&quot;</span><span class="content">bar;baz</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">UTF-8</span><span class="delimiter">&quot;</span></span>));</code></pre>
</div>
</div>
<div class="paragraph">
<p>Jetty validates all cookie names and values being added to the <code>HttpServletResponse</code> via the <code>addCookie(Cookie)</code> method.
If an illegal value is discovered Jetty will throw an <code>IllegalArgumentException</code> with the details.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-authentication"><a class="anchor" href="#pg-client-http-authentication"></a><a class="link" href="#pg-client-http-authentication">HttpClient Authentication Support</a></h4>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> supports the <code>BASIC</code> and <code>DIGEST</code> authentication mechanisms defined by <a href="https://tools.ietf.org/html/rfc7235">RFC 7235</a>, as well as the SPNEGO authentication mechanism defined in <a href="https://tools.ietf.org/html/rfc4559">RFC 4559</a>.</p>
</div>
<div class="paragraph">
<p>The HTTP <em>conversation</em>, the sequence of related HTTP requests, for a request that needs authentication is the following:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-136e615bb97d8356ceb17a851c86817a.png" alt="Diagram" width="377" height="211">
</div>
</div>
<div class="paragraph">
<p>Upon receiving a HTTP 401 response code, <code>HttpClient</code> looks at the <code>WWW-Authenticate</code> response header (the server <em>challenge</em>) and then tries to match configured authentication credentials to produce an <code>Authentication</code> header that contains the authentication credentials to access the resource.</p>
</div>
<div class="paragraph">
<p>You can configure authentication credentials in the <code>HttpClient</code> instance as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Add authentication credentials.</span>
AuthenticationStore auth = httpClient.getAuthenticationStore();
<span class="predefined-type">URI</span> uri1 = <span class="keyword">new</span> <span class="predefined-type">URI</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://mydomain.com/secure</span><span class="delimiter">&quot;</span></span>);
auth.addAuthentication(<span class="keyword">new</span> BasicAuthentication(uri1, <span class="string"><span class="delimiter">&quot;</span><span class="content">MyRealm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">userName1</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">password1</span><span class="delimiter">&quot;</span></span>));
<span class="predefined-type">URI</span> uri2 = <span class="keyword">new</span> <span class="predefined-type">URI</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://otherdomain.com/admin</span><span class="delimiter">&quot;</span></span>);
auth.addAuthentication(<span class="keyword">new</span> BasicAuthentication(uri1, <span class="string"><span class="delimiter">&quot;</span><span class="content">AdminRealm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">admin</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span>));</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>Authentication</code>s are matched against the server challenge first by mechanism (e.g. <code>BASIC</code> or <code>DIGEST</code>), then by realm and then by URI.</p>
</div>
<div class="paragraph">
<p>If an <code>Authentication</code> match is found, the application does not receive events related to the HTTP 401 response.
These events are handled internally by <code>HttpClient</code> which produces another (internal) request similar to the original request but with an additional <code>Authorization</code> header.</p>
</div>
<div class="paragraph">
<p>If the authentication is successful, the server responds with a HTTP 200 and <code>HttpClient</code> caches the <code>Authentication.Result</code> so that subsequent requests for a matching URI will not incur in the additional rountrip caused by the HTTP 401 response.</p>
</div>
<div class="paragraph">
<p>It is possible to clear <code>Authentication.Result</code>s in order to force authentication again:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">httpClient.getAuthenticationStore().clearAuthenticationResults();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Authentication results may be preempted to avoid the additional roundtrip due to the server challenge in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">AuthenticationStore auth = httpClient.getAuthenticationStore();
<span class="predefined-type">URI</span> uri = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/secure</span><span class="delimiter">&quot;</span></span>);
auth.addAuthenticationResult(<span class="keyword">new</span> BasicAuthentication.BasicResult(uri, <span class="string"><span class="delimiter">&quot;</span><span class="content">username</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span>));</code></pre>
</div>
</div>
<div class="paragraph">
<p>In this way, requests for the given URI are enriched immediately with the <code>Authorization</code> header, and the server should respond with HTTP 200 (and the resource content) rather than with the 401 and the challenge.</p>
</div>
<div class="paragraph">
<p>It is also possible to preempt the authentication for a single request only, in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">URI</span> uri = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/secure</span><span class="delimiter">&quot;</span></span>);
Authentication.Result authn = <span class="keyword">new</span> BasicAuthentication.BasicResult(uri, <span class="string"><span class="delimiter">&quot;</span><span class="content">username</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">password</span><span class="delimiter">&quot;</span></span>);
Request request = httpClient.newRequest(uri);
authn.apply(request);
request.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>See also the <a href="#pg-client-http-proxy-authentication">proxy authentication section</a> for further information about how authentication works with HTTP proxies.</p>
</div>
<div class="sect4">
<h5 id="pg-client-http-authentication-spnego"><a class="anchor" href="#pg-client-http-authentication-spnego"></a><a class="link" href="#pg-client-http-authentication-spnego">HttpClient SPNEGO Authentication Support</a></h5>
<div class="paragraph">
<p>TODO</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-proxy"><a class="anchor" href="#pg-client-http-proxy"></a><a class="link" href="#pg-client-http-proxy">HttpClient Proxy Support</a></h4>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> can be configured to use proxies to connect to destinations.</p>
</div>
<div class="paragraph">
<p>Two types of proxies are available out of the box: a HTTP proxy (provided by class <code>org.eclipse.jetty.client.HttpProxy</code>) and a SOCKS 4 proxy (provided by class <code>org.eclipse.jetty.client.Socks4Proxy</code>).
Other implementations may be written by subclassing <code>ProxyConfiguration.Proxy</code>.</p>
</div>
<div class="paragraph">
<p>The following is a typical configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpProxy proxy = <span class="keyword">new</span> HttpProxy(<span class="string"><span class="delimiter">&quot;</span><span class="content">proxyHost</span><span class="delimiter">&quot;</span></span>, <span class="integer">8888</span>);
<span class="comment">// Do not proxy requests for localhost:8080.</span>
proxy.getExcludedAddresses().add(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost:8080</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Add the new proxy to the list of proxies already registered.</span>
ProxyConfiguration proxyConfig = httpClient.getProxyConfiguration();
proxyConfig.getProxies().add(proxy);
ContentResponse response = httpClient.GET(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/path</span><span class="delimiter">&quot;</span></span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>You specify the proxy host and proxy port, and optionally also the addresses that you do not want to be proxied, and then add the proxy configuration on the <code>ProxyConfiguration</code> instance.</p>
</div>
<div class="paragraph">
<p>Configured in this way, <code>HttpClient</code> makes requests to the HTTP proxy (for plain-text HTTP requests) or establishes a tunnel via HTTP <code>CONNECT</code> (for encrypted HTTPS requests).</p>
</div>
<div class="paragraph">
<p>Proxying is supported for both HTTP/1.1 and HTTP/2.</p>
</div>
<div class="sect4">
<h5 id="pg-client-http-proxy-authentication"><a class="anchor" href="#pg-client-http-proxy-authentication"></a><a class="link" href="#pg-client-http-proxy-authentication">Proxy Authentication Support</a></h5>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> supports proxy authentication in the same way it supports <a href="#pg-client-http-authentication">server authentication</a>.</p>
</div>
<div class="paragraph">
<p>In the example below, the proxy requires <code>BASIC</code> authentication, but the server requires <code>DIGEST</code> authentication, and therefore:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">AuthenticationStore auth = httpClient.getAuthenticationStore();
<span class="comment">// Proxy credentials.</span>
<span class="predefined-type">URI</span> proxyURI = <span class="keyword">new</span> <span class="predefined-type">URI</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://proxy.net:8080</span><span class="delimiter">&quot;</span></span>);
auth.addAuthentication(<span class="keyword">new</span> BasicAuthentication(proxyURI, <span class="string"><span class="delimiter">&quot;</span><span class="content">ProxyRealm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">proxyUser</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">proxyPass</span><span class="delimiter">&quot;</span></span>));
<span class="comment">// Server credentials.</span>
<span class="predefined-type">URI</span> serverURI = <span class="keyword">new</span> <span class="predefined-type">URI</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://domain.com/secure</span><span class="delimiter">&quot;</span></span>);
auth.addAuthentication(<span class="keyword">new</span> DigestAuthentication(serverURI, <span class="string"><span class="delimiter">&quot;</span><span class="content">ServerRealm</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">serverUser</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">serverPass</span><span class="delimiter">&quot;</span></span>));
<span class="comment">// Proxy configuration.</span>
ProxyConfiguration proxyConfig = httpClient.getProxyConfiguration();
HttpProxy proxy = <span class="keyword">new</span> HttpProxy(<span class="string"><span class="delimiter">&quot;</span><span class="content">proxy.net</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>);
proxyConfig.getProxies().add(proxy);
ContentResponse response = httpClient.newRequest(serverURI).send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The HTTP conversation for successful authentications on both the proxy and the server is the following:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-e7fd1b7ba54e07262bd726c9fe979363.png" alt="Diagram" width="719" height="416">
</div>
</div>
<div class="paragraph">
<p>The application does not receive events related to the responses with code 407 and 401 since they are handled internally by <code>HttpClient</code>.</p>
</div>
<div class="paragraph">
<p>Similarly to the <a href="#pg-client-http-authentication">authentication section</a>, the proxy authentication result and the server authentication result can be preempted to avoid, respectively, the 407 and 401 roundtrips.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http-transport"><a class="anchor" href="#pg-client-http-transport"></a><a class="link" href="#pg-client-http-transport">HttpClient Pluggable Transports</a></h4>
<div class="paragraph">
<p>Jetty&#8217;s <code>HttpClient</code> can be configured to use different transports to carry the semantic of HTTP requests and responses.</p>
</div>
<div class="paragraph">
<p>This means that the intention of a client to request resource <code>/index.html</code> using the <code>GET</code> method can be carried over the network in different formats.</p>
</div>
<div class="paragraph">
<p>A <code>HttpClient</code> transport is the component that is in charge of converting a high-level, semantic, HTTP requests such as &#8220;`GET<code> resource </code>/index.html`&#8221; into the specific format understood by the server (for example, HTTP/2), and to convert the server response from the specific format (HTTP/2) into high-level, semantic objects that can be used by applications.</p>
</div>
<div class="paragraph">
<p>The most common protocol format is HTTP/1.1, a textual protocol with lines separated by <code>\r\n</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">GET /index.html HTTP/1.1\r\n
Host: domain.com\r\n
...
\r\n</code></pre>
</div>
</div>
<div class="paragraph">
<p>However, the same request can be made using FastCGI, a binary protocol:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">x01 x01 x00 x01 x00 x08 x00 x00
x00 x01 x01 x00 x00 x00 x00 x00
x01 x04 x00 x01 xLL xLL x00 x00
x0C x0B D O C U M E
N T _ U R I / i
n d e x . h t m
l
...</code></pre>
</div>
</div>
<div class="paragraph">
<p>Similarly, HTTP/2 is a binary protocol that transports the same information in a yet different format.</p>
</div>
<div class="paragraph">
<p>A protocol may be <em>negotiated</em> between client and server.
A request for a resource may be sent using one protocol (for example, HTTP/1.1), but the response may arrive in a different protocol (for example, HTTP/2).</p>
</div>
<div class="paragraph">
<p><code>HttpClient</code> supports 3 static transports, each speaking only one protocol: <a href="#pg-client-http-transport-http11">HTTP/1.1</a>, <a href="#pg-client-http-transport-http2">HTTP/2</a> and <a href="#pg-client-http-transport-fcgi">FastCGI</a>, all of them with 2 variants: clear-text and TLS encrypted.</p>
</div>
<div class="paragraph">
<p><code>HttpClient</code> also supports one <a href="#pg-client-http-transport-dynamic">dynamic transport</a>, that can speak different protocols and can select the right protocol by negotiating it with the server or by explicit indication from applications.</p>
</div>
<div class="paragraph">
<p>Applications are typically not aware of the actual protocol being used.
This allows them to write their logic against a high-level API that hides the details of the specific protocol being used over the network.</p>
</div>
<div class="sect4">
<h5 id="pg-client-http-transport-http11"><a class="anchor" href="#pg-client-http-transport-http11"></a><a class="link" href="#pg-client-http-transport-http11">HTTP/1.1 Transport</a></h5>
<div class="paragraph">
<p>HTTP/1.1 is the default transport.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// No transport specified, using default.</span>
HttpClient httpClient = <span class="keyword">new</span> HttpClient();
httpClient.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you want to customize the HTTP/1.1 transport, you can explicitly configure it in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Configure HTTP/1.1 transport.</span>
HttpClientTransportOverHTTP transport = <span class="keyword">new</span> HttpClientTransportOverHTTP();
transport.setHeaderCacheSize(<span class="integer">16384</span>);
HttpClient client = <span class="keyword">new</span> HttpClient(transport);
client.start();</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-http-transport-http2"><a class="anchor" href="#pg-client-http-transport-http2"></a><a class="link" href="#pg-client-http-transport-http2">HTTP/2 Transport</a></h5>
<div class="paragraph">
<p>The HTTP/2 transport can be configured in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// The HTTP2Client powers the HTTP/2 transport.</span>
HTTP2Client h2Client = <span class="keyword">new</span> HTTP2Client();
h2Client.setInitialSessionRecvWindow(<span class="integer">64</span> * <span class="integer">1024</span> * <span class="integer">1024</span>);
<span class="comment">// Create and configure the HTTP/2 transport.</span>
HttpClientTransportOverHTTP2 transport = <span class="keyword">new</span> HttpClientTransportOverHTTP2(h2Client);
transport.setUseALPN(<span class="predefined-constant">true</span>);
HttpClient client = <span class="keyword">new</span> HttpClient(transport);
client.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>HTTP2Client</code> is the lower-level client that provides an API based on HTTP/2 concepts such as <em>sessions</em>, <em>streams</em> and <em>frames</em> that are specific to HTTP/2. See <a href="#pg-client-http2">the HTTP/2 client section</a> for more information.</p>
</div>
<div class="paragraph">
<p><code>HttpClientTransportOverHTTP2</code> uses <code>HTTP2Client</code> to format high-level semantic HTTP requests (like "GET resource /index.html") into the HTTP/2 specific format.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-http-transport-fcgi"><a class="anchor" href="#pg-client-http-transport-fcgi"></a><a class="link" href="#pg-client-http-transport-fcgi">FastCGI Transport</a></h5>
<div class="paragraph">
<p>The FastCGI transport can be configured in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">String</span> scriptRoot = <span class="string"><span class="delimiter">&quot;</span><span class="content">/var/www/wordpress</span><span class="delimiter">&quot;</span></span>;
HttpClientTransportOverFCGI transport = <span class="keyword">new</span> HttpClientTransportOverFCGI(scriptRoot);
HttpClient client = <span class="keyword">new</span> HttpClient(transport);
client.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>In order to make requests using the FastCGI transport, you need to have a FastCGI server such as <a href="https://en.wikipedia.org/wiki/PHP#PHPFPM">PHP-FPM</a> (see also <a href="http://php.net/manual/en/install.fpm.php" class="bare">http://php.net/manual/en/install.fpm.php</a>).</p>
</div>
<div class="paragraph">
<p>The FastCGI transport is primarily used by Jetty&#8217;s <a href="#fastcgi">FastCGI support</a> to serve PHP pages (WordPress for example).</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-http-transport-dynamic"><a class="anchor" href="#pg-client-http-transport-dynamic"></a><a class="link" href="#pg-client-http-transport-dynamic">Dynamic Transport</a></h5>
<div class="paragraph">
<p>The static transports work well if you know in advance the protocol you want to speak with the server, or if the server only supports one protocol (such as FastCGI).</p>
</div>
<div class="paragraph">
<p>With the advent of HTTP/2, however, servers are now able to support multiple protocols, at least both HTTP/1.1 and HTTP/2.</p>
</div>
<div class="paragraph">
<p>The HTTP/2 protocol is typically negotiated between client and server.
This negotiation can happen via ALPN, a TLS extension that allows the client to tell the server the list of protocol that the client supports, so that the server can pick one of the client supported protocols that also the server supports; or via HTTP/1.1 upgrade by means of the <code>Upgrade</code> header.</p>
</div>
<div class="paragraph">
<p>Applications can configure the dynamic transport with one or more <em>application</em> protocols such as HTTP/1.1 or HTTP/2. The implementation will take care of using TLS for HTTPS URIs, using ALPN if necessary, negotiating protocols, upgrading from one protocol to another, etc.</p>
</div>
<div class="paragraph">
<p>By default, the dynamic transport only speaks HTTP/1.1:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Dynamic transport speaks HTTP/1.1 by default.</span>
HttpClientTransportDynamic transport = <span class="keyword">new</span> HttpClientTransportDynamic();
HttpClient client = <span class="keyword">new</span> HttpClient(transport);
client.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The dynamic transport can be configured with just one protocol, making it equivalent to the corresponding static transport:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ClientConnector connector = <span class="keyword">new</span> ClientConnector();
<span class="comment">// Equivalent to HttpClientTransportOverHTTP.</span>
HttpClientTransportDynamic http11Transport = <span class="keyword">new</span> HttpClientTransportDynamic(connector, HttpClientConnectionFactory.HTTP11);
<span class="comment">// Equivalent to HttpClientTransportOverHTTP2.</span>
HTTP2Client http2Client = <span class="keyword">new</span> HTTP2Client(connector);
HttpClientTransportDynamic http2Transport = <span class="keyword">new</span> HttpClientTransportDynamic(connector, <span class="keyword">new</span> ClientConnectionFactoryOverHTTP2.HTTP2(http2Client));</code></pre>
</div>
</div>
<div class="paragraph">
<p>The dynamic transport, however, has been implemented to support multiple transports, in particular both HTTP/1.1 and HTTP/2:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ClientConnector connector = <span class="keyword">new</span> ClientConnector();
ClientConnectionFactory.Info http1 = HttpClientConnectionFactory.HTTP11;
HTTP2Client http2Client = <span class="keyword">new</span> HTTP2Client(connector);
ClientConnectionFactoryOverHTTP2.HTTP2 http2 = <span class="keyword">new</span> ClientConnectionFactoryOverHTTP2.HTTP2(http2Client);
HttpClientTransportDynamic transport = <span class="keyword">new</span> HttpClientTransportDynamic(connector, http1, http2);
HttpClient client = <span class="keyword">new</span> HttpClient(transport);
client.start();</code></pre>
</div>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
The order in which the protocols are specified to <code>HttpClientTransportDynamic</code> indicates what is the client preference.
If the protocol is negotiated via ALPN, it is the server that decides what is the protocol to use for the communication, regardless of the client preference.
If the protocol is not negotiated, the client preference is honored.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Provided that the server supports both HTTP/1.1 and HTTP/2 clear-text, client applications can explicitly hint the version they want to use:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ClientConnector connector = <span class="keyword">new</span> ClientConnector();
ClientConnectionFactory.Info http1 = HttpClientConnectionFactory.HTTP11;
HTTP2Client http2Client = <span class="keyword">new</span> HTTP2Client(connector);
ClientConnectionFactoryOverHTTP2.HTTP2 http2 = <span class="keyword">new</span> ClientConnectionFactoryOverHTTP2.HTTP2(http2Client);
HttpClientTransportDynamic transport = <span class="keyword">new</span> HttpClientTransportDynamic(connector, http1, http2);
HttpClient client = <span class="keyword">new</span> HttpClient(transport);
client.start();
<span class="comment">// The server supports both HTTP/1.1 and HTTP/2 clear-text on port 8080.</span>
<span class="comment">// Make a clear-text request without explicit version.</span>
<span class="comment">// The first protocol specified to HttpClientTransportDynamic</span>
<span class="comment">// is picked, in this example will be HTTP/1.1.</span>
ContentResponse http1Response = client.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">host</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>).send();
<span class="comment">// Make a clear-text request with explicit version.</span>
<span class="comment">// Clear-text HTTP/2 is used for this request.</span>
ContentResponse http2Response = client.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">host</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>)
<span class="comment">// Specify the version explicitly.</span>
.version(HttpVersion.HTTP_2)
.send();
<span class="comment">// Make a clear-text upgrade request from HTTP/1.1 to HTTP/2.</span>
<span class="comment">// The request will start as HTTP/1.1, but the response will be HTTP/2.</span>
ContentResponse upgradedResponse = client.newRequest(<span class="string"><span class="delimiter">&quot;</span><span class="content">host</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>)
.headers(headers -&gt; headers
.put(HttpHeader.UPGRADE, <span class="string"><span class="delimiter">&quot;</span><span class="content">h2c</span><span class="delimiter">&quot;</span></span>)
.put(HttpHeader.HTTP2_SETTINGS, <span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span>)
.put(HttpHeader.CONNECTION, <span class="string"><span class="delimiter">&quot;</span><span class="content">Upgrade, HTTP2-Settings</span><span class="delimiter">&quot;</span></span>))
.send();</code></pre>
</div>
</div>
<div class="paragraph">
<p>In case of TLS encrypted communication using the HTTPS scheme, things are a little more complicated.</p>
</div>
<div class="paragraph">
<p>If the client application explicitly specifies the HTTP version, then ALPN is not used on the client.
By specifying the HTTP version explicitly, the client application has prior-knowledge of what HTTP version the server supports, and therefore ALPN is not needed.
If the server does not support the HTTP version chosen by the client, then the communication will fail.</p>
</div>
<div class="paragraph">
<p>If the client application does not explicitly specify the HTTP version, then ALPN will be used on the client.
If the server also supports ALPN, then the protocol will be negotiated via ALPN and the server will choose the protocol to use.
If the server does not support ALPN, the client will try to use the first protocol configured in <code>HttpClientTransportDynamic</code>, and the communication may succeed or fail depending on whether the server supports the protocol chosen by the client.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-client-http2"><a class="anchor" href="#pg-client-http2"></a><a class="link" href="#pg-client-http2">HTTP/2 Client Library</a></h3>
<div class="paragraph">
<p>In the vast majority of cases, client applications should use the generic, high-level, <a href="#pg-client-http">HTTP client library</a> that also provides HTTP/2 support via the pluggable <a href="#pg-client-http-transport-http2">HTTP/2 transport</a> or the <a href="#pg-client-http-transport-dynamic">dynamic transport</a>.</p>
</div>
<div class="paragraph">
<p>The high-level HTTP library supports cookies, authentication, redirection, connection pooling and a number of other features that are absent in the low-level HTTP/2 library.</p>
</div>
<div class="paragraph">
<p>The HTTP/2 client library has been designed for those applications that need low-level access to HTTP/2 features such as <em>sessions</em>, <em>streams</em> and <em>frames</em>, and this is quite a rare use case.</p>
</div>
<div class="paragraph">
<p>See also the correspondent <a href="#pg-server-http2">HTTP/2 server library</a>.</p>
</div>
<div class="sect3">
<h4 id="pg-client-http2-intro"><a class="anchor" href="#pg-client-http2-intro"></a><a class="link" href="#pg-client-http2-intro">Introducing HTTP2Client</a></h4>
<div class="paragraph">
<p>The Maven artifact coordinates for the HTTP/2 client library are the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty.http2<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>http2-client<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The main class is named <code>org.eclipse.jetty.http2.client.HTTP2Client</code>, and must be created, configured and started before use:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Instantiate HTTP2Client.</span>
HTTP2Client http2Client = <span class="keyword">new</span> HTTP2Client();
<span class="comment">// Configure HTTP2Client, for example:</span>
http2Client.setStreamIdleTimeout(<span class="integer">15000</span>);
<span class="comment">// Start HTTP2Client.</span>
http2Client.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>When your application stops, or otherwise does not need <code>HTTP2Client</code> anymore, it should stop the <code>HTTP2Client</code> instance (or instances) that were started:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Stop HTTP2Client.</span>
http2Client.stop();</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>HTTP2Client</code> allows client applications to connect to an HTTP/2 server.
A <em>session</em> represents a single TCP connection to an HTTP/2 server and is defined by class <code>org.eclipse.jetty.http2.api.Session</code>.
A <em>session</em> typically has a long life&#8201;&#8212;&#8201;once the TCP connection is established, it remains open until it is not used anymore (and therefore it is closed by the idle timeout mechanism), until a fatal error occurs (for example, a network failure), or if one of the peers decides unilaterally to close the TCP connection.</p>
</div>
<div class="paragraph">
<p>HTTP/2 is a multiplexed protocol: it allows multiple HTTP/2 requests to be sent on the same TCP connection.
Each request/response cycle is represented by a <em>stream</em>.
Therefore, a single <em>session</em> manages multiple concurrent <em>streams</em>.
A <em>stream</em> has typically a very short life compared to the <em>session</em>: a <em>stream</em> only exists for the duration of the request/response cycle and then disappears.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http2-flow-control"><a class="anchor" href="#pg-client-http2-flow-control"></a><a class="link" href="#pg-client-http2-flow-control">HTTP/2 Flow Control</a></h4>
<div class="paragraph">
<p>The HTTP/2 protocol is <em>flow controlled</em> (see <a href="https://tools.ietf.org/html/rfc7540#section-5.2">the specification</a>).
This means that a sender and a receiver maintain a <em>flow control window</em> that tracks the number of data bytes sent and received, respectively.
When a sender sends data bytes, it reduces its flow control window.
When a receiver receives data bytes, it also reduces its flow control window, and then passes the received data bytes to the application.
The application consumes the data bytes and tells back the receiver that it has consumed the data bytes.
The receiver then enlarges the flow control window, and arranges to send a message to the sender with the number of bytes consumed, so that the sender can enlarge its flow control window.</p>
</div>
<div class="paragraph">
<p>A sender can send data bytes up to its whole flow control window, then it must stop sending until it receives a message from the receiver that the data bytes have been consumed, which enlarges the flow control window, which allows the sender to send more data bytes.</p>
</div>
<div class="paragraph">
<p>HTTP/2 defines <em>two</em> flow control windows: one for each <em>session</em>, and one for each <em>stream</em>.
Let&#8217;s see with an example how they interact, assuming that in this example the session flow control window is 120 bytes and the stream flow control window is 100 bytes.</p>
</div>
<div class="paragraph">
<p>The sender opens a session, and then opens <code>stream_1</code> on that session, and sends <code>80</code> data bytes.
At this point the session flow control window is <code>40</code> bytes (<code>120 - 80</code>), and <code>stream_1</code>'s flow control window is <code>20</code> bytes (<code>100 - 80</code>).
The sender now opens <code>stream_2</code> on the same session and sends <code>40</code> data bytes.
At this point, the session flow control window is <code>0</code> bytes (<code>40 - 40</code>), while <code>stream_2</code>'s flow control window is <code>60</code> (<code>100 - 40</code>).
Since now the session flow control window is <code>0</code>, the sender cannot send more data bytes, neither on <code>stream_1</code> nor on <code>stream_2</code> despite both have their stream flow control windows greater than <code>0</code>.</p>
</div>
<div class="paragraph">
<p>The receiver consumes <code>stream_2</code>'s <code>40</code> data bytes and sends a message to the sender with this information.
At this point, the session flow control window is <code>40</code> (<code>0 40</code>), <code>stream_1</code>'s flow control window is still <code>20</code> and <code>stream_2</code>'s flow control window is <code>100</code> (<code>60 40</code>).
If the sender opens <code>stream_3</code> and would like to send 50 data bytes, it would only be able to send <code>40</code> because that is the maximum allowed by the session flow control window at this point.</p>
</div>
<div class="paragraph">
<p>It is therefore very important that applications notify the fact that they have consumed data bytes as soon as possible, so that the implementation (the receiver) can send a message to the sender (in the form of a <code>WINDOW_UPDATE</code> frame) with the information to enlarge the flow control window, therefore reducing the possibility that sender stalls due to the flow control windows being reduced to <code>0</code>.</p>
</div>
<div class="paragraph">
<p>How a client application should handle HTTP/2 flow control is discussed in details in <a href="#pg-client-http2-response">this section</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http2-connect"><a class="anchor" href="#pg-client-http2-connect"></a><a class="link" href="#pg-client-http2-connect">Connecting to the Server</a></h4>
<div class="paragraph">
<p>The first thing an application should do is to connect to the server and obtain a <code>Session</code>.
The following example connects to the server on a clear-text port:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Address of the server's clear-text port.</span>
<span class="predefined-type">SocketAddress</span> serverAddress = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>);
<span class="comment">// Connect to the server, the CompletableFuture will be</span>
<span class="comment">// notified when the connection is succeeded (or failed).</span>
CompletableFuture&lt;Session&gt; sessionCF = http2Client.connect(serverAddress, <span class="keyword">new</span> Session.Listener.Adapter());
<span class="comment">// Block to obtain the Session.</span>
<span class="comment">// Alternatively you can use the CompletableFuture APIs to avoid blocking.</span>
Session session = sessionCF.get();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example connects to the server on an encrypted port:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HTTP2Client http2Client = <span class="keyword">new</span> HTTP2Client();
http2Client.start();
ClientConnector connector = http2Client.getClientConnector();
<span class="comment">// Address of the server's encrypted port.</span>
<span class="predefined-type">SocketAddress</span> serverAddress = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>, <span class="integer">8443</span>);
<span class="comment">// Connect to the server, the CompletableFuture will be</span>
<span class="comment">// notified when the connection is succeeded (or failed).</span>
CompletableFuture&lt;Session&gt; sessionCF = http2Client.connect(connector.getSslContextFactory(), serverAddress, <span class="keyword">new</span> Session.Listener.Adapter());
<span class="comment">// Block to obtain the Session.</span>
<span class="comment">// Alternatively you can use the CompletableFuture APIs to avoid blocking.</span>
Session session = sessionCF.get();</code></pre>
</div>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Applications must know in advance whether they want to connect to a clear-text or encrypted port, and pass the <code>SslContextFactory</code> parameter accordingly to the <code>connect(&#8230;&#8203;)</code> method.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http2-configure"><a class="anchor" href="#pg-client-http2-configure"></a><a class="link" href="#pg-client-http2-configure">Configuring the Session</a></h4>
<div class="paragraph">
<p>The <code>connect(&#8230;&#8203;)</code> method takes a <code>Session.Listener</code> parameter.
This listener&#8217;s <code>onPreface(&#8230;&#8203;)</code> method is invoked just before establishing the connection to the server to gather the client configuration to send to the server.
Client applications can override this method to change the default configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">SocketAddress</span> serverAddress = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>);
http2Client.connect(serverAddress, <span class="keyword">new</span> Session.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Map</span>&lt;<span class="predefined-type">Integer</span>, <span class="predefined-type">Integer</span>&gt; onPreface(Session session)
{
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">Integer</span>, <span class="predefined-type">Integer</span>&gt; configuration = <span class="keyword">new</span> <span class="predefined-type">HashMap</span>&lt;&gt;();
<span class="comment">// Disable push from the server.</span>
configuration.put(SettingsFrame.ENABLE_PUSH, <span class="integer">0</span>);
<span class="comment">// Override HTTP2Client.initialStreamRecvWindow for this session.</span>
configuration.put(SettingsFrame.INITIAL_WINDOW_SIZE, <span class="integer">1024</span> * <span class="integer">1024</span>);
<span class="keyword">return</span> configuration;
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Session.Listener</code> is notified of session events originated by the server such as receiving a <code>SETTINGS</code> frame from the server, or the server closing the connection, or the client timing out the connection due to idleness.
Please refer to the <code>Session.Listener</code> <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http2/api/Session.Listener.html">javadocs</a> for the complete list of events.</p>
</div>
<div class="paragraph">
<p>Once a <code>Session</code> has been established, the communication with the server happens by exchanging <em>frames</em>, as specified in the <a href="https://tools.ietf.org/html/rfc7540#section-4">HTTP/2 specification</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http2-request"><a class="anchor" href="#pg-client-http2-request"></a><a class="link" href="#pg-client-http2-request">Sending a Request</a></h4>
<div class="paragraph">
<p>Sending an HTTP request to the server, and receiving a response, creates a <em>stream</em> that encapsulates the exchange of HTTP/2 frames that compose the request and the response.</p>
</div>
<div class="paragraph">
<p>In order to send an HTTP request to the server, the client must send a <code>HEADERS</code> frame.
<code>HEADERS</code> frames carry the request method, the request URI and the request headers.
Sending the <code>HEADERS</code> frame opens the <code>Stream</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">SocketAddress</span> serverAddress = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>);
CompletableFuture&lt;Session&gt; sessionCF = http2Client.connect(serverAddress, <span class="keyword">new</span> Session.Listener.Adapter());
Session session = sessionCF.get();
<span class="comment">// Configure the request headers.</span>
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.USER_AGENT, <span class="string"><span class="delimiter">&quot;</span><span class="content">Jetty HTTP2Client 10.0.6</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// The request metadata with method, URI and headers.</span>
MetaData.Request request = <span class="keyword">new</span> MetaData.Request(<span class="string"><span class="delimiter">&quot;</span><span class="content">GET</span><span class="delimiter">&quot;</span></span>, HttpURI.from(<span class="string"><span class="delimiter">&quot;</span><span class="content"><a href="http://localhost:8080/path" class="bare">http://localhost:8080/path</a></span><span class="delimiter">&quot;</span></span>), HttpVersion.HTTP_2, requestHeaders);
<span class="comment">// The HTTP/2 HEADERS frame, with endStream=true</span>
<span class="comment">// to signal that this request has no content.</span>
HeadersFrame headersFrame = <span class="keyword">new</span> HeadersFrame(request, <span class="predefined-constant">null</span>, <span class="predefined-constant">true</span>);
<span class="comment">// Open a Stream by sending the HEADERS frame.</span>
session.newStream(headersFrame, <span class="keyword">new</span> Stream.Listener.Adapter());</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how <code>Session.newStream(&#8230;&#8203;)</code> takes a <code>Stream.Listener</code> parameter.
This listener is notified of stream events originated by the server such as receiving <code>HEADERS</code> or <code>DATA</code> frames that are part of the response, discussed in more details in the <a href="#pg-client-http2-response">section below</a>.
Please refer to the <code>Stream.Listener</code> <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http2/api/Stream.Listener.html">javadocs</a> for the complete list of events.</p>
</div>
<div class="paragraph">
<p>HTTP requests may have content, which is sent using the <code>Stream</code> APIs:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">SocketAddress</span> serverAddress = <span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>, <span class="integer">8080</span>);
CompletableFuture&lt;Session&gt; sessionCF = http2Client.connect(serverAddress, <span class="keyword">new</span> Session.Listener.Adapter());
Session session = sessionCF.get();
<span class="comment">// Configure the request headers.</span>
HttpFields requestHeaders = HttpFields.build()
.put(HttpHeader.CONTENT_TYPE, <span class="string"><span class="delimiter">&quot;</span><span class="content">application/json</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// The request metadata with method, URI and headers.</span>
MetaData.Request request = <span class="keyword">new</span> MetaData.Request(<span class="string"><span class="delimiter">&quot;</span><span class="content">POST</span><span class="delimiter">&quot;</span></span>, HttpURI.from(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://localhost:8080/path</span><span class="delimiter">&quot;</span></span>), HttpVersion.HTTP_2, requestHeaders);
<span class="comment">// The HTTP/2 HEADERS frame, with endStream=false to</span>
<span class="comment">// signal that there will be more frames in this stream.</span>
HeadersFrame headersFrame = <span class="keyword">new</span> HeadersFrame(request, <span class="predefined-constant">null</span>, <span class="predefined-constant">false</span>);
<span class="comment">// Open a Stream by sending the HEADERS frame.</span>
CompletableFuture&lt;Stream&gt; streamCF = session.newStream(headersFrame, <span class="keyword">new</span> Stream.Listener.Adapter());
<span class="comment">// Block to obtain the Stream.</span>
<span class="comment">// Alternatively you can use the CompletableFuture APIs to avoid blocking.</span>
Stream stream = streamCF.get();
<span class="comment">// The request content, in two chunks.</span>
<span class="predefined-type">String</span> content1 = <span class="string"><span class="delimiter">&quot;</span><span class="content">{</span><span class="char">\&quot;</span><span class="content">greet</span><span class="char">\&quot;</span><span class="content">: </span><span class="char">\&quot;</span><span class="content">hello world</span><span class="char">\&quot;</span><span class="content">}</span><span class="delimiter">&quot;</span></span>;
<span class="predefined-type">ByteBuffer</span> buffer1 = StandardCharsets.UTF_8.encode(content1);
<span class="predefined-type">String</span> content2 = <span class="string"><span class="delimiter">&quot;</span><span class="content">{</span><span class="char">\&quot;</span><span class="content">user</span><span class="char">\&quot;</span><span class="content">: </span><span class="char">\&quot;</span><span class="content">jetty</span><span class="char">\&quot;</span><span class="content">}</span><span class="delimiter">&quot;</span></span>;
<span class="predefined-type">ByteBuffer</span> buffer2 = StandardCharsets.UTF_8.encode(content2);
<span class="comment">// Send the first DATA frame on the stream, with endStream=false</span>
<span class="comment">// to signal that there are more frames in this stream.</span>
CompletableFuture&lt;Stream&gt; dataCF1 = stream.data(<span class="keyword">new</span> DataFrame(stream.getId(), buffer1, <span class="predefined-constant">false</span>));
<span class="comment">// Only when the first chunk has been sent we can send the second,</span>
<span class="comment">// with endStream=true to signal that there are no more frames.</span>
dataCF1.thenCompose(s -&gt; s.data(<span class="keyword">new</span> DataFrame(s.getId(), buffer2, <span class="predefined-constant">true</span>)));</code></pre>
</div>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
When sending two <code>DATA</code> frames consecutively, the second call to <code>Stream.data(&#8230;&#8203;)</code> must be done only when the first is completed, or a <code>WritePendingException</code> will be thrown.
Use the <code>Callback</code> APIs or <code>CompletableFuture</code> APIs to ensure that the second <code>Stream.data(&#8230;&#8203;)</code> call is performed when the first completed successfully.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http2-response"><a class="anchor" href="#pg-client-http2-response"></a><a class="link" href="#pg-client-http2-response">Receiving a Response</a></h4>
<div class="paragraph">
<p>Response events are delivered to the <code>Stream.Listener</code> passed to <code>Session.newStream(&#8230;&#8203;)</code>.</p>
</div>
<div class="paragraph">
<p>An HTTP response is typically composed of a <code>HEADERS</code> frame containing the HTTP status code and the response headers, and optionally one or more <code>DATA</code> frames containing the response content bytes.</p>
</div>
<div class="paragraph">
<p>The HTTP/2 protocol also supports response trailers (that is, headers that are sent after the response content) that also are sent using a <code>HEADERS</code> frame.</p>
</div>
<div class="paragraph">
<p>A client application can therefore receive the HTTP/2 frames sent by the server by implementing the relevant methods in <code>Stream.Listener</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Open a Stream by sending the HEADERS frame.</span>
session.newStream(headersFrame, <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onHeaders(Stream stream, HeadersFrame frame)
{
MetaData metaData = frame.getMetaData();
<span class="comment">// Is this HEADERS frame the response or the trailers?</span>
<span class="keyword">if</span> (metaData.isResponse())
{
MetaData.Response response = (MetaData.Response)metaData;
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">http2</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Received response {0}</span><span class="delimiter">&quot;</span></span>, response);
}
<span class="keyword">else</span>
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">http2</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Received trailers {0}</span><span class="delimiter">&quot;</span></span>, metaData.getFields());
}
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onData(Stream stream, DataFrame frame, <span class="predefined-type">Callback</span> callback)
{
<span class="comment">// Get the content buffer.</span>
<span class="predefined-type">ByteBuffer</span> buffer = frame.getData();
<span class="comment">// Consume the buffer, here - as an example - just log it.</span>
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">http2</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Consuming buffer {0}</span><span class="delimiter">&quot;</span></span>, buffer);
<span class="comment">// Tell the implementation that the buffer has been consumed.</span>
callback.succeeded();
<span class="comment">// By returning from the method, implicitly tell the implementation</span>
<span class="comment">// to deliver to this method more DATA frames when they are available.</span>
}
});</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Returning from the <code>onData(&#8230;&#8203;)</code> method implicitly demands for more <code>DATA</code> frames (unless the one just delivered was the last).
Additional <code>DATA</code> frames may be delivered immediately if they are available or later, asynchronously, when they arrive.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Applications that consume the content buffer within <code>onData(&#8230;&#8203;)</code> (for example, writing it to a file, or copying the bytes to another storage) should succeed the callback as soon as they have consumed the content buffer.
This allows the implementation to reuse the buffer, reducing the memory requirements needed to handle the content buffers.</p>
</div>
<div class="paragraph">
<p>Alternatively, a client application may store away <em>both</em> the buffer and the callback to consume the buffer bytes later, or pass <em>both</em> the buffer and the callback to another asynchronous API (this is typical in proxy applications).</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Completing the <code>Callback</code> is very important not only to allow the implementation to reuse the buffer, but also tells the implementation to enlarge the stream and session flow control windows so that the sender will be able to send more <code>DATA</code> frames without stalling.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Applications can also precisely control <em>when</em> to demand more <code>DATA</code> frames, by implementing the <code>onDataDemanded(&#8230;&#8203;)</code> method instead of <code>onData(&#8230;&#8203;)</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">Chunk</span>
{
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">ByteBuffer</span> buffer;
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">Callback</span> callback;
Chunk(<span class="predefined-type">ByteBuffer</span> buffer, <span class="predefined-type">Callback</span> callback)
{
<span class="local-variable">this</span>.buffer = buffer;
<span class="local-variable">this</span>.callback = callback;
}
}
<span class="comment">// A queue that consumers poll to consume content asynchronously.</span>
<span class="predefined-type">Queue</span>&lt;Chunk&gt; dataQueue = <span class="keyword">new</span> <span class="predefined-type">ConcurrentLinkedQueue</span>&lt;&gt;();
<span class="comment">// Implementation of Stream.Listener.onDataDemanded(...)</span>
<span class="comment">// in case of asynchronous content consumption and demand.</span>
Stream.Listener listener = <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onDataDemanded(Stream stream, DataFrame frame, <span class="predefined-type">Callback</span> callback)
{
<span class="comment">// Get the content buffer.</span>
<span class="predefined-type">ByteBuffer</span> buffer = frame.getData();
<span class="comment">// Store buffer to consume it asynchronously, and wrap the callback.</span>
dataQueue.offer(<span class="keyword">new</span> Chunk(buffer, <span class="predefined-type">Callback</span>.from(() -&gt;
{
<span class="comment">// When the buffer has been consumed, then:</span>
<span class="comment">// A) succeed the nested callback.</span>
callback.succeeded();
<span class="comment">// B) demand more DATA frames.</span>
stream.demand(<span class="integer">1</span>);
}, callback::failed)));
<span class="comment">// Do not demand more content here, to avoid to overflow the queue.</span>
}
};</code></pre>
</div>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Applications that implement <code>onDataDemanded(&#8230;&#8203;)</code> must remember to call <code>Stream.demand(&#8230;&#8203;)</code>.
If they don&#8217;t, the implementation will not deliver <code>DATA</code> frames and the application will stall threadlessly until an idle timeout fires to close the stream or the session.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http2-reset"><a class="anchor" href="#pg-client-http2-reset"></a><a class="link" href="#pg-client-http2-reset">Resetting a Request or Response</a></h4>
<div class="paragraph">
<p>In HTTP/2, clients and servers have the ability to tell to the other peer that they are not interested anymore in either the request or the response, using a <code>RST_STREAM</code> frame.</p>
</div>
<div class="paragraph">
<p>The <code>HTTP2Client</code> APIs allow client applications to send and receive this "reset" frame:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Open a Stream by sending the HEADERS frame.</span>
CompletableFuture&lt;Stream&gt; streamCF = session.newStream(headersFrame, <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onReset(Stream stream, ResetFrame frame)
{
<span class="comment">// The server reset this stream.</span>
}
});
Stream stream = streamCF.get();
<span class="comment">// Reset this stream (for example, the user closed the application).</span>
stream.reset(<span class="keyword">new</span> ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), <span class="predefined-type">Callback</span>.NOOP);</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-http2-push"><a class="anchor" href="#pg-client-http2-push"></a><a class="link" href="#pg-client-http2-push">Receiving HTTP/2 Pushes</a></h4>
<div class="paragraph">
<p>HTTP/2 servers have the ability to push resources related to a primary resource.
When an HTTP/2 server pushes a resource, it sends to the client a <code>PUSH_PROMISE</code> frame that contains the request URI and headers that a client would use to request explicitly that resource.</p>
</div>
<div class="paragraph">
<p>Client applications can be configured to tell the server to never push resources, see <a href="#pg-client-http2-configure">this section</a>.</p>
</div>
<div class="paragraph">
<p>Client applications can listen to the push events, and act accordingly:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Open a Stream by sending the HEADERS frame.</span>
CompletableFuture&lt;Stream&gt; streamCF = session.newStream(headersFrame, <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> Stream.Listener onPush(Stream pushedStream, PushPromiseFrame frame)
{
<span class="comment">// The &quot;request&quot; the client would make for the pushed resource.</span>
MetaData.Request pushedRequest = frame.getMetaData();
<span class="comment">// The pushed &quot;request&quot; URI.</span>
HttpURI pushedURI = pushedRequest.getURI();
<span class="comment">// The pushed &quot;request&quot; headers.</span>
HttpFields pushedRequestHeaders = pushedRequest.getFields();
<span class="comment">// If needed, retrieve the primary stream that triggered the push.</span>
Stream primaryStream = pushedStream.getSession().getStream(frame.getStreamId());
<span class="comment">// Return a Stream.Listener to listen for the pushed &quot;response&quot; events.</span>
<span class="keyword">return</span> <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onHeaders(Stream stream, HeadersFrame frame)
{
<span class="comment">// Handle the pushed stream &quot;response&quot;.</span>
MetaData metaData = frame.getMetaData();
<span class="keyword">if</span> (metaData.isResponse())
{
<span class="comment">// The pushed &quot;response&quot; headers.</span>
HttpFields pushedResponseHeaders = metaData.getFields();
}
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onData(Stream stream, DataFrame frame, <span class="predefined-type">Callback</span> callback)
{
<span class="comment">// Handle the pushed stream &quot;response&quot; content.</span>
<span class="comment">// The pushed stream &quot;response&quot; content bytes.</span>
<span class="predefined-type">ByteBuffer</span> buffer = frame.getData();
<span class="comment">// Consume the buffer and complete the callback.</span>
callback.succeeded();
}
};
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>If a client application does not want to handle a particular HTTP/2 push, it can just reset the pushed stream to tell the server to stop sending bytes for the pushed stream:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Open a Stream by sending the HEADERS frame.</span>
CompletableFuture&lt;Stream&gt; streamCF = session.newStream(headersFrame, <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> Stream.Listener onPush(Stream pushedStream, PushPromiseFrame frame)
{
<span class="comment">// Reset the pushed stream to tell the server we are not interested.</span>
pushedStream.reset(<span class="keyword">new</span> ResetFrame(pushedStream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), <span class="predefined-type">Callback</span>.NOOP);
<span class="comment">// Not interested in listening to pushed response events.</span>
<span class="keyword">return</span> <span class="predefined-constant">null</span>;
}
});</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-client-websocket"><a class="anchor" href="#pg-client-websocket"></a><a class="link" href="#pg-client-websocket">WebSocket Client</a></h3>
<div class="paragraph">
<p>Jetty&#8217;s <code>WebSocketClient</code> is a more powerful alternative to the WebSocket client provided by the standard JSR 356 <code>javax.websocket</code> APIs.</p>
</div>
<div class="paragraph">
<p>Similarly to Jetty&#8217;s <a href="#pg-client-http"><code>HttpClient</code></a>, the <code>WebSocketClient</code> is non-blocking and asynchronous, making it very efficient in resource utilization.
A synchronous, blocking, API is also offered for simpler cases.</p>
</div>
<div class="paragraph">
<p>Since the first step of establishing a WebSocket communication is an HTTP request, <code>WebSocketClient</code> makes use of <code>HttpClient</code> and therefore depends on it.</p>
</div>
<div class="paragraph">
<p>The Maven artifact coordinates are the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty.websocket<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>websocket-jetty-client<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-websocket-start"><a class="anchor" href="#pg-client-websocket-start"></a><a class="link" href="#pg-client-websocket-start">Starting WebSocketClient</a></h4>
<div class="paragraph">
<p>The main class is <code>org.eclipse.jetty.websocket.client.WebSocketClient</code>; you instantiate it, configure it, and then start it like may other Jetty components.
This is a minimal example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Instantiate WebSocketClient.</span>
WebSocketClient webSocketClient = <span class="keyword">new</span> WebSocketClient();
<span class="comment">// Configure WebSocketClient, for example:</span>
webSocketClient.setMaxTextMessageSize(<span class="integer">8</span> * <span class="integer">1024</span>);
<span class="comment">// Start WebSocketClient.</span>
webSocketClient.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>However, it is recommended that you explicitly pass an <code>HttpClient</code> instance to <code>WebSocketClient</code> so that you can have control over the HTTP configuration as well:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Instantiate and configure HttpClient.</span>
HttpClient httpClient = <span class="keyword">new</span> HttpClient();
<span class="comment">// For example, configure a proxy.</span>
httpClient.getProxyConfiguration().getProxies().add(<span class="keyword">new</span> HttpProxy(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>, <span class="integer">8888</span>));
<span class="comment">// Instantiate WebSocketClient, passing HttpClient to the constructor.</span>
WebSocketClient webSocketClient = <span class="keyword">new</span> WebSocketClient(httpClient);
<span class="comment">// Configure WebSocketClient, for example:</span>
webSocketClient.setMaxTextMessageSize(<span class="integer">8</span> * <span class="integer">1024</span>);
<span class="comment">// Start WebSocketClient; this implicitly starts also HttpClient.</span>
webSocketClient.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>You may create multiple instances of <code>WebSocketClient</code>, but typically one instance is enough for most applications.
Creating multiple instances may be necessary for example when you need to specify different configuration parameters for different instances.
For example, you may need different instances when you need to configure the <code>HttpClient</code> differently: different transports, different proxies, different cookie stores, different authentications, etc.</p>
</div>
<div class="paragraph">
<p>WebSocket specific configuration may be typically be given a default value in <code>WebSocketClient</code> and then overridden more specifically, see for example <a href="#pg-websocket-session-configure">this section</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-websocket-stop"><a class="anchor" href="#pg-client-websocket-stop"></a><a class="link" href="#pg-client-websocket-stop">Stopping WebSocketClient</a></h4>
<div class="paragraph">
<p>It is recommended that when your application stops, you also stop the <code>WebSocketClient</code> instance (or instances) that you are using.</p>
</div>
<div class="paragraph">
<p>Similarly to <a href="#pg-client-http-stop">stopping <code>HttpClient</code></a>, you want to stop <code>WebSocketClient</code> from a thread that is not owned by <code>WebSocketClient</code> itself, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Stop WebSocketClient.</span>
<span class="comment">// Use LifeCycle.stop(...) to rethrow checked exceptions as unchecked.</span>
<span class="keyword">new</span> <span class="predefined-type">Thread</span>(() -&gt; LifeCycle.stop(webSocketClient)).start();</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-client-websocket-connect"><a class="anchor" href="#pg-client-websocket-connect"></a><a class="link" href="#pg-client-websocket-connect">Connecting to a Remote Host</a></h4>
<div class="paragraph">
<p>A WebSocket client may initiate the communication with the server either <a href="#pg-client-websocket-connect-http11">using HTTP/1.1</a> or <a href="#pg-client-websocket-connect-http2">using HTTP/2</a>.
The two mechanism are quite different and detailed in the following sections.</p>
</div>
<div class="sect4">
<h5 id="pg-client-websocket-connect-http11"><a class="anchor" href="#pg-client-websocket-connect-http11"></a><a class="link" href="#pg-client-websocket-connect-http11">Using HTTP/1.1</a></h5>
<div class="paragraph">
<p>Initiating a WebSocket communication with a server using HTTP/1.1 is detailed in <a href="https://tools.ietf.org/html/rfc6455#section-1.8">RFC 6455</a>.</p>
</div>
<div class="paragraph">
<p>A WebSocket client first establishes a TCP connection to the server, then sends an HTTP/1.1 <em>upgrade</em> request.</p>
</div>
<div class="paragraph">
<p>If the server supports upgrading to WebSocket, it responds with HTTP status code <code>101</code>, and then switches the communication over that connection, either incoming or outgoing, to happen using the WebSocket protocol.</p>
</div>
<div class="paragraph">
<p>When the client receives the HTTP status code <code>101</code>, it switches the communication over that connection, either incoming or outgoing, to happen using the WebSocket protocol.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-fada5fbf7628dc70c998680727a069bd.png" alt="Diagram" width="695" height="514">
</div>
</div>
<div class="paragraph">
<p>In code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Use a standard, HTTP/1.1, HttpClient.</span>
HttpClient httpClient = <span class="keyword">new</span> HttpClient();
<span class="comment">// Create and start WebSocketClient.</span>
WebSocketClient webSocketClient = <span class="keyword">new</span> WebSocketClient(httpClient);
webSocketClient.start();
<span class="comment">// The client-side WebSocket EndPoint that</span>
<span class="comment">// receives WebSocket messages from the server.</span>
ClientEndPoint clientEndPoint = <span class="keyword">new</span> ClientEndPoint();
<span class="comment">// The server URI to connect to.</span>
<span class="predefined-type">URI</span> serverURI = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">ws://domain.com/path</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Connect the client EndPoint to the server.</span>
CompletableFuture&lt;Session&gt; clientSessionPromise = webSocketClient.connect(clientEndPoint, serverURI);</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>WebSocketClient.connect()</code> links the client-side WebSocket <em>endpoint</em> to a specific server URI, and returns a <code>CompletableFuture</code> of an <code>org.eclipse.jetty.websocket.api.Session</code>.</p>
</div>
<div class="paragraph">
<p>The endpoint offers APIs to <em>receive</em> WebSocket data (or errors) from the server, while the session offers APIs to <em>send</em> WebSocket data to the server.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-websocket-connect-http2"><a class="anchor" href="#pg-client-websocket-connect-http2"></a><a class="link" href="#pg-client-websocket-connect-http2">Using HTTP/2</a></h5>
<div class="paragraph">
<p>Initiating a WebSocket communication with a server using HTTP/1.1 is detailed in <a href="https://tools.ietf.org/html/rfc8441">RFC 8441</a>.</p>
</div>
<div class="paragraph">
<p>A WebSocket client establishes a TCP connection to the server or reuses an existing one currently used for HTTP/2, then sends an HTTP/2 <em>connect</em> request over an HTTP/2 stream.</p>
</div>
<div class="paragraph">
<p>If the server supports upgrading to WebSocket, it responds with HTTP status code <code>200</code>, then switches the communication over that stream, either incoming or outgoing, to happen using HTTP/2 <code>DATA</code> frames wrapping WebSocket frames.</p>
</div>
<div class="paragraph">
<p>When the client receives the HTTP status code <code>200</code>, it switches the communication over that stream, either incoming or outgoing, to happen using HTTP/2 <code>DATA</code> frames wrapping WebSocket frames.</p>
</div>
<div class="paragraph">
<p>From an external point of view, it will look like client is sending chunks of an infinite HTTP/2 request upload, and the server is sending chunks of an infinite HTTP/2 response download, as they will exchange HTTP/2 <code>DATA</code> frames; but the HTTP/2 <code>DATA</code> frames will contain each one or more WebSocket frames that both client and server know how to deliver to the respective WebSocket endpoints.</p>
</div>
<div class="paragraph">
<p>When either WebSocket endpoint decides to terminate the communication, the HTTP/2 stream will be closed as well.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-1ed737fca2f0d63f7ebac20672a2e222.png" alt="Diagram" width="684" height="575">
</div>
</div>
<div class="paragraph">
<p>In code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Use the HTTP/2 transport for HttpClient.</span>
HTTP2Client http2Client = <span class="keyword">new</span> HTTP2Client();
HttpClient httpClient = <span class="keyword">new</span> HttpClient(<span class="keyword">new</span> HttpClientTransportOverHTTP2(http2Client));
<span class="comment">// Create and start WebSocketClient.</span>
WebSocketClient webSocketClient = <span class="keyword">new</span> WebSocketClient(httpClient);
webSocketClient.start();
<span class="comment">// The client-side WebSocket EndPoint that</span>
<span class="comment">// receives WebSocket messages from the server.</span>
ClientEndPoint clientEndPoint = <span class="keyword">new</span> ClientEndPoint();
<span class="comment">// The server URI to connect to.</span>
<span class="predefined-type">URI</span> serverURI = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">wss://domain.com/path</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Connect the client EndPoint to the server.</span>
CompletableFuture&lt;Session&gt; clientSessionPromise = webSocketClient.connect(clientEndPoint, serverURI);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively, you can use the <a href="#pg-client-http-transport-dynamic">dynamic <code>HttpClient</code> transport</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Use the dynamic HTTP/2 transport for HttpClient.</span>
HTTP2Client http2Client = <span class="keyword">new</span> HTTP2Client();
HttpClient httpClient = <span class="keyword">new</span> HttpClient(<span class="keyword">new</span> HttpClientTransportDynamic(<span class="keyword">new</span> ClientConnectionFactoryOverHTTP2.HTTP2(http2Client)));
<span class="comment">// Create and start WebSocketClient.</span>
WebSocketClient webSocketClient = <span class="keyword">new</span> WebSocketClient(httpClient);
webSocketClient.start();
ClientEndPoint clientEndPoint = <span class="keyword">new</span> ClientEndPoint();
<span class="predefined-type">URI</span> serverURI = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">wss://domain.com/path</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Connect the client EndPoint to the server.</span>
CompletableFuture&lt;Session&gt; clientSessionPromise = webSocketClient.connect(clientEndPoint, serverURI);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-websocket-connect-custom-http-request"><a class="anchor" href="#pg-client-websocket-connect-custom-http-request"></a><a class="link" href="#pg-client-websocket-connect-custom-http-request">Customizing the Initial HTTP Request</a></h5>
<div class="paragraph">
<p>Sometimes you need to add custom cookies, or other HTTP headers, or specify a WebSocket sub-protocol to the HTTP request that initiates the WebSocket communication.</p>
</div>
<div class="paragraph">
<p>You can do this by using overloaded versions of the <code>WebSocketClient.connect(&#8230;&#8203;)</code> method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ClientEndPoint clientEndPoint = <span class="keyword">new</span> ClientEndPoint();
<span class="predefined-type">URI</span> serverURI = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">ws://domain.com/path</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Create a custom HTTP request.</span>
ClientUpgradeRequest customRequest = <span class="keyword">new</span> ClientUpgradeRequest();
<span class="comment">// Specify a cookie.</span>
customRequest.getCookies().add(<span class="keyword">new</span> HttpCookie(<span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">value</span><span class="delimiter">&quot;</span></span>));
<span class="comment">// Specify a custom header.</span>
customRequest.setHeader(<span class="string"><span class="delimiter">&quot;</span><span class="content">X-Token</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">0123456789ABCDEF</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Specify a custom sub-protocol.</span>
customRequest.setSubProtocols(<span class="string"><span class="delimiter">&quot;</span><span class="content">chat</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Connect the client EndPoint to the server with a custom HTTP request.</span>
CompletableFuture&lt;Session&gt; clientSessionPromise = webSocketClient.connect(clientEndPoint, serverURI, customRequest);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-client-websocket-connect-inspect-http-response"><a class="anchor" href="#pg-client-websocket-connect-inspect-http-response"></a><a class="link" href="#pg-client-websocket-connect-inspect-http-response">Inspecting the Initial HTTP Response</a></h5>
<div class="paragraph">
<p>If you want to inspect the HTTP response returned by the server as a reply to the HTTP request that initiates the WebSocket communication, you may provide a <code>JettyUpgradeListener</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ClientEndPoint clientEndPoint = <span class="keyword">new</span> ClientEndPoint();
<span class="predefined-type">URI</span> serverURI = <span class="predefined-type">URI</span>.create(<span class="string"><span class="delimiter">&quot;</span><span class="content">ws://domain.com/path</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// The listener to inspect the HTTP response.</span>
JettyUpgradeListener listener = <span class="keyword">new</span> JettyUpgradeListener()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onHandshakeResponse(HttpRequest request, HttpResponse response)
{
<span class="comment">// Inspect the HTTP response here.</span>
}
};
<span class="comment">// Connect the client EndPoint to the server with a custom HTTP request.</span>
CompletableFuture&lt;Session&gt; clientSessionPromise = webSocketClient.connect(clientEndPoint, serverURI, <span class="predefined-constant">null</span>, listener);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-websocket-architecture"><a class="anchor" href="#pg-websocket-architecture"></a><a class="link" href="#pg-websocket-architecture">WebSocket Architecture</a></h4>
<div class="paragraph">
<p>The Jetty WebSocket architecture is organized around the concept of a logical <em>connection</em> between the client and the server.</p>
</div>
<div class="paragraph">
<p>The connection may be physical, when connecting to the server using HTTP/1.1, as the WebSocket bytes are carried directly by the TCP connection.</p>
</div>
<div class="paragraph">
<p>The connection may be virtual, when connecting to the server using HTTP/2, as the WebSocket bytes are wrapped into HTTP/2 <code>DATA</code> frames of an HTTP/2 stream.
In this case, a single TCP connection may carry several WebSocket virtual connections, each wrapped in its own HTTP/2 stream.</p>
</div>
<div class="paragraph">
<p>Each side of a WebSocket connection, either client or server, is made of two entities:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A <a href="#pg-websocket-endpoints">WebSocket <em>endpoint</em></a>, the entity that <em>receives</em> WebSocket events.</p>
</li>
<li>
<p>A <a href="#pg-websocket-session">WebSocket <em>session</em></a>, the entity that offers an API to <em>send</em> WebSocket data (and to close the WebSocket connection), as well as to configure WebSocket connection parameters.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="pg-websocket-endpoints"><a class="anchor" href="#pg-websocket-endpoints"></a><a class="link" href="#pg-websocket-endpoints">WebSocket Endpoints</a></h4>
<div class="paragraph">
<p>A WebSocket endpoint is the entity that receives WebSocket events.</p>
</div>
<div class="paragraph">
<p>The WebSocket events are the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The <em>connect</em> event.
This event is emitted when the WebSocket communication has been successfully established.
Applications interested in the connect event receive the WebSocket <em>session</em> so that they can use it to send data to the remote peer.</p>
</li>
<li>
<p>The <em>close</em> event.
This event is emitted when the WebSocket communication has been closed.
Applications interested in the close event receive a WebSocket status code and an optional close reason message.</p>
</li>
<li>
<p>The <em>error</em> event.
This event is emitted when the WebSocket communication encounters a fatal error, such as an I/O error (for example, the network connection has been broken), or a protocol error (for example, the remote peer sends an invalid WebSocket frame).
Applications interested in the error event receive a <code>Throwable</code> that represent the error.</p>
</li>
<li>
<p>The <em>message</em> event.
The message event is emitted when a WebSocket message is received.
The message event can be of two types:</p>
<div class="ulist">
<ul>
<li>
<p>Textual message event.
Applications interested in this type of messages receive a <code>String</code> representing the UTF-8 bytes received.</p>
</li>
<li>
<p>Binary message event.
Applications interested in this type of messages receive a <code>byte[]</code> representing the raw bytes received.</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="sect4">
<h5 id="pg-websocket-endpoints-listener"><a class="anchor" href="#pg-websocket-endpoints-listener"></a><a class="link" href="#pg-websocket-endpoints-listener">Listener Endpoints</a></h5>
<div class="paragraph">
<p>A WebSocket endpoint may implement the <code>org.eclipse.jetty.websocket.api.WebSocketListener</code> interface to receive WebSocket events:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ListenerEndPoint</span> <span class="directive">implements</span> WebSocketListener <i class="conum" data-value="1"></i><b>(1)</b>
{
<span class="directive">private</span> Session session;
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketConnect(Session session)
{
<span class="comment">// The WebSocket connection is established.</span>
<span class="comment">// Store the session to be able to send data to the remote peer.</span>
<span class="local-variable">this</span>.session = session;
<span class="comment">// You may configure the session.</span>
session.setMaxTextMessageSize(<span class="integer">16</span> * <span class="integer">1024</span>);
<span class="comment">// You may immediately send a message to the remote peer.</span>
session.getRemote().sendString(<span class="string"><span class="delimiter">&quot;</span><span class="content">connected</span><span class="delimiter">&quot;</span></span>, WriteCallback.NOOP);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketClose(<span class="type">int</span> statusCode, <span class="predefined-type">String</span> reason)
{
<span class="comment">// The WebSocket connection is closed.</span>
<span class="comment">// You may dispose resources.</span>
disposeResources();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketError(<span class="predefined-type">Throwable</span> cause)
{
<span class="comment">// The WebSocket connection failed.</span>
<span class="comment">// You may log the error.</span>
cause.printStackTrace();
<span class="comment">// You may dispose resources.</span>
disposeResources();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketText(<span class="predefined-type">String</span> message)
{
<span class="comment">// A WebSocket textual message is received.</span>
<span class="comment">// You may echo it back if it matches certain criteria.</span>
<span class="keyword">if</span> (message.startsWith(<span class="string"><span class="delimiter">&quot;</span><span class="content">echo:</span><span class="delimiter">&quot;</span></span>))
session.getRemote().sendString(message.substring(<span class="string"><span class="delimiter">&quot;</span><span class="content">echo:</span><span class="delimiter">&quot;</span></span>.length()), WriteCallback.NOOP);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketBinary(<span class="type">byte</span><span class="type">[]</span> payload, <span class="type">int</span> offset, <span class="type">int</span> length)
{
<span class="comment">// A WebSocket binary message is received.</span>
<span class="comment">// Save only PNG images.</span>
<span class="type">byte</span><span class="type">[]</span> pngBytes = <span class="keyword">new</span> <span class="type">byte</span><span class="type">[]</span>{(<span class="type">byte</span>)<span class="hex">0x89</span>, <span class="string"><span class="delimiter">'</span><span class="content">P</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">N</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">G</span><span class="delimiter">'</span></span>};
<span class="keyword">for</span> (<span class="type">int</span> i = <span class="integer">0</span>; i &lt; pngBytes.length; ++i)
{
<span class="keyword">if</span> (pngBytes[i] != payload[offset + i])
<span class="keyword">return</span>;
}
savePNGImage(payload, offset, length);
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Your listener class implements <code>WebSocketListener</code>.</td>
</tr>
</table>
</div>
<div class="sect5">
<h6 id="pg-message-streaming-reads"><a class="anchor" href="#pg-message-streaming-reads"></a><a class="link" href="#pg-message-streaming-reads">Message Streaming Reads</a></h6>
<div class="paragraph">
<p>If you need to deal with large WebSocket messages, you may reduce the memory usage by streaming the message content.
For large WebSocket messages, the memory usage may be large due to the fact that the text or the bytes must be accumulated until the message is complete before delivering the message event.</p>
</div>
<div class="paragraph">
<p>To stream textual or binary messages, you must implement interface <code>org.eclipse.jetty.websocket.api.WebSocketPartialListener</code> instead of <code>WebSocketListener</code>.</p>
</div>
<div class="paragraph">
<p>Interface <code>WebSocketPartialListener</code> exposes one method for textual messages, and one method to binary messages that receive <em>chunks</em> of, respectively, text and bytes that form the whole WebSocket message.</p>
</div>
<div class="paragraph">
<p>You may accumulate the chunks yourself, or process each chunk as it arrives, or stream the chunks elsewhere, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">StreamingListenerEndpoint</span> <span class="directive">implements</span> WebSocketPartialListener
{
<span class="directive">private</span> Path textPath;
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketPartialText(<span class="predefined-type">String</span> payload, <span class="type">boolean</span> fin)
{
<span class="comment">// Forward chunks to external REST service.</span>
forwardToREST(payload, fin);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketPartialBinary(<span class="predefined-type">ByteBuffer</span> payload, <span class="type">boolean</span> fin)
{
<span class="comment">// Save chunks to file.</span>
appendToFile(payload, fin);
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-websocket-endpoints-annotated"><a class="anchor" href="#pg-websocket-endpoints-annotated"></a><a class="link" href="#pg-websocket-endpoints-annotated">Annotated Endpoints</a></h5>
<div class="paragraph">
<p>A WebSocket endpoint may annotate methods with <code>org.eclipse.jetty.websocket.api.annotations.*</code> annotations to receive WebSocket events.
Each annotated method may take an optional <code>Session</code> argument as its first parameter:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@WebSocket</span> <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnotatedEndPoint</span>
{
<span class="directive">private</span> Session session;
<span class="annotation">@OnWebSocketConnect</span> <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> <span class="type">void</span> onConnect(Session session)
{
<span class="comment">// The WebSocket connection is established.</span>
<span class="comment">// Store the session to be able to send data to the remote peer.</span>
<span class="local-variable">this</span>.session = session;
<span class="comment">// You may configure the session.</span>
session.setMaxTextMessageSize(<span class="integer">16</span> * <span class="integer">1024</span>);
<span class="comment">// You may immediately send a message to the remote peer.</span>
session.getRemote().sendString(<span class="string"><span class="delimiter">&quot;</span><span class="content">connected</span><span class="delimiter">&quot;</span></span>, WriteCallback.NOOP);
}
<span class="annotation">@OnWebSocketClose</span> <i class="conum" data-value="3"></i><b>(3)</b>
<span class="directive">public</span> <span class="type">void</span> onClose(<span class="type">int</span> statusCode, <span class="predefined-type">String</span> reason)
{
<span class="comment">// The WebSocket connection is closed.</span>
<span class="comment">// You may dispose resources.</span>
disposeResources();
}
<span class="annotation">@OnWebSocketError</span> <i class="conum" data-value="4"></i><b>(4)</b>
<span class="directive">public</span> <span class="type">void</span> onError(<span class="predefined-type">Throwable</span> cause)
{
<span class="comment">// The WebSocket connection failed.</span>
<span class="comment">// You may log the error.</span>
cause.printStackTrace();
<span class="comment">// You may dispose resources.</span>
disposeResources();
}
<span class="annotation">@OnWebSocketMessage</span> <i class="conum" data-value="5"></i><b>(5)</b>
<span class="directive">public</span> <span class="type">void</span> onTextMessage(Session session, <span class="predefined-type">String</span> message) <i class="conum" data-value="3"></i><b>(3)</b>
{
<span class="comment">// A WebSocket textual message is received.</span>
<span class="comment">// You may echo it back if it matches certain criteria.</span>
<span class="keyword">if</span> (message.startsWith(<span class="string"><span class="delimiter">&quot;</span><span class="content">echo:</span><span class="delimiter">&quot;</span></span>))
session.getRemote().sendString(message.substring(<span class="string"><span class="delimiter">&quot;</span><span class="content">echo:</span><span class="delimiter">&quot;</span></span>.length()), WriteCallback.NOOP);
}
<span class="annotation">@OnWebSocketMessage</span> <i class="conum" data-value="5"></i><b>(5)</b>
<span class="directive">public</span> <span class="type">void</span> onBinaryMessage(<span class="type">byte</span><span class="type">[]</span> payload, <span class="type">int</span> offset, <span class="type">int</span> length)
{
<span class="comment">// A WebSocket binary message is received.</span>
<span class="comment">// Save only PNG images.</span>
<span class="type">byte</span><span class="type">[]</span> pngBytes = <span class="keyword">new</span> <span class="type">byte</span><span class="type">[]</span>{(<span class="type">byte</span>)<span class="hex">0x89</span>, <span class="string"><span class="delimiter">'</span><span class="content">P</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">N</span><span class="delimiter">'</span></span>, <span class="string"><span class="delimiter">'</span><span class="content">G</span><span class="delimiter">'</span></span>};
<span class="keyword">for</span> (<span class="type">int</span> i = <span class="integer">0</span>; i &lt; pngBytes.length; ++i)
{
<span class="keyword">if</span> (pngBytes[i] != payload[offset + i])
<span class="keyword">return</span>;
}
savePNGImage(payload, offset, length);
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Use the <code>@WebSocket</code> annotation at the class level to make it a WebSocket endpoint.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Use the <code>@OnWebSocketConnect</code> annotation for the <em>connect</em> event.
As this is the first event notified to the endpoint, you can configure the <code>Session</code> object.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Use the <code>@OnWebSocketClose</code> annotation for the <em>close</em> event.
The method may take an optional <code>Session</code> as first parameter.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Use the <code>@OnWebSocketError</code> annotation for the <em>error</em> event.
The method may take an optional <code>Session</code> as first parameter.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Use the <code>@OnWebSocketMessage</code> annotation for the <em>message</em> event, both for textual and binary messages.
The method may take an optional <code>Session</code> as first parameter.</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For binary messages, you may declare the annotated method with either or these two signatures:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> methodName(<span class="type">byte</span><span class="type">[]</span> bytes, <span class="type">int</span> offset, <span class="type">int</span> length) { ... }</code></pre>
</div>
</div>
<div class="paragraph">
<p>or</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> methodName(<span class="predefined-type">ByteBuffer</span> buffer) { ... }</code></pre>
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="sect5">
<h6 id="pg-message-streaming-reads-2"><a class="anchor" href="#pg-message-streaming-reads-2"></a><a class="link" href="#pg-message-streaming-reads-2">Message Streaming Reads</a></h6>
<div class="paragraph">
<p>If you need to deal with large WebSocket messages, you may reduce the memory usage by streaming the message content.</p>
</div>
<div class="paragraph">
<p>To stream textual or binary messages, you still use the <code>@OnWebSocketMessage</code> annotation, but you change the signature of the method to take, respectively a <code>Reader</code> and an <code>InputStream</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@WebSocket</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">StreamingAnnotatedEndpoint</span>
{
<span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> onTextMessage(<span class="predefined-type">Reader</span> reader)
{
<span class="comment">// Read chunks and forward.</span>
forwardToREST(reader);
}
<span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> onBinaryMessage(<span class="predefined-type">InputStream</span> stream)
{
<span class="comment">// Save chunks to file.</span>
appendToFile(stream);
}
}</code></pre>
</div>
</div>
<div class="admonitionblock caution">
<table>
<tr>
<td class="icon">
<i class="fa icon-caution" title="Caution"></i>
</td>
<td class="content">
<div class="paragraph">
<p><code>Reader</code> or <code>InputStream</code> only offer blocking APIs, so if the remote peers are slow in sending the large WebSocket messages, reading threads may be blocked in <code>Reader.read(char[])</code> or <code>InputStream.read(byte[])</code>, possibly exhausting the thread pool.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-websocket-session"><a class="anchor" href="#pg-websocket-session"></a><a class="link" href="#pg-websocket-session">WebSocket Session</a></h4>
<div class="paragraph">
<p>A WebSocket session is the entity that offers an API to send data to the remote peer, to close the WebSocket connection, and to configure WebSocket connection parameters.</p>
</div>
<div class="sect4">
<h5 id="pg-websocket-session-configure"><a class="anchor" href="#pg-websocket-session-configure"></a><a class="link" href="#pg-websocket-session-configure">Configuring the Session</a></h5>
<div class="paragraph">
<p>You may configure the WebSocket session behavior using the <code>org.eclipse.jetty.websocket.api.Session</code> APIs.
You want to do this as soon as you have access to the <code>Session</code> object, typically from the <a href="#pg-websocket-endpoints"><em>connect</em> event</a> handler:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ConfigureEndpoint</span> <span class="directive">implements</span> WebSocketListener
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketConnect(Session session)
{
<span class="comment">// Configure the max length of incoming messages.</span>
session.setMaxTextMessageSize(<span class="integer">16</span> * <span class="integer">1024</span>);
<span class="comment">// Configure the idle timeout.</span>
session.setIdleTimeout(<span class="predefined-type">Duration</span>.ofSeconds(<span class="integer">30</span>));
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Please refer to the <code>Session</code> <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/websocket/api/Session.html">javadocs</a> for the complete list of configuration APIs.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-websocket-session-send"><a class="anchor" href="#pg-websocket-session-send"></a><a class="link" href="#pg-websocket-session-send">Sending Data</a></h5>
<div class="paragraph">
<p>To send data to the remote peer, you need to obtain the <code>RemoteEndpoint</code> object from the <code>Session</code>, and then use its API to send data.</p>
</div>
<div class="paragraph">
<p><code>RemoteEndpoint</code> offers two styles of APIs to send data:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Blocking APIs, where the call returns when the data has been sent, or throws an <code>IOException</code> if the data cannot be sent.</p>
</li>
<li>
<p>Non-blocking APIs, where a callback object is notified when the data has been sent, or when there was a failure sending the data.</p>
</li>
</ul>
</div>
<div class="sect5">
<h6 id="pg-websocket-session-send-blocking"><a class="anchor" href="#pg-websocket-session-send-blocking"></a><a class="link" href="#pg-websocket-session-send-blocking">Blocking APIs</a></h6>
<div class="paragraph">
<p><code>RemoteEndpoint</code> blocking APIs throw <code>IOException</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@WebSocket</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">BlockingSendEndpoint</span>
{
<span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> onText(Session session, <span class="predefined-type">String</span> text)
{
<span class="comment">// Obtain the RemoteEndpoint APIs.</span>
RemoteEndpoint remote = session.getRemote();
<span class="keyword">try</span>
{
<span class="comment">// Send textual data to the remote peer.</span>
remote.sendString(<span class="string"><span class="delimiter">&quot;</span><span class="content">data</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Send binary data to the remote peer.</span>
<span class="predefined-type">ByteBuffer</span> bytes = readImageFromFile();
remote.sendBytes(bytes);
<span class="comment">// Send a PING frame to the remote peer.</span>
remote.sendPing(<span class="predefined-type">ByteBuffer</span>.allocate(<span class="integer">8</span>).putLong(<span class="predefined-type">System</span>.nanoTime()).flip());
}
<span class="keyword">catch</span> (<span class="exception">IOException</span> x)
{
<span class="comment">// No need to rethrow or close the session.</span>
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">websocket</span><span class="delimiter">&quot;</span></span>).log(<span class="predefined-type">System</span>.Logger.Level.WARNING, <span class="string"><span class="delimiter">&quot;</span><span class="content">could not send data</span><span class="delimiter">&quot;</span></span>, x);
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Blocking APIs are simpler to use since they can be invoked one after the other sequentially.</p>
</div>
<div class="admonitionblock caution">
<table>
<tr>
<td class="icon">
<i class="fa icon-caution" title="Caution"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Sending large messages to the remote peer may cause the sending thread to block, possibly exhausting the thread pool.
Consider using non-blocking APIs for large messages.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect5">
<h6 id="pg-websocket-session-send-non-blocking"><a class="anchor" href="#pg-websocket-session-send-non-blocking"></a><a class="link" href="#pg-websocket-session-send-non-blocking">Non-Blocking APIs</a></h6>
<div class="paragraph">
<p><code>RemoteEndpoint</code> non-blocking APIs have an additional callback parameter:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@WebSocket</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">NonBlockingSendEndpoint</span>
{
<span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> onText(Session session, <span class="predefined-type">String</span> text)
{
<span class="comment">// Obtain the RemoteEndpoint APIs.</span>
RemoteEndpoint remote = session.getRemote();
<span class="comment">// Send textual data to the remote peer.</span>
remote.sendString(<span class="string"><span class="delimiter">&quot;</span><span class="content">data</span><span class="delimiter">&quot;</span></span>, <span class="keyword">new</span> WriteCallback() <i class="conum" data-value="1"></i><b>(1)</b>
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> writeSuccess()
{
<span class="comment">// Send binary data to the remote peer.</span>
<span class="predefined-type">ByteBuffer</span> bytes = readImageFromFile();
remote.sendBytes(bytes, <span class="keyword">new</span> WriteCallback() <i class="conum" data-value="2"></i><b>(2)</b>
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> writeSuccess()
{
<span class="comment">// Both sends succeeded.</span>
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> writeFailed(<span class="predefined-type">Throwable</span> x)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">websocket</span><span class="delimiter">&quot;</span></span>).log(<span class="predefined-type">System</span>.Logger.Level.WARNING, <span class="string"><span class="delimiter">&quot;</span><span class="content">could not send binary data</span><span class="delimiter">&quot;</span></span>, x);
}
});
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> writeFailed(<span class="predefined-type">Throwable</span> x)
{
<span class="comment">// No need to rethrow or close the session.</span>
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">websocket</span><span class="delimiter">&quot;</span></span>).log(<span class="predefined-type">System</span>.Logger.Level.WARNING, <span class="string"><span class="delimiter">&quot;</span><span class="content">could not send textual data</span><span class="delimiter">&quot;</span></span>, x);
}
});
<span class="comment">// remote.sendString(&quot;wrong&quot;, WriteCallback.NOOP); // May throw WritePendingException! </span><i class="conum" data-value="3"></i><b>(3)</b>
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Non-blocking APIs require a <code>WriteCallback</code> parameter.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Note how the second send must be performed from inside the callback.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Sequential sends may throw <code>WritePendingException</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Non-blocking APIs are more difficult to use since you are required to meet the following condition:</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>You cannot initiate another send of any kind until the previous send is completed.</p>
</div>
<div class="paragraph">
<p>For example, if you have initiated a text send, you cannot initiate a binary send, until the previous send has completed.</p>
</div>
<div class="paragraph">
<p>Furthermore, if you have initiated a non-blocking send, you cannot initiate a blocking send, until the previous send has completed.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This requirement is necessary to avoid unbounded buffering that could lead to <code>OutOfMemoryError</code>s.</p>
</div>
<div class="admonitionblock caution">
<table>
<tr>
<td class="icon">
<i class="fa icon-caution" title="Caution"></i>
</td>
<td class="content">
<div class="paragraph">
<p>We strongly recommend that you follow the condition above.</p>
</div>
<div class="paragraph">
<p>However, there may be cases where you want to explicitly control the number of outgoing buffered messages using <code>RemoteEndpoint.setMaxOutgoingFrames(int)</code>.</p>
</div>
<div class="paragraph">
<p>Remember that trying to control the number of outgoing buffered messages is very difficult and tricky; you may set <code>maxOutgoingFrames=4</code> and have a situation where 6 threads try to concurrently send messages: threads 1 to 4 will be able to successfully buffer their messages, thread 5 may fail, but thread 6 may succeed because one of the previous threads completed its send.
At this point you have an out-of-order message delivery that could be unexpected and very difficult to troubleshoot because it will happen non-deterministically.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>While non-blocking APIs are more difficult to use, they don&#8217;t block the sender thread and therefore use less resources, which in turn typically allows for greater scalability under load: with respect to blocking APIs, non-blocking APIs need less resources to cope with the same load.</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-websocket-session-send-stream"><a class="anchor" href="#pg-websocket-session-send-stream"></a><a class="link" href="#pg-websocket-session-send-stream">Streaming Send APIs</a></h6>
<div class="paragraph">
<p>If you need to send large WebSocket messages, you may reduce the memory usage by streaming the message content.</p>
</div>
<div class="paragraph">
<p>Both blocking and non-blocking APIs offer <code>sendPartial*(&#8230;&#8203;)</code> methods that allow you to send a chunk of the whole message at a time, therefore reducing the memory usage since it is not necessary to have the whole message <code>String</code> or <code>byte[]</code> in memory to send it.</p>
</div>
<div class="paragraph">
<p>Streaming sends using blocking APIs is quite simple:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@WebSocket</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">StreamSendBlockingEndpoint</span>
{
<span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> onText(Session session, <span class="predefined-type">String</span> text)
{
<span class="keyword">try</span>
{
RemoteEndpoint remote = session.getRemote();
<span class="keyword">while</span> (<span class="predefined-constant">true</span>)
{
<span class="predefined-type">ByteBuffer</span> chunk = readChunkToSend();
<span class="keyword">if</span> (chunk == <span class="predefined-constant">null</span>)
{
<span class="comment">// No more bytes, finish the WebSocket message.</span>
remote.sendPartialBytes(<span class="predefined-type">ByteBuffer</span>.allocate(<span class="integer">0</span>), <span class="predefined-constant">true</span>);
<span class="keyword">break</span>;
}
<span class="keyword">else</span>
{
<span class="comment">// Send the chunk.</span>
remote.sendPartialBytes(chunk, <span class="predefined-constant">false</span>);
}
}
}
<span class="keyword">catch</span> (<span class="exception">IOException</span> x)
{
x.printStackTrace();
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Streaming sends using non-blocking APIs is more complicated, as you should wait (without blocking!) for the callbacks to complete.</p>
</div>
<div class="paragraph">
<p>Fortunately, Jetty provides you with the <code>IteratingCallback</code> utility class (described in more details <a href="#pg-arch-io-echo">in this section</a>) which greatly simplify the use of non-blocking APIs:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@WebSocket</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">StreamSendNonBlockingEndpoint</span>
{
<span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> onText(Session session, <span class="predefined-type">String</span> text)
{
RemoteEndpoint remote = session.getRemote();
<span class="keyword">new</span> Sender(remote).iterate();
}
<span class="directive">private</span> <span class="type">class</span> <span class="class">Sender</span> <span class="directive">extends</span> IteratingCallback <span class="directive">implements</span> WriteCallback <i class="conum" data-value="1"></i><b>(1)</b>
{
<span class="directive">private</span> <span class="directive">final</span> RemoteEndpoint remote;
<span class="directive">private</span> <span class="type">boolean</span> finished;
<span class="directive">private</span> Sender(RemoteEndpoint remote)
{
<span class="local-variable">this</span>.remote = remote;
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="predefined-type">Action</span> process() <span class="directive">throws</span> <span class="predefined-type">Throwable</span> <i class="conum" data-value="2"></i><b>(2)</b>
{
<span class="keyword">if</span> (finished)
<span class="keyword">return</span> <span class="predefined-type">Action</span>.SUCCEEDED;
<span class="predefined-type">ByteBuffer</span> chunk = readChunkToSend();
<span class="keyword">if</span> (chunk == <span class="predefined-constant">null</span>)
{
<span class="comment">// No more bytes, finish the WebSocket message.</span>
remote.sendPartialBytes(<span class="predefined-type">ByteBuffer</span>.allocate(<span class="integer">0</span>), <span class="predefined-constant">true</span>, <span class="local-variable">this</span>); <i class="conum" data-value="3"></i><b>(3)</b>
finished = <span class="predefined-constant">true</span>;
<span class="keyword">return</span> <span class="predefined-type">Action</span>.SCHEDULED;
}
<span class="keyword">else</span>
{
<span class="comment">// Send the chunk.</span>
remote.sendPartialBytes(<span class="predefined-type">ByteBuffer</span>.allocate(<span class="integer">0</span>), <span class="predefined-constant">false</span>, <span class="local-variable">this</span>); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="keyword">return</span> <span class="predefined-type">Action</span>.SCHEDULED;
}
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> writeSuccess()
{
<span class="comment">// When the send succeeds, succeed this IteratingCallback.</span>
succeeded();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> writeFailed(<span class="predefined-type">Throwable</span> x)
{
<span class="comment">// When the send fails, fail this IteratingCallback.</span>
failed(x);
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> onCompleteFailure(<span class="predefined-type">Throwable</span> x)
{
x.printStackTrace();
}
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Implementing <code>WriteCallback</code> allows to pass <code>this</code> to <code>sendPartialBytes(&#8230;&#8203;)</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The <code>process()</code> method is called iteratively when each <code>sendPartialBytes(&#8230;&#8203;)</code> is completed.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Send the message chunks.</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-websocket-session-ping"><a class="anchor" href="#pg-websocket-session-ping"></a><a class="link" href="#pg-websocket-session-ping">Sending Ping/Pong</a></h5>
<div class="paragraph">
<p>The WebSocket protocol defines two special frame, named <code>Ping</code> and <code>Pong</code> that may be interesting to applications for these use cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Calculate the round-trip time with the remote peer.</p>
</li>
<li>
<p>Keep the connection from being closed due to idle timeout&#8201;&#8212;&#8201;a heartbeat-like mechanism.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>To handle <code>Ping</code>/<code>Pong</code> events, you may implement interface <code>org.eclipse.jetty.websocket.api.WebSocketPingPongListener</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p><code>Ping</code>/<code>Pong</code> events are not supported when using annotations.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>Ping</code> frames may contain opaque application bytes, and the WebSocket implementation replies to them with a <code>Pong</code> frame containing the same bytes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">RoundTripListenerEndpoint</span> <span class="directive">implements</span> WebSocketPingPongListener <i class="conum" data-value="1"></i><b>(1)</b>
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketConnect(Session session)
{
<span class="comment">// Send to the remote peer the local nanoTime.</span>
<span class="predefined-type">ByteBuffer</span> buffer = <span class="predefined-type">ByteBuffer</span>.allocate(<span class="integer">8</span>).putLong(<span class="predefined-type">System</span>.nanoTime()).flip();
session.getRemote().sendPing(buffer, WriteCallback.NOOP);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onWebSocketPong(<span class="predefined-type">ByteBuffer</span> payload)
{
<span class="comment">// The remote peer echoed back the local nanoTime.</span>
<span class="type">long</span> start = payload.getLong();
<span class="comment">// Calculate the round-trip time.</span>
<span class="type">long</span> roundTrip = <span class="predefined-type">System</span>.nanoTime() - start;
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The WebSocket endpoint class must implement <code>WebSocketPingPongListener</code></td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="pg-websocket-session-close"><a class="anchor" href="#pg-websocket-session-close"></a><a class="link" href="#pg-websocket-session-close">Closing the Session</a></h5>
<div class="paragraph">
<p>When you want to terminate the communication with the remote peer, you close the <code>Session</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@WebSocket</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">CloseEndpoint</span>
{
<span class="annotation">@OnWebSocketMessage</span>
<span class="directive">public</span> <span class="type">void</span> onText(Session session, <span class="predefined-type">String</span> text)
{
<span class="keyword">if</span> (<span class="string"><span class="delimiter">&quot;</span><span class="content">close</span><span class="delimiter">&quot;</span></span>.equalsIgnoreCase(text))
session.close(StatusCode.NORMAL, <span class="string"><span class="delimiter">&quot;</span><span class="content">bye</span><span class="delimiter">&quot;</span></span>);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Closing a WebSocket <code>Session</code> carries a status code and a reason message that the remote peer can inspect in the <em>close</em> event handler (see <a href="#pg-websocket-endpoints">this section</a>).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The reason message is optional, and may be truncated to fit into the WebSocket frame sent to the client.
It is best to use short tokens such as <code>"shutdown"</code>, or <code>"idle_timeout"</code>, etc. or even application specific codes such as <code>"0001"</code> or <code>"00AF"</code> that can be converted by the application into more meaningful messages.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="pg-server"><a class="anchor" href="#pg-server"></a><a class="link" href="#pg-server">Server Libraries</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Eclipse Jetty Project provides server-side libraries that allow you to configure and start programmatically an HTTP or WebSocket server from a main class, or embed it in your existing application.
A typical example is a HTTP server that needs to expose a REST endpoint.
Another example is a proxy application that receives HTTP requests, processes them, and then forwards them to third party services, for example using the Jetty <a href="#pg-client">client libraries</a>.</p>
</div>
<div class="paragraph">
<p>While historically Jetty is an HTTP server, it is possible to use the Jetty server-side libraries to write a generic network server that interprets any network protocol (not only HTTP).
If you are interested in the low-level details of how the Eclipse Jetty server libraries work, or are interested in writing a custom protocol, look at the <a href="#pg-server-io-arch">Server I/O Architecture</a>.</p>
</div>
<div class="paragraph">
<p>The Jetty server-side libraries provide:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>HTTP support for HTTP/1.0, HTTP/1.1, HTTP/2, clear-text or encrypted, for applications that want to embed Jetty as a generic HTTP server or proxy, via the <a href="#pg-server-http">HTTP libraries</a></p>
</li>
<li>
<p>HTTP/2 low-level support, for applications that want to explicitly handle low-level HTTP/2 <em>sessions</em>, <em>streams</em> and <em>frames</em>, via the <a href="#pg-server-http2">HTTP/2 libraries</a></p>
</li>
<li>
<p>WebSocket support, for applications that want to embed a WebSocket server, via the <a href="#pg-server-websocket">WebSocket libraries</a></p>
</li>
<li>
<p>FCGI support, to delegate requests to python or similar scripting languages.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="pg-server-compliance"><a class="anchor" href="#pg-server-compliance"></a><a class="link" href="#pg-server-compliance">Server Compliance Modes</a></h3>
<div class="paragraph">
<p>The Jetty server strives to keep up with the latest <a href="https://en.wikipedia.org/wiki/Request_for_Comments">IETF RFC</a>s for compliance with internet specifications, which are periodically updated.</p>
</div>
<div class="paragraph">
<p>When possible, Jetty will support backwards compatibility by providing compliance modes that can be configured to allow violations of the current specifications that may have been allowed in obsoleted specifications.</p>
</div>
<div class="paragraph">
<p>There are compliance modes provided for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#pg-server-compliance-http">HTTP Compliance</a></p>
</li>
<li>
<p><a href="#pg-server-compliance-uri">URI Compliance</a></p>
</li>
<li>
<p><a href="#pg-server-compliance-cookie">Cookie Compliance</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Compliance modes can be configured to allow violations from the RFC requirements, or in some cases to allow additional behaviors that Jetty has implemented in excess of the RFC (for example, to allow <a href="#pg-server-compliance-uri">ambiguous URIs</a>).</p>
</div>
<div class="paragraph">
<p>For example, the HTTP RFCs require that request HTTP methods are <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1">case sensitive</a>, however Jetty can allow case-insensitive HTTP methods by including the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/HttpCompliance.Violation.html#CASE_INSENSITIVE_METHOD"><code>HttpCompliance.Violation.CASE_INSENSITIVE_METHOD</code></a> in the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/HttpCompliance.html"><code>HttpCompliance</code></a> set of allowed violations.</p>
</div>
<div class="sect3">
<h4 id="pg-server-compliance-http"><a class="anchor" href="#pg-server-compliance-http"></a><a class="link" href="#pg-server-compliance-http">HTTP Compliance Modes</a></h4>
<div class="paragraph">
<p>In 1995, when Jetty was first implemented, there were no RFC specification of HTTP, only a W3C specification for <a href="https://www.w3.org/Protocols/HTTP/AsImplemented.html">HTTP/0.9</a>, which has since been obsoleted or augmented by:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://datatracker.ietf.org/doc/html/rfc1945">RFC 1945</a> for HTTP/1.0 in 1996</p>
</li>
<li>
<p><a href="https://datatracker.ietf.org/doc/html/rfc2068">RFC 2068</a> for HTTP/1.1 in 1997</p>
</li>
<li>
<p><a href="https://datatracker.ietf.org/doc/html/rfc2616">RFC 2616</a> for HTTP/1.1 bis in 1999</p>
</li>
<li>
<p><a href="https://datatracker.ietf.org/doc/html/rfc7230">RFC 7230</a>, <a href="https://datatracker.ietf.org/doc/html/rfc7231">RFC 7231</a>, <a href="https://datatracker.ietf.org/doc/html/rfc7232">RFC 7232</a>, <a href="https://datatracker.ietf.org/doc/html/rfc7233">RFC 7233</a>, <a href="https://datatracker.ietf.org/doc/html/rfc7234">RFC 7234</a>, <a href="https://datatracker.ietf.org/doc/html/rfc7235">RFC 7235</a> again for HTTP/1.1 in 2014</p>
</li>
<li>
<p><a href="https://datatracker.ietf.org/doc/html/rfc7540">RFC 7540</a> for HTTP/2.0 in 2015</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In addition to these evolving requirements, some earlier version of Jetty did not completely or strictly implement the RFC at the time (for example, case-insensitive HTTP methods).
Therefore, upgrading to a newer Jetty version may cause runtime behavior differences that may break your applications.</p>
</div>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/HttpCompliance.Violation.html"><code>HttpCompliance.Violation</code></a> enumeration defines the RFC requirements that may be optionally enforced by Jetty, to support legacy deployments. These possible violations are grouped into modes by the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/HttpCompliance.html"><code>HttpCompliance</code></a> class, which also defines several named modes that support common deployed sets of violations (with the default being <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/HttpCompliance.html#RFC7230"><code>HttpCompliance.RFC7230</code></a>).</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpConfiguration httpConfiguration = <span class="keyword">new</span> HttpConfiguration();
httpConfiguration.setHttpCompliance(HttpCompliance.RFC7230);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you want to customize the violations that you want to allow, you can create your own mode using the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/HttpCompliance.html#from(java.lang.String)"><code>HttpCompliance.from(String)</code></a> method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpConfiguration httpConfiguration = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// RFC7230 compliance, but allow Violation.MULTIPLE_CONTENT_LENGTHS.</span>
HttpCompliance customHttpCompliance = HttpCompliance.from(<span class="string"><span class="delimiter">&quot;</span><span class="content">RFC7230,MULTIPLE_CONTENT_LENGTHS</span><span class="delimiter">&quot;</span></span>);
httpConfiguration.setHttpCompliance(customHttpCompliance);</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-compliance-uri"><a class="anchor" href="#pg-server-compliance-uri"></a><a class="link" href="#pg-server-compliance-uri">URI Compliance Modes</a></h4>
<div class="paragraph">
<p>Universal Resource Locators (URLs) where initially formalized in 1994 in <a href="https://datatracker.ietf.org/doc/html/rfc1738">RFC 1738</a> and then refined in 1995 with relative URLs by <a href="https://datatracker.ietf.org/doc/html/rfc1808">RFC 1808</a>.</p>
</div>
<div class="paragraph">
<p>In 1998, URLs were generalized to Universal Resource Identifiers (URIs) by <a href="https://datatracker.ietf.org/doc/html/rfc2396">RFC 2396</a>, which also introduced features such a <a href="https://datatracker.ietf.org/doc/html/rfc2396#section-3.3">path parameter</a>s.</p>
</div>
<div class="paragraph">
<p>This was then obsoleted in 2005 by <a href="https://datatracker.ietf.org/doc/html/rfc3986">RFC 3986</a> which removed the definition for path parameters.</p>
</div>
<div class="paragraph">
<p>Unfortunately by this stage the existence and use of such parameters had already been codified in the Servlet specification.
For example, the relative URI <code>/foo/bar;JSESSIONID=a8b38cd02b1c</code> would define the path parameter <code>JSESSIONID</code> for the path segment <code>bar</code>, but the most recent RFC does not specify a formal definition of what this relative URI actually means.</p>
</div>
<div class="paragraph">
<p>The current situation is that there may be URIs that are entirely valid for <a href="https://datatracker.ietf.org/doc/html/rfc3986">RFC 3986</a>, but are ambiguous when handled by the Servlet APIs:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A URI with <code>..</code> <em>and</em> path parameters such as <code>/some/..;/path</code> is not <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-5.2"><em>resolved</em></a> by RFC 3986, since the resolution process only applies to the exact segment <code>..</code>, not to <code>..;</code>.
However, once the path parameters are removed by the Servlet APIs, the resulting <code>/some/../path</code> can easily be resolved to <code>/path</code>, rather than be treated as a path that has <code>..;</code> as a segment.</p>
</li>
<li>
<p>A URI such as <code>/some/%2e%2e/path</code> is not resolved by RFC 3986, yet when URL-decoded by the Servlet APIs will result in <code>/some/../path</code> which can easily be resolved to <code>/path</code>, rather than be treated as a path that has <code>..</code> as a segment.</p>
</li>
<li>
<p>A URI with empty segments like <code>/some//../path</code> may be correctly resolved to <code>/some/path</code> (the <code>..</code> removes the previous empty segment) by the Servlet APIs.
However, if the URI raw path is passed to some other APIs (for example, file system APIs) it can be interpreted as <code>/path</code> because the empty segment <code>//</code> is discarded and treated as <code>/</code>, and the <code>..</code> thus removes the <code>/some</code> segment.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In order to avoid ambiguous URIs, Jetty imposes additional URI requirements in excess of what is required by <a href="https://datatracker.ietf.org/doc/html/rfc3986">RFC 3986</a> compliance.</p>
</div>
<div class="paragraph">
<p>These additional requirements may optionally be violated and are defined by the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/UriCompliance.Violation.html"><code>UriCompliance.Violation</code></a> enumeration.</p>
</div>
<div class="paragraph">
<p>These violations are then grouped into modes by the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/UriCompliance.html"><code>UriCompliance</code></a> class, which also defines several named modes that support common deployed sets of violations, with the default being <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/UriCompliance.html#DEFAULT"><code>UriCompliance.DEFAULT</code></a>.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpConfiguration httpConfiguration = <span class="keyword">new</span> HttpConfiguration();
httpConfiguration.setUriCompliance(UriCompliance.RFC3986);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you want to customize the violations that you want to allow, you can create your own mode using the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/UriCompliance.html#from(java.lang.String)"><code>UriCompliance.from(String)</code></a> method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpConfiguration httpConfiguration = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// RFC3986 compliance, but enforce Violation.AMBIGUOUS_PATH_SEPARATOR.</span>
UriCompliance customUriCompliance = UriCompliance.from(<span class="string"><span class="delimiter">&quot;</span><span class="content">RFC3986,-AMBIGUOUS_PATH_SEPARATOR</span><span class="delimiter">&quot;</span></span>);
httpConfiguration.setUriCompliance(customUriCompliance);</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-compliance-cookie"><a class="anchor" href="#pg-server-compliance-cookie"></a><a class="link" href="#pg-server-compliance-cookie">Cookie Compliance Modes</a></h4>
<div class="paragraph">
<p>The standards for Cookies have varied greatly over time from a non-specified but de-facto standard (implemented by the first browsers), through <a href="https://tools.ietf.org/html/rfc2965">RFC 2965</a> and currently to <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>.</p>
</div>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/CookieCompliance.Violation.html">CookieCompliance.Violation</a> enumeration defines the RFC requirements that may be optionally enforced by Jetty when parsing the <code>Cookie</code> HTTP header in requests and when generating the <code>Set-Cookie</code> HTTP header in responses.</p>
</div>
<div class="paragraph">
<p>These violations are then grouped into modes by the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/CookieCompliance.html"><code>CookieCompliance</code></a> class, which also defines several named modes that support common deployed sets of violations, with the default being <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/CookieCompliance.html#RFC6265"><code>CookieCompliance.RFC6265</code></a>.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpConfiguration httpConfiguration = <span class="keyword">new</span> HttpConfiguration();
httpConfiguration.setRequestCookieCompliance(CookieCompliance.RFC6265);
httpConfiguration.setResponseCookieCompliance(CookieCompliance.RFC6265);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you want to customize the violations that you want to allow, you can create your own mode using the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http/CookieCompliance.html#from(java.lang.String)"><code>CookieCompliance.from(String)</code></a> method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpConfiguration httpConfiguration = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// RFC6265 compliance, but enforce Violation.RESERVED_NAMES_NOT_DOLLAR_PREFIXED.</span>
CookieCompliance customUriCompliance = CookieCompliance.from(<span class="string"><span class="delimiter">&quot;</span><span class="content">RFC6265,-RESERVED_NAMES_NOT_DOLLAR_PREFIXED</span><span class="delimiter">&quot;</span></span>);
httpConfiguration.setRequestCookieCompliance(customUriCompliance);
httpConfiguration.setResponseCookieCompliance(CookieCompliance.RFC6265);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-server-http"><a class="anchor" href="#pg-server-http"></a><a class="link" href="#pg-server-http">HTTP Server Libraries</a></h3>
<div class="paragraph">
<p>Web application development typically involves writing your web applications, packaging them into a web application archive, the <code>*.war</code> file, and then deploy the <code>*.war</code> file into a standalone Servlet Container that you have previously installed.</p>
</div>
<div class="paragraph">
<p>The Eclipse Jetty server libraries allow you to write web applications components using either the Jetty APIs (by writing <a href="#pg-server-http-handler">Jetty <code>Handler</code>s</a>) or using the standard <a href="#pg-server-http-handler-use-servlet">Servlet APIs</a> (by writing <code>Servlet</code>s and Servlet <code>Filter</code>s).
These components can then be programmatically assembled together, without the need of creating a <code>*.war</code> file, added to a Jetty <code>Server</code> instance that is then started.
This result in your web applications to be available to HTTP clients as if you deployed your <code>*.war</code> files in a standalone Jetty server.</p>
</div>
<div class="paragraph">
<p>The Maven artifact coordinates are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-server<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>An <code>org.eclipse.jetty.server.Server</code> instance is the central component that links together a collection of <code>Connector</code>s and a collection of <code>Handler</code>s, with threads from a <code>ThreadPool</code> doing the work.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-05cfcead1245ff0fbcf3af8873998cee.png" alt="Diagram" width="450" height="219">
</div>
</div>
<div class="paragraph">
<p>The components that accept connections from clients are <code>org.eclipse.jetty.server.Connector</code> implementations.</p>
</div>
<div class="paragraph">
<p>When a Jetty server interprets the HTTP protocol (both HTTP/1.1 and HTTP/2), it uses <code>org.eclipse.jetty.server.Handler</code> instances to process incoming requests and eventually produce responses.</p>
</div>
<div class="paragraph">
<p>A <code>Server</code> must be created, configured and started:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create and configure a ThreadPool.</span>
QueuedThreadPool threadPool = <span class="keyword">new</span> QueuedThreadPool();
threadPool.setName(<span class="string"><span class="delimiter">&quot;</span><span class="content">server</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Create a Server instance.</span>
Server server = <span class="keyword">new</span> Server(threadPool);
<span class="comment">// Create a ServerConnector to accept connections from clients.</span>
Connector connector = <span class="keyword">new</span> ServerConnector(server);
<span class="comment">// Add the Connector to the Server</span>
server.addConnector(connector);
<span class="comment">// Set a simple Handler to handle requests/responses.</span>
server.setHandler(<span class="keyword">new</span> AbstractHandler()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
{
<span class="comment">// Mark the request as handled so that it</span>
<span class="comment">// will not be processed by other handlers.</span>
jettyRequest.setHandled(<span class="predefined-constant">true</span>);
}
});
<span class="comment">// Start the Server so it starts accepting connections from clients.</span>
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The example above shows the simplest HTTP/1.1 server; it has no support for HTTP sessions, for HTTP authentication, or for any of the features required by the Servlet specification.</p>
</div>
<div class="paragraph">
<p>All these features are provided by the Jetty Server Libraries, and server applications only need to put the required components together to provide all the required features.</p>
</div>
<div class="paragraph">
<p>The <code>Handler</code>s provided by the Jetty Server Libraries allow writing server applications that have functionalities similar to Apache HTTPD or Nginx (for example: URL redirection, URL rewriting, serving static content, reverse proxying, etc.), as well as generating content dynamically by processing incoming requests.
Read <a href="#pg-server-http-handler">this section</a> for further details about <code>Handler</code>s.</p>
</div>
<div class="paragraph">
<p>If you are interested in writing your server application based on the Servlet APIs, jump to <a href="#pg-server-http-handler-use-servlet">this section</a>.</p>
</div>
<div class="sect3">
<h4 id="pg-server-http-request-processing"><a class="anchor" href="#pg-server-http-request-processing"></a><a class="link" href="#pg-server-http-request-processing">Server Request Processing</a></h4>
<div class="paragraph">
<p>The Jetty HTTP request processing is outlined below in the diagram below.
You may want to refer to the <a href="#pg-arch-io">Jetty I/O architecture</a> for additional information about the classes mentioned below.</p>
</div>
<div class="paragraph">
<p>Request handing is slightly different for each protocol; in HTTP/2 Jetty takes into account multiplexing, something that is not present in HTTP/1.1.</p>
</div>
<div class="paragraph">
<p>However, the diagram below captures the essence of request handling that is common among all protocols that carry HTTP requests.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-3ca149653ee220164efd33ca869b97b5.png" alt="Diagram" width="667" height="342">
</div>
</div>
<div class="paragraph">
<p>First, the Jetty I/O layer emits an event that a socket has data to read.
This event is converted to a call to <code>AbstractConnection.onFillable()</code>, where the <code>Connection</code> first reads from the <code>EndPoint</code> into a <code>ByteBuffer</code>, and then calls a protocol specific parser to parse the bytes in the <code>ByteBuffer</code>.</p>
</div>
<div class="paragraph">
<p>The parser emit events that are protocol specific; the HTTP/2 parser, for example, emits events for each HTTP/2 frame that has been parsed.
The parser events are then converted to protocol independent events such as <em>"request start"</em>, <em>"request headers"</em>, <em>"request content chunk"</em>, etc.
that in turn are converted into method calls to <code>HttpChannel</code>.</p>
</div>
<div class="paragraph">
<p>When enough of the HTTP request is arrived, the <code>Connection</code> calls <code>HttpChannel.handle()</code> that calls the <code>Handler</code> chain, that eventually calls the server application code.</p>
</div>
<div class="sect4">
<h5 id="pg-server-http-channel-events"><a class="anchor" href="#pg-server-http-channel-events"></a><a class="link" href="#pg-server-http-channel-events">HttpChannel Events</a></h5>
<div class="paragraph">
<p>The central component processing HTTP requests is <code>HttpChannel</code>.
There is a 1-to-1 relationship between an HTTP request/response and an <code>HttpChannel</code>, no matter what is the specific protocol that carries the HTTP request over the network (HTTP/1.1, HTTP/2 or FastCGI).</p>
</div>
<div class="paragraph">
<p>Advanced server applications may be interested in the progress of the processing of an HTTP request/response by <code>HttpChannel</code>.
A typical case is to know exactly <em>when</em> the HTTP request/response processing is complete, for example to monitor processing times.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
A <code>Handler</code> or a Servlet <code>Filter</code> may not report precisely when an HTTP request/response processing is finished.
A server application may write a small enough content that is aggregated by Jetty for efficiency reasons; the write returns immediately, but nothing has been written to the network yet.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>HttpChannel</code> notifies <code>HttpChannel.Listener</code>s of the progress of the HTTP request/response handling.
Currently, the following events are available:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>requestBegin</code></p>
</li>
<li>
<p><code>beforeDispatch</code></p>
</li>
<li>
<p><code>dispatchFailure</code></p>
</li>
<li>
<p><code>afterDispatch</code></p>
</li>
<li>
<p><code>requestContent</code></p>
</li>
<li>
<p><code>requestContentEnd</code></p>
</li>
<li>
<p><code>requestTrailers</code></p>
</li>
<li>
<p><code>requestEnd</code></p>
</li>
<li>
<p><code>responseBegin</code></p>
</li>
<li>
<p><code>responseCommit</code></p>
</li>
<li>
<p><code>responseContent</code></p>
</li>
<li>
<p><code>responseFailure</code></p>
</li>
<li>
<p><code>responseEnd</code></p>
</li>
<li>
<p><code>complete</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Please refer to the <code>HttpChannel.Listener</code> <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/HttpChannel.Listener.html">javadocs</a> for the complete list of events.</p>
</div>
<div class="paragraph">
<p>Server applications can register <code>HttpChannel.Listener</code> by adding them as <a href="#pg-arch-bean">beans</a> to the <code>Connector</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">TimingHttpChannelListener</span> <span class="directive">implements</span> HttpChannel.Listener
{
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">ConcurrentMap</span>&lt;Request, <span class="predefined-type">Long</span>&gt; times = <span class="keyword">new</span> <span class="predefined-type">ConcurrentHashMap</span>&lt;&gt;();
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onRequestBegin(Request request)
{
times.put(request, <span class="predefined-type">System</span>.nanoTime());
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onComplete(Request request)
{
<span class="type">long</span> begin = times.remove(request);
<span class="type">long</span> elapsed = <span class="predefined-type">System</span>.nanoTime() - begin;
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">timing</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Request {0} took {1} ns</span><span class="delimiter">&quot;</span></span>, request, elapsed);
}
}
Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Add the HttpChannel.Listener as bean to the connector.</span>
connector.addBean(<span class="keyword">new</span> TimingHttpChannelListener());
<span class="comment">// Set a simple Handler to handle requests/responses.</span>
server.setHandler(<span class="keyword">new</span> AbstractHandler()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
{
jettyRequest.setHandled(<span class="predefined-constant">true</span>);
}
});
server.start();</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http-connector"><a class="anchor" href="#pg-server-http-connector"></a><a class="link" href="#pg-server-http-connector">Server Connectors</a></h4>
<div class="paragraph">
<p>A <code>Connector</code> is the component that handles incoming requests from clients, and works in conjunction with <code>ConnectionFactory</code> instances.</p>
</div>
<div class="paragraph">
<p>The primary implementation is <code>org.eclipse.jetty.server.ServerConnector</code>.
<code>ServerConnector</code> uses a <code>java.nio.channels.ServerSocketChannel</code> to listen to a TCP port and to accept TCP connections.</p>
</div>
<div class="paragraph">
<p>Since <code>ServerConnector</code> wraps a <code>ServerSocketChannel</code>, it can be configured in a similar way, for example the port to listen to, the network address to bind to, etc.:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// The number of acceptor threads.</span>
<span class="type">int</span> acceptors = <span class="integer">1</span>;
<span class="comment">// The number of selectors.</span>
<span class="type">int</span> selectors = <span class="integer">1</span>;
<span class="comment">// Create a ServerConnector instance.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, <span class="integer">1</span>, <span class="integer">1</span>, <span class="keyword">new</span> HttpConnectionFactory());
<span class="comment">// Configure TCP parameters.</span>
<span class="comment">// The TCP port to listen to.</span>
connector.setPort(<span class="integer">8080</span>);
<span class="comment">// The TCP address to bind to.</span>
connector.setHost(<span class="string"><span class="delimiter">&quot;</span><span class="content">127.0.0.1</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// The TCP accept queue size.</span>
connector.setAcceptQueueSize(<span class="integer">128</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <em>acceptors</em> are threads (typically only one) that compete to accept TCP connections on the listening port.
When a connection is accepted, <code>ServerConnector</code> wraps the accepted <code>SocketChannel</code> and passes it to the <a href="#pg-arch-io-selector-manager"><code>SelectorManager</code></a>.
Therefore, there is a little moment where the acceptor thread is not accepting new connections because it is busy wrapping the just accepted connection to pass it to the <code>SelectorManager</code>.
Connections that are ready to be accepted but are not accepted yet are queued in a bounded queue (at the OS level) whose capacity can be configured with the <code>ServerConnector.acceptQueueSize</code> parameter.</p>
</div>
<div class="paragraph">
<p>If your application must withstand a very high rate of connections opened, configuring more than one acceptor thread may be beneficial: when one acceptor thread accepts one connection, another acceptor thread can take over accepting connections.</p>
</div>
<div class="paragraph">
<p>The <em>selectors</em> are components that manage a set of connected sockets, implemented by <a href="#pg-arch-io-selector-manager"><code>ManagedSelector</code></a>.
Each selector requires one thread and uses the Java NIO mechanism to efficiently handle a set of connected sockets.
As a rule of thumb, a single selector can easily manage up to 1000-5000 sockets, although the number may vary greatly depending on the application.</p>
</div>
<div class="paragraph">
<p>For example, web site applications tend to use sockets for one or more HTTP requests to retrieve resources and then the socket is idle for most of the time.
In this case a single selector may be able to manage many sockets because chances are that they will be idle most of the time.
On the contrary, web messaging applications tend to send many small messages at a very high frequency so that sockets are rarely idle.
In this case a single selector may be able to manage less sockets because chances are that many of them will be active at the same time.</p>
</div>
<div class="paragraph">
<p>It is possible to configure more than one <code>ServerConnector</code>, each listening on a different port:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Create a ServerConnector instance on port 8080.</span>
ServerConnector connector1 = <span class="keyword">new</span> ServerConnector(server, <span class="integer">1</span>, <span class="integer">1</span>, <span class="keyword">new</span> HttpConnectionFactory());
connector1.setPort(<span class="integer">8080</span>);
server.addConnector(connector1);
<span class="comment">// Create another ServerConnector instance on port 9090,</span>
<span class="comment">// for example with a different HTTP configuration.</span>
HttpConfiguration httpConfig2 = <span class="keyword">new</span> HttpConfiguration();
httpConfig2.setHttpCompliance(HttpCompliance.LEGACY);
ServerConnector connector2 = <span class="keyword">new</span> ServerConnector(server, <span class="integer">1</span>, <span class="integer">1</span>, <span class="keyword">new</span> HttpConnectionFactory(httpConfig2));
connector2.setPort(<span class="integer">9090</span>);
server.addConnector(connector2);
server.start();</code></pre>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-http-connector-protocol"><a class="anchor" href="#pg-server-http-connector-protocol"></a><a class="link" href="#pg-server-http-connector-protocol">Configuring Protocols</a></h5>
<div class="paragraph">
<p>For each accepted TCP connection, <code>ServerConnector</code> asks a <code>ConnectionFactory</code> to create a <code>Connection</code> object that handles the network traffic on that TCP connection, parsing and generating bytes for a specific protocol (see <a href="#pg-arch-io">this section</a> for more details about <code>Connection</code> objects).</p>
</div>
<div class="paragraph">
<p>A <code>ServerConnector</code> can be configured with one or more <code>ConnectionFactory</code>s.
If no <code>ConnectionFactory</code> is specified then <code>HttpConnectionFactory</code> is implicitly configured.</p>
</div>
<div class="sect5">
<h6 id="pg-server-http-connector-protocol-http11"><a class="anchor" href="#pg-server-http-connector-protocol-http11"></a><a class="link" href="#pg-server-http-connector-protocol-http11">Clear-Text HTTP/1.1</a></h6>
<div class="paragraph">
<p><code>HttpConnectionFactory</code> creates <code>HttpConnection</code> objects that parse bytes and generate bytes for the HTTP/1.1 protocol.</p>
</div>
<div class="paragraph">
<p>This is how you configure Jetty to support clear-text HTTP/1.1:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// The HTTP configuration object.</span>
HttpConfiguration httpConfig = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// Configure the HTTP support, for example:</span>
httpConfig.setSendServerVersion(<span class="predefined-constant">false</span>);
<span class="comment">// The ConnectionFactory for HTTP/1.1.</span>
HttpConnectionFactory http11 = <span class="keyword">new</span> HttpConnectionFactory(httpConfig);
<span class="comment">// Create the ServerConnector.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, http11);
connector.setPort(<span class="integer">8080</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-connector-protocol-http11-tls"><a class="anchor" href="#pg-server-http-connector-protocol-http11-tls"></a><a class="link" href="#pg-server-http-connector-protocol-http11-tls">Encrypted HTTP/1.1 (https)</a></h6>
<div class="paragraph">
<p>Supporting encrypted HTTP/1.1 (that is, requests with the <code>https</code> scheme) is supported by configuring an <code>SslContextFactory</code> that has access to the keyStore containing the private server key and public server certificate, in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// The HTTP configuration object.</span>
HttpConfiguration httpConfig = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// Add the SecureRequestCustomizer because we are using TLS.</span>
httpConfig.addCustomizer(<span class="keyword">new</span> SecureRequestCustomizer());
<span class="comment">// The ConnectionFactory for HTTP/1.1.</span>
HttpConnectionFactory http11 = <span class="keyword">new</span> HttpConnectionFactory(httpConfig);
<span class="comment">// Configure the SslContextFactory with the keyStore information.</span>
SslContextFactory.Server sslContextFactory = <span class="keyword">new</span> SslContextFactory.Server();
sslContextFactory.setKeyStorePath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keystore</span><span class="delimiter">&quot;</span></span>);
sslContextFactory.setKeyStorePassword(<span class="string"><span class="delimiter">&quot;</span><span class="content">secret</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// The ConnectionFactory for TLS.</span>
SslConnectionFactory tls = <span class="keyword">new</span> SslConnectionFactory(sslContextFactory, http11.getProtocol());
<span class="comment">// The ServerConnector instance.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, tls, http11);
connector.setPort(<span class="integer">8443</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-connector-protocol-http2"><a class="anchor" href="#pg-server-http-connector-protocol-http2"></a><a class="link" href="#pg-server-http-connector-protocol-http2">Clear-Text HTTP/2</a></h6>
<div class="paragraph">
<p>It is well known that the HTTP ports are <code>80</code> (for clear-text HTTP) and <code>443</code> for encrypted HTTP.
By using those ports, a client had <em>prior knowledge</em> that the server would speak, respectively, the HTTP/1.x protocol and the TLS protocol (and, after decryption, the HTTP/1.x protocol).</p>
</div>
<div class="paragraph">
<p>HTTP/2 was designed to be a smooth transition from HTTP/1.1 for users and as such the HTTP ports were not changed.
However the HTTP/2 protocol is, on the wire, a binary protocol, completely different from HTTP/1.1.
Therefore, with HTTP/2, clients that connect to port <code>80</code> may speak either HTTP/1.1 or HTTP/2, and the server must figure out which version of the HTTP protocol the client is speaking.</p>
</div>
<div class="paragraph">
<p>Jetty can support both HTTP/1.1 and HTTP/2 on the same clear-text port by configuring both the HTTP/1.1 and the HTTP/2 <code>ConnectionFactory</code>s:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// The HTTP configuration object.</span>
HttpConfiguration httpConfig = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// The ConnectionFactory for HTTP/1.1.</span>
HttpConnectionFactory http11 = <span class="keyword">new</span> HttpConnectionFactory(httpConfig);
<span class="comment">// The ConnectionFactory for clear-text HTTP/2.</span>
HTTP2CServerConnectionFactory h2c = <span class="keyword">new</span> HTTP2CServerConnectionFactory(httpConfig);
<span class="comment">// The ServerConnector instance.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, http11, h2c);
connector.setPort(<span class="integer">8080</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how the <code>ConnectionFactory</code>s passed to <code>ServerConnector</code> are in order: first HTTP/1.1, then HTTP/2.
This is necessary to support both protocols on the same port: Jetty will start parsing the incoming bytes as HTTP/1.1, but then realize that they are HTTP/2 bytes and will therefore <em>upgrade</em> from HTTP/1.1 to HTTP/2.</p>
</div>
<div class="paragraph">
<p>This configuration is also typical when Jetty is installed in backend servers behind a load balancer that also takes care of offloading TLS.
When Jetty is behind a load balancer, you can always prepend the PROXY protocol as described in <a href="#pg-server-http-connector-protocol-proxy-http11">this section</a>.</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-connector-protocol-http2-tls"><a class="anchor" href="#pg-server-http-connector-protocol-http2-tls"></a><a class="link" href="#pg-server-http-connector-protocol-http2-tls">Encrypted HTTP/2</a></h6>
<div class="paragraph">
<p>When using encrypted HTTP/2, the unencrypted protocol is negotiated by client and server using an extension to the TLS protocol called ALPN.</p>
</div>
<div class="paragraph">
<p>Jetty supports ALPN and encrypted HTTP/2 with this configuration:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// The HTTP configuration object.</span>
HttpConfiguration httpConfig = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// Add the SecureRequestCustomizer because we are using TLS.</span>
httpConfig.addCustomizer(<span class="keyword">new</span> SecureRequestCustomizer());
<span class="comment">// The ConnectionFactory for HTTP/1.1.</span>
HttpConnectionFactory http11 = <span class="keyword">new</span> HttpConnectionFactory(httpConfig);
<span class="comment">// The ConnectionFactory for HTTP/2.</span>
HTTP2ServerConnectionFactory h2 = <span class="keyword">new</span> HTTP2ServerConnectionFactory(httpConfig);
<span class="comment">// The ALPN ConnectionFactory.</span>
ALPNServerConnectionFactory alpn = <span class="keyword">new</span> ALPNServerConnectionFactory();
<span class="comment">// The default protocol to use in case there is no negotiation.</span>
alpn.setDefaultProtocol(http11.getProtocol());
<span class="comment">// Configure the SslContextFactory with the keyStore information.</span>
SslContextFactory.Server sslContextFactory = <span class="keyword">new</span> SslContextFactory.Server();
sslContextFactory.setKeyStorePath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keystore</span><span class="delimiter">&quot;</span></span>);
sslContextFactory.setKeyStorePassword(<span class="string"><span class="delimiter">&quot;</span><span class="content">secret</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// The ConnectionFactory for TLS.</span>
SslConnectionFactory tls = <span class="keyword">new</span> SslConnectionFactory(sslContextFactory, alpn.getProtocol());
<span class="comment">// The ServerConnector instance.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, tls, alpn, h2, http11);
connector.setPort(<span class="integer">8443</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how the <code>ConnectionFactory</code>s passed to <code>ServerConnector</code> are in order: TLS, ALPN, HTTP/2, HTTP/1.1.</p>
</div>
<div class="paragraph">
<p>Jetty starts parsing TLS bytes so that it can obtain the ALPN extension.
With the ALPN extension information, Jetty can negotiate a protocol and pick, among the <code>ConnectionFactory</code>s supported by the <code>ServerConnector</code>, the <code>ConnectionFactory</code> correspondent to the negotiated protocol.</p>
</div>
<div class="paragraph">
<p>The fact that the HTTP/2 protocol comes before the HTTP/1.1 protocol indicates that HTTP/2 is the preferred protocol for the server.</p>
</div>
<div class="paragraph">
<p>Note also that the default protocol set in the ALPN <code>ConnectionFactory</code>, which is used in case ALPN is not supported by the client, is HTTP/1.1&#8201;&#8212;&#8201;if the client does not support ALPN is probably an old client so HTTP/1.1 is the safest choice.</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-connector-protocol-proxy-http11"><a class="anchor" href="#pg-server-http-connector-protocol-proxy-http11"></a><a class="link" href="#pg-server-http-connector-protocol-proxy-http11">Jetty Behind a Load Balancer</a></h6>
<div class="paragraph">
<p>It is often the case that Jetty receives connections from a load balancer configured to distribute the load among many Jetty backend servers.</p>
</div>
<div class="paragraph">
<p>From the Jetty point of view, all the connections arrive from the load balancer, rather than the real clients, but is possible to configure the load balancer to forward the real client IP address and port to the backend Jetty server using the <a href="https://www.haproxy.org/download/2.1/doc/proxy-protocol.txt">PROXY protocol</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The PROXY protocol is widely supported by load balancers such as <a href="http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#5.2-send-proxy">HAProxy</a> (via its <code>send-proxy</code> directive), <a href="https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol">Nginx</a>(via its <code>proxy_protocol on</code> directive) and others.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To support this case, Jetty can be configured in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// The HTTP configuration object.</span>
HttpConfiguration httpConfig = <span class="keyword">new</span> HttpConfiguration();
<span class="comment">// Configure the HTTP support, for example:</span>
httpConfig.setSendServerVersion(<span class="predefined-constant">false</span>);
<span class="comment">// The ConnectionFactory for HTTP/1.1.</span>
HttpConnectionFactory http11 = <span class="keyword">new</span> HttpConnectionFactory(httpConfig);
<span class="comment">// The ConnectionFactory for the PROXY protocol.</span>
ProxyConnectionFactory proxy = <span class="keyword">new</span> ProxyConnectionFactory(http11.getProtocol());
<span class="comment">// Create the ServerConnector.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, proxy, http11);
connector.setPort(<span class="integer">8080</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how the <code>ConnectionFactory</code>s passed to <code>ServerConnector</code> are in order: first PROXY, then HTTP/1.1.
Note also how the PROXY <code>ConnectionFactory</code> needs to know its <em>next</em> protocol (in this example, HTTP/1.1).</p>
</div>
<div class="paragraph">
<p>Each <code>ConnectionFactory</code> is asked to create a <code>Connection</code> object for each accepted TCP connection; the <code>Connection</code> objects will be chained together to handle the bytes, each for its own protocol.
Therefore the <code>ProxyConnection</code> will handle the PROXY protocol bytes and <code>HttpConnection</code> will handle the HTTP/1.1 bytes producing a request object and response object that will be processed by <code>Handler</code>s.</p>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http-handler"><a class="anchor" href="#pg-server-http-handler"></a><a class="link" href="#pg-server-http-handler">Server Handlers</a></h4>
<div class="paragraph">
<p>An <code>org.eclipse.jetty.server.Handler</code> is the component that processes incoming HTTP requests and eventually produces HTTP responses.</p>
</div>
<div class="paragraph">
<p><code>Handler</code>s can be organized in different ways:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>in a sequence, where <code>Handler</code>s are invoked one after the other</p>
<div class="ulist">
<ul>
<li>
<p><code>HandlerCollection</code> invokes <em>all</em> <code>Handler</code>s one after the other</p>
</li>
<li>
<p><code>HandlerList</code> invokes <code>Handlers</code>s until one calls <code>Request.setHandled(true)</code> to indicate that the request has been handled and no further <code>Handler</code> should be invoked</p>
</li>
</ul>
</div>
</li>
<li>
<p>nested, where one <code>Handler</code> invokes the next, nested, <code>Handler</code></p>
<div class="ulist">
<ul>
<li>
<p><code>HandlerWrapper</code> implements this behavior</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>HandlerCollection</code> behavior (invoking <em>all</em> handlers) is useful when for example the last <code>Handler</code> is a logging <code>Handler</code> that logs the request(that may have been modified by previous handlers).</p>
</div>
<div class="paragraph">
<p>The <code>HandlerList</code> behavior (invoking handlers up to the first that calls <code>Request.setHandled(true)</code>) is useful when each handler processes a different URIs or a different virtual hosts: <code>Handler</code>s are invoked one after the other until one matches the URI or virtual host.</p>
</div>
<div class="paragraph">
<p>The nested behavior is useful to enrich the request with additional services such as HTTP session support (<code>SessionHandler</code>), or with specific behaviors dictated by the Servlet specification (<code>ServletHandler</code>).</p>
</div>
<div class="paragraph">
<p><code>Handler</code>s can be organized in a tree by composing them together:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create a Server instance.</span>
Server server = <span class="keyword">new</span> Server();
HandlerCollection collection = <span class="keyword">new</span> HandlerCollection();
<span class="comment">// Link the root Handler with the Server.</span>
server.setHandler(collection);
HandlerList list = <span class="keyword">new</span> HandlerList();
collection.addHandler(list);
collection.addHandler(<span class="keyword">new</span> LoggingHandler());
list.addHandler(<span class="keyword">new</span> App1Handler());
HandlerWrapper wrapper = <span class="keyword">new</span> HandlerWrapper();
list.addHandler(wrapper);
wrapper.setHandler(<span class="keyword">new</span> App2Handler());</code></pre>
</div>
</div>
<div class="paragraph">
<p>The corresponding <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">HandlerCollection
├── HandlerList
│ ├── App1Handler
│ └── HandlerWrapper
│ └── App2Handler
└── LoggingHandler</code></pre>
</div>
</div>
<div class="paragraph">
<p>Server applications should rarely write custom <code>Handler</code>s, preferring instead to use existing <code>Handler</code>s provided by the Jetty Server Libraries for managing web application contexts, security, HTTP sessions and Servlet support.
Refer to <a href="#pg-server-http-handler-use">this section</a> for more information about how to use the <code>Handler</code>s provided by the Jetty Server Libraries.</p>
</div>
<div class="paragraph">
<p>However, in some cases the additional features are not required, or additional constraints on memory footprint, or performance, or just simplicity must be met.
In these cases, implementing your own <code>Handler</code> may be a better solution.
Refer to <a href="#pg-server-http-handler-implement">this section</a> for more information about how to write your own <code>Handler</code>s.</p>
</div>
<div class="sect4">
<h5 id="pg-server-http-handler-use"><a class="anchor" href="#pg-server-http-handler-use"></a><a class="link" href="#pg-server-http-handler-use">Jetty Handlers</a></h5>
<div class="paragraph">
<p>Web applications are the unit of deployment in an HTTP server or Servlet container such as Jetty.</p>
</div>
<div class="paragraph">
<p>Two different web applications are typically deployed on different <em>context path</em>s, where a <em>context path</em> is the initial segment of the URI path.
For example, web application <code>webappA</code> that implements a web user interface for an e-commerce site may be deployed to context path <code>/shop</code>, while web application <code>webappB</code> that implements a REST API for the e-commerce business may be deployed to <code>/api</code>.</p>
</div>
<div class="paragraph">
<p>A client making a request to URI <code>/shop/cart</code> is directed by Jetty to <code>webappA</code>, while a request to URI <code>/api/products</code> is directed to <code>webappB</code>.</p>
</div>
<div class="paragraph">
<p>An alternative way to deploy the two web applications of the example above is to use <em>virtual hosts</em>.
A <em>virtual host</em> is a subdomain of the primary domain that shares the same IP address with the primary domain.
If the e-commerce business primary domain is <code>domain.com</code>, then a virtual host for <code>webappA</code> could be <code>shop.domain.com</code>, while a virtual host for <code>webappB</code> could be <code>api.domain.com</code>.</p>
</div>
<div class="paragraph">
<p>Web application <code>webappA</code> can now be deployed to virtual host <code>shop.domain.com</code> and context path <code>/</code>, while web application <code>webappB</code> can be deployed to virtual host <code>api.domain.com</code> and context path <code>/</code>.
Both applications have the same context path <code>/</code>, but they can be distinguished by the subdomain.</p>
</div>
<div class="paragraph">
<p>A client making a request to <code>https://shop.domain.com/cart</code> is directed by Jetty to <code>webappA</code>, while a request to <code>https://api.domain.com/products</code> is directed to <code>webappB</code>.</p>
</div>
<div class="paragraph">
<p>Therefore, in general, a web application is deployed to a <em>context</em> which can be seen as the pair <code>(virtual_host, context_path)</code>.
In the first case the contexts were <code>(domain.com, /shop)</code> and <code>(domain.com, /api)</code>, while in the second case the contexts were <code>(shop.domain.com, /)</code> and <code>(api.domain.com, /)</code>.
Server applications using the Jetty Server Libraries create and configure a <em>context</em> for each web application.
Many <em>context</em>s can be deployed together to enrich the web application offering&#8201;&#8212;&#8201;for example a catalog context, a shop context, an API context, an administration context, etc.</p>
</div>
<div class="paragraph">
<p>Web applications can be written using exclusively the Servlet APIs, since developers know well the Servlet API and because they guarantee better portability across Servlet container implementations.</p>
</div>
<div class="paragraph">
<p>Embedded web applications based on the Servlet APIs are described in <a href="#pg-server-http-handler-use-servlet">this section</a>.</p>
</div>
<div class="paragraph">
<p>Embedded web applications may also require additional features such as access to Jetty specific APIs, or utility features such as redirection from HTTP to HTTPS, support for <code>gzip</code> content compression, etc.
The Jetty Server Libraries provides a number of out-of-the-box <em>Handler</em>s that implement the most common functionalities and are described in <a href="#pg-server-http-handler-use">this section</a>.</p>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-context"><a class="anchor" href="#pg-server-http-handler-use-util-context"></a><a class="link" href="#pg-server-http-handler-use-util-context">ContextHandler</a></h6>
<div class="paragraph">
<p><code>ContextHandler</code> is a <code>Handler</code> that represents a <em>context</em> for a web application.
It is a <code>HandlerWrapper</code> that performs some action before and after delegating to the nested <code>Handler</code>.</p>
</div>
<div class="paragraph">
<p>The simplest use of <code>ContextHandler</code> is the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">ShopHandler</span> <span class="directive">extends</span> AbstractHandler
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
{
baseRequest.setHandled(<span class="predefined-constant">true</span>);
<span class="comment">// Implement the shop.</span>
}
}
Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Create a ContextHandler with contextPath.</span>
ContextHandler context = <span class="keyword">new</span> ContextHandler();
context.setContextPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/shop</span><span class="delimiter">&quot;</span></span>);
context.setHandler(<span class="keyword">new</span> ShopHandler());
<span class="comment">// Link the context to the server.</span>
server.setHandler(context);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── ContextHandler /shop
└── ShopHandler</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-context-collection"><a class="anchor" href="#pg-server-http-handler-use-util-context-collection"></a><a class="link" href="#pg-server-http-handler-use-util-context-collection">ContextHandlerCollection</a></h6>
<div class="paragraph">
<p>Server applications may need to deploy to Jetty more than one web application.</p>
</div>
<div class="paragraph">
<p>Recall from the <a href="#pg-server-http-handler">introduction</a> that Jetty offers <code>HandlerCollection</code> and <code>HandlerList</code> that may contain a sequence of children <code>Handler</code>s.
However, both of these have no knowledge of the concept of <em>context</em> and just iterate through the sequence of <code>Handler</code>s.</p>
</div>
<div class="paragraph">
<p>A better choice for multiple web application is <code>ContextHandlerCollection</code>, that matches a <em>context</em> from either its <em>context path</em> or <em>virtual host</em>, without iterating through the <code>Handler</code>s.</p>
</div>
<div class="paragraph">
<p>If <code>ContextHandlerCollection</code> does not find a match, it just returns.
What happens next depends on the <code>Handler</code> tree structure: other <code>Handler</code>s may be invoked after <code>ContextHandlerCollection</code>, for example <code>DefaultHandler</code> (see <a href="#pg-server-http-handler-use-util-default-handler">this section</a>).
Eventually, if <code>Request.setHandled(true)</code> is not called, Jetty returns an HTTP <code>404</code> response to the client.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">ShopHandler</span> <span class="directive">extends</span> AbstractHandler
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
{
baseRequest.setHandled(<span class="predefined-constant">true</span>);
<span class="comment">// Implement the shop.</span>
}
}
<span class="type">class</span> <span class="class">RESTHandler</span> <span class="directive">extends</span> AbstractHandler
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
{
baseRequest.setHandled(<span class="predefined-constant">true</span>);
<span class="comment">// Implement the REST APIs.</span>
}
}
Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Create a ContextHandlerCollection to hold contexts.</span>
ContextHandlerCollection contextCollection = <span class="keyword">new</span> ContextHandlerCollection();
<span class="comment">// Link the ContextHandlerCollection to the Server.</span>
server.setHandler(contextCollection);
<span class="comment">// Create the context for the shop web application.</span>
ContextHandler shopContext = <span class="keyword">new</span> ContextHandler(<span class="string"><span class="delimiter">&quot;</span><span class="content">/shop</span><span class="delimiter">&quot;</span></span>);
shopContext.setHandler(<span class="keyword">new</span> ShopHandler());
<span class="comment">// Add it to ContextHandlerCollection.</span>
contextCollection.addHandler(shopContext);
server.start();
<span class="comment">// Create the context for the API web application.</span>
ContextHandler apiContext = <span class="keyword">new</span> ContextHandler(<span class="string"><span class="delimiter">&quot;</span><span class="content">/api</span><span class="delimiter">&quot;</span></span>);
apiContext.setHandler(<span class="keyword">new</span> RESTHandler());
<span class="comment">// Web applications can be deployed after the Server is started.</span>
contextCollection.deployHandler(apiContext, <span class="predefined-type">Callback</span>.NOOP);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── ContextHandlerCollection
├── ContextHandler /shop
│ └── ShopHandler
└── ContextHandler /api
└── RESTHandler</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-resource-handler"><a class="anchor" href="#pg-server-http-handler-use-util-resource-handler"></a><a class="link" href="#pg-server-http-handler-use-util-resource-handler">ResourceHandler&#8201;&#8212;&#8201;Static Content</a></h6>
<div class="paragraph">
<p>Static content such as images or files (HTML, JavaScript, CSS) can be sent by Jetty very efficiently because Jetty can write the content asynchronously, using direct <code>ByteBuffer</code>s to minimize data copy, and using a memory cache for faster access to the data to send.</p>
</div>
<div class="paragraph">
<p>Being able to write content asynchronously means that if the network gets congested (for example, the client reads the content very slowly) and the server stalls the send of the requested data, then Jetty will wait to resume the send <em>without</em> blocking a thread to finish the send.</p>
</div>
<div class="paragraph">
<p><code>ResourceHandler</code> supports the following features:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Welcome files, for example serving <code>/index.html</code> for request URI <code>/</code></p>
</li>
<li>
<p>Precompressed resources, serving a precompressed <code>/document.txt.gz</code> for request URI <code>/document.txt</code></p>
</li>
<li>
<p><a href="https://tools.ietf.org/html/rfc7233">Range requests</a>, for requests containing the <code>Range</code> header, which allows clients to pause and resume downloads of large files</p>
</li>
<li>
<p>Directory listing, serving a HTML page with the file list of the requested directory</p>
</li>
<li>
<p>Conditional headers, for requests containing the <code>If-Match</code>, <code>If-None-Match</code>, <code>If-Modified-Since</code>, <code>If-Unmodified-Since</code> headers.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The number of features supported and the efficiency in sending static content are on the same level as those of common front-end servers used to serve static content such as Nginx or Apache.
Therefore, the traditional architecture where Nginx/Apache was the front-end server used only to send static content and Jetty was the back-end server used only to send dynamic content is somehow obsolete as Jetty can perform efficiently both tasks.
This leads to simpler systems (less components to configure and manage) and more performance (no need to proxy dynamic requests from front-end servers to back-end servers).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
It is common to use Nginx/Apache as load balancers, or as rewrite/redirect servers.
We typically recommend <a href="https://haproxy.org">HAProxy</a> as load balancer, and Jetty has <a href="#pg-server-http-handler-use-util-rewrite-handler">rewrite/redirect features</a> as well.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This is how you configure a <code>ResourceHandler</code> to create a simple file server:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Create and configure a ResourceHandler.</span>
ResourceHandler handler = <span class="keyword">new</span> ResourceHandler();
<span class="comment">// Configure the directory where static resources are located.</span>
handler.setBaseResource(Resource.newResource(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/static/resources/</span><span class="delimiter">&quot;</span></span>));
<span class="comment">// Configure directory listing.</span>
handler.setDirectoriesListed(<span class="predefined-constant">false</span>);
<span class="comment">// Configure welcome files.</span>
handler.setWelcomeFiles(<span class="keyword">new</span> <span class="predefined-type">String</span><span class="type">[]</span>{<span class="string"><span class="delimiter">&quot;</span><span class="content">index.html</span><span class="delimiter">&quot;</span></span>});
<span class="comment">// Configure whether to accept range requests.</span>
handler.setAcceptRanges(<span class="predefined-constant">true</span>);
<span class="comment">// Link the context to the server.</span>
server.setHandler(handler);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you need to serve static resources from multiple directories:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ResourceHandler handler = <span class="keyword">new</span> ResourceHandler();
<span class="comment">// For multiple directories, use ResourceCollection.</span>
ResourceCollection directories = <span class="keyword">new</span> ResourceCollection();
directories.addPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/static/resources/</span><span class="delimiter">&quot;</span></span>);
directories.addPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/another/path/to/static/resources/</span><span class="delimiter">&quot;</span></span>);
handler.setBaseResource(directories);</code></pre>
</div>
</div>
<div class="paragraph">
<p>If the resource is not found, <code>ResourceHandler</code> will not call <code>Request.setHandled(true)</code> so what happens next depends on the <code>Handler</code> tree structure.
See also <a href="#pg-server-http-handler-use-util-default-handler">how to use</a> <code>DefaultHandler</code>.</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-gzip-handler"><a class="anchor" href="#pg-server-http-handler-use-util-gzip-handler"></a><a class="link" href="#pg-server-http-handler-use-util-gzip-handler">GzipHandler</a></h6>
<div class="paragraph">
<p><code>GzipHandler</code> provides supports for automatic decompression of compressed request content and automatic compression of response content.</p>
</div>
<div class="paragraph">
<p><code>GzipHandler</code> is a <code>HandlerWrapper</code> that inspects the request and, if the request matches the <code>GzipHandler</code> configuration, just installs the required components to eventually perform decompression of the request content or compression of the response content.
The decompression/compression is not performed until the web application reads request content or writes response content.</p>
</div>
<div class="paragraph">
<p><code>GzipHandler</code> can be configured at the server level in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Create and configure GzipHandler.</span>
GzipHandler gzipHandler = <span class="keyword">new</span> GzipHandler();
<span class="comment">// Only compress response content larger than this.</span>
gzipHandler.setMinGzipSize(<span class="integer">1024</span>);
<span class="comment">// Do not compress these URI paths.</span>
gzipHandler.setExcludedPaths(<span class="string"><span class="delimiter">&quot;</span><span class="content">/uncompressed</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Also compress POST responses.</span>
gzipHandler.addIncludedMethods(<span class="string"><span class="delimiter">&quot;</span><span class="content">POST</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Do not compress these mime types.</span>
gzipHandler.addExcludedMimeTypes(<span class="string"><span class="delimiter">&quot;</span><span class="content">font/ttf</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Link a ContextHandlerCollection to manage contexts.</span>
ContextHandlerCollection contexts = <span class="keyword">new</span> ContextHandlerCollection();
gzipHandler.setHandler(contexts);
<span class="comment">// Link the GzipHandler to the Server.</span>
server.setHandler(gzipHandler);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── GzipHandler
└── ContextHandlerCollection
├── ContextHandler 1
:── ...
└── ContextHandler N</code></pre>
</div>
</div>
<div class="paragraph">
<p>However, in less common cases, you can configure <code>GzipHandler</code> on a per-context basis, for example because you want to configure <code>GzipHandler</code> with different parameters for each context, or because you want only some contexts to have compression support:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create a ContextHandlerCollection to hold contexts.</span>
ContextHandlerCollection contextCollection = <span class="keyword">new</span> ContextHandlerCollection();
<span class="comment">// Link the ContextHandlerCollection to the Server.</span>
server.setHandler(contextCollection);
<span class="comment">// Create the context for the shop web application.</span>
ContextHandler shopContext = <span class="keyword">new</span> ContextHandler(<span class="string"><span class="delimiter">&quot;</span><span class="content">/shop</span><span class="delimiter">&quot;</span></span>);
shopContext.setHandler(<span class="keyword">new</span> ShopHandler());
<span class="comment">// You want to gzip the shop web application only.</span>
GzipHandler shopGzipHandler = <span class="keyword">new</span> GzipHandler();
shopGzipHandler.setHandler(shopContext);
<span class="comment">// Add it to ContextHandlerCollection.</span>
contextCollection.addHandler(shopGzipHandler);
<span class="comment">// Create the context for the API web application.</span>
ContextHandler apiContext = <span class="keyword">new</span> ContextHandler(<span class="string"><span class="delimiter">&quot;</span><span class="content">/api</span><span class="delimiter">&quot;</span></span>);
apiContext.setHandler(<span class="keyword">new</span> RESTHandler());
<span class="comment">// Add it to ContextHandlerCollection.</span>
contextCollection.addHandler(apiContext);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── ContextHandlerCollection
└── ContextHandlerCollection
├── GzipHandler
│ └── ContextHandler /shop
│ └── ShopHandler
└── ContextHandler /api
└── RESTHandler</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-rewrite-handler"><a class="anchor" href="#pg-server-http-handler-use-util-rewrite-handler"></a><a class="link" href="#pg-server-http-handler-use-util-rewrite-handler">RewriteHandler</a></h6>
<div class="paragraph">
<p><code>RewriteHandler</code> provides support for URL rewriting, very similarly to <a href="https://httpd.apache.org/docs/current/mod/mod_rewrite.html">Apache&#8217;s mod_rewrite</a> or <a href="https://nginx.org/en/docs/http/ngx_http_rewrite_module.html">Nginx rewrite module</a>.</p>
</div>
<div class="paragraph">
<p>The Maven artifact coordinates are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-rewrite<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><code>RewriteHandler</code> can be configured with a set of <em>rule</em>s; a <em>rule</em> inspects the request and when it matches it performs some change to the request (for example, changes the URI path, adds/removes headers, etc.).</p>
</div>
<div class="paragraph">
<p>The Jetty Server Libraries provide rules for the most common usages, but you can write your own rules by extending the <code>org.eclipse.jetty.rewrite.handler.Rule</code> class.</p>
</div>
<div class="paragraph">
<p>Please refer to the <code>jetty-rewrite</code> module <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/rewrite/handler/package-summary.html">javadocs</a> for the complete list of available rules.</p>
</div>
<div class="paragraph">
<p>You typically want to configure <code>RewriteHandler</code> at the server level, although it is possible to configure it on a per-context basis.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
RewriteHandler rewriteHandler = <span class="keyword">new</span> RewriteHandler();
<span class="comment">// Compacts URI paths with double slashes, e.g. /ctx//path/to//resource.</span>
rewriteHandler.addRule(<span class="keyword">new</span> CompactPathRule());
<span class="comment">// Rewrites */products/* to */p/*.</span>
rewriteHandler.addRule(<span class="keyword">new</span> RewriteRegexRule(<span class="string"><span class="delimiter">&quot;</span><span class="content">/(.*)/product/(.*)</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/$1/p/$2</span><span class="delimiter">&quot;</span></span>));
<span class="comment">// Redirects permanently to a different URI.</span>
RedirectRegexRule redirectRule = <span class="keyword">new</span> RedirectRegexRule(<span class="string"><span class="delimiter">&quot;</span><span class="content">/documentation/(.*)</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">https://docs.domain.com/$1</span><span class="delimiter">&quot;</span></span>);
redirectRule.setStatusCode(HttpStatus.MOVED_PERMANENTLY_301);
rewriteHandler.addRule(redirectRule);
<span class="comment">// Link the RewriteHandler to the Server.</span>
server.setHandler(rewriteHandler);
<span class="comment">// Create a ContextHandlerCollection to hold contexts.</span>
ContextHandlerCollection contextCollection = <span class="keyword">new</span> ContextHandlerCollection();
<span class="comment">// Link the ContextHandlerCollection to the RewriteHandler.</span>
rewriteHandler.setHandler(contextCollection);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── RewriteHandler
└── ContextHandlerCollection
├── ContextHandler 1
:── ...
└── ContextHandler N</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-stats-handler"><a class="anchor" href="#pg-server-http-handler-use-util-stats-handler"></a><a class="link" href="#pg-server-http-handler-use-util-stats-handler">StatisticsHandler</a></h6>
<div class="paragraph">
<p><code>StatisticsHandler</code> gathers and exposes a number of statistic values related to request processing such as:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Total number of requests</p>
</li>
<li>
<p>Current number of concurrent requests</p>
</li>
<li>
<p>Minimum, maximum, average and standard deviation of request processing times</p>
</li>
<li>
<p>Number of responses grouped by HTTP code (i.e. how many <code>2xx</code> responses, how many <code>3xx</code> responses, etc.)</p>
</li>
<li>
<p>Total response content bytes</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Server applications can read these values and use them internally, or expose them via some service, or <a href="#pg-arch-jmx">export them to JMX</a>.</p>
</div>
<div class="paragraph">
<p><code>StatisticsHandler</code> can be configured at the server level or at the context level.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
StatisticsHandler statsHandler = <span class="keyword">new</span> StatisticsHandler();
<span class="comment">// Link the StatisticsHandler to the Server.</span>
server.setHandler(statsHandler);
<span class="comment">// Create a ContextHandlerCollection to hold contexts.</span>
ContextHandlerCollection contextCollection = <span class="keyword">new</span> ContextHandlerCollection();
<span class="comment">// Link the ContextHandlerCollection to the StatisticsHandler.</span>
statsHandler.setHandler(contextCollection);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── StatisticsHandler
└── ContextHandlerCollection
├── ContextHandler 1
:── ...
└── ContextHandler N</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-secure-handler"><a class="anchor" href="#pg-server-http-handler-use-util-secure-handler"></a><a class="link" href="#pg-server-http-handler-use-util-secure-handler">SecuredRedirectHandler&#8201;&#8212;&#8201;Redirect from HTTP to HTTPS</a></h6>
<div class="paragraph">
<p><code>SecuredRedirectHandler</code> allows to redirect requests made with the <code>http</code> scheme (and therefore to the clear-text port) to the <code>https</code> scheme (and therefore to the encrypted port).</p>
</div>
<div class="paragraph">
<p>For example a request to <code>http://domain.com:8080/path?param=value</code> is redirected to <code>https://domain.com:8443/path?param=value</code>.</p>
</div>
<div class="paragraph">
<p>Server applications must configure a <code>HttpConfiguration</code> object with the secure scheme and secure port so that <code>SecuredRedirectHandler</code> can build the redirect URI.</p>
</div>
<div class="paragraph">
<p><code>SecuredRedirectHandler</code> is typically configured at the server level, although it can be configured on a per-context basis.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Configure the HttpConfiguration for the clear-text connector.</span>
<span class="type">int</span> securePort = <span class="integer">8443</span>;
HttpConfiguration httpConfig = <span class="keyword">new</span> HttpConfiguration();
httpConfig.setSecurePort(securePort);
<span class="comment">// The clear-text connector.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, <span class="keyword">new</span> HttpConnectionFactory(httpConfig));
connector.setPort(<span class="integer">8080</span>);
server.addConnector(connector);
<span class="comment">// Configure the HttpConfiguration for the encrypted connector.</span>
HttpConfiguration httpsConfig = <span class="keyword">new</span> HttpConfiguration(httpConfig);
<span class="comment">// Add the SecureRequestCustomizer because we are using TLS.</span>
httpConfig.addCustomizer(<span class="keyword">new</span> SecureRequestCustomizer());
<span class="comment">// The HttpConnectionFactory for the encrypted connector.</span>
HttpConnectionFactory http11 = <span class="keyword">new</span> HttpConnectionFactory(httpsConfig);
<span class="comment">// Configure the SslContextFactory with the keyStore information.</span>
SslContextFactory.Server sslContextFactory = <span class="keyword">new</span> SslContextFactory.Server();
sslContextFactory.setKeyStorePath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keystore</span><span class="delimiter">&quot;</span></span>);
sslContextFactory.setKeyStorePassword(<span class="string"><span class="delimiter">&quot;</span><span class="content">secret</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// The ConnectionFactory for TLS.</span>
SslConnectionFactory tls = <span class="keyword">new</span> SslConnectionFactory(sslContextFactory, http11.getProtocol());
<span class="comment">// The encrypted connector.</span>
ServerConnector secureConnector = <span class="keyword">new</span> ServerConnector(server, tls, http11);
secureConnector.setPort(<span class="integer">8443</span>);
server.addConnector(secureConnector);
SecuredRedirectHandler securedHandler = <span class="keyword">new</span> SecuredRedirectHandler();
<span class="comment">// Link the SecuredRedirectHandler to the Server.</span>
server.setHandler(securedHandler);
<span class="comment">// Create a ContextHandlerCollection to hold contexts.</span>
ContextHandlerCollection contextCollection = <span class="keyword">new</span> ContextHandlerCollection();
<span class="comment">// Link the ContextHandlerCollection to the StatisticsHandler.</span>
securedHandler.setHandler(contextCollection);
server.start();</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-util-default-handler"><a class="anchor" href="#pg-server-http-handler-use-util-default-handler"></a><a class="link" href="#pg-server-http-handler-use-util-default-handler">DefaultHandler</a></h6>
<div class="paragraph">
<p><code>DefaultHandler</code> is a terminal <code>Handler</code> that always calls <code>Request.setHandled(true)</code> and performs the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Serves the <code>favicon.ico</code> Jetty icon when it is requested</p>
</li>
<li>
<p>Sends a HTTP <code>404</code> response for any other request</p>
</li>
<li>
<p>The HTTP <code>404</code> response content nicely shows a HTML table with all the contexts deployed on the <code>Server</code> instance</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>DefaultHandler</code> is best used as the last <code>Handler</code> of a <code>HandlerList</code>, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Create a HandlerList.</span>
HandlerList handlerList = <span class="keyword">new</span> HandlerList();
<span class="comment">// Add as first a ContextHandlerCollection to manage contexts.</span>
ContextHandlerCollection contexts = <span class="keyword">new</span> ContextHandlerCollection();
handlerList.addHandler(contexts);
<span class="comment">// Add as last a DefaultHandler.</span>
DefaultHandler defaultHandler = <span class="keyword">new</span> DefaultHandler();
handlerList.addHandler(defaultHandler);
<span class="comment">// Link the HandlerList to the Server.</span>
server.setHandler(handlerList);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── HandlerList
├── ContextHandlerCollection
│ ├── ContextHandler 1
│ :── ...
│ └── ContextHandler N
└── DefaultHandler</code></pre>
</div>
</div>
<div class="paragraph">
<p>In the example above, <code>ContextHandlerCollection</code> will try to match a request to one of the contexts; if the match fails, <code>HandlerList</code> will call the next <code>Handler</code> which is <code>DefaultHandler</code> that will return a HTTP <code>404</code> with an HTML page showing the existing contexts deployed on the <code>Server</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<code>DefaultHandler</code> just sends a nicer HTTP <code>404</code> response in case of wrong requests from clients.
Jetty will send an HTTP <code>404</code> response anyway if <code>DefaultHandler</code> is not used.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-http-handler-use-servlet"><a class="anchor" href="#pg-server-http-handler-use-servlet"></a><a class="link" href="#pg-server-http-handler-use-servlet">Servlet API Handlers</a></h5>
<div class="sect5">
<h6 id="pg-server-http-handler-use-servlet-context"><a class="anchor" href="#pg-server-http-handler-use-servlet-context"></a><a class="link" href="#pg-server-http-handler-use-servlet-context">ServletContextHandler</a></h6>
<div class="paragraph">
<p><code>Handler</code>s are easy to write, but often web applications have already been written using the Servlet APIs, using <code>Servlet</code>s and <code>Filter</code>s.</p>
</div>
<div class="paragraph">
<p><code>ServletContextHandler</code> is a <code>ContextHandler</code> that provides support for the Servlet APIs and implements the behaviors required by the Servlet specification.</p>
</div>
<div class="paragraph">
<p>The Maven artifact coordinates are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-servlet<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">ShopCartServlet</span> <span class="directive">extends</span> HttpServlet
{
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> service(HttpServletRequest request, HttpServletResponse response)
{
<span class="comment">// Implement the shop cart functionality.</span>
}
}
Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Create a ServletContextHandler with contextPath.</span>
ServletContextHandler context = <span class="keyword">new</span> ServletContextHandler();
context.setContextPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/shop</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Add the Servlet implementing the cart functionality to the context.</span>
ServletHolder servletHolder = context.addServlet(ShopCartServlet.class, <span class="string"><span class="delimiter">&quot;</span><span class="content">/cart/*</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Configure the Servlet with init-parameters.</span>
servletHolder.setInitParameter(<span class="string"><span class="delimiter">&quot;</span><span class="content">maxItems</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">128</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Add the CrossOriginFilter to protect from CSRF attacks.</span>
FilterHolder filterHolder = context.addFilter(CrossOriginFilter.class, <span class="string"><span class="delimiter">&quot;</span><span class="content">/*</span><span class="delimiter">&quot;</span></span>, <span class="predefined-type">EnumSet</span>.of(DispatcherType.REQUEST));
<span class="comment">// Configure the filter.</span>
filterHolder.setAsyncSupported(<span class="predefined-constant">true</span>);
<span class="comment">// Link the context to the server.</span>
server.setHandler(context);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>Handler</code> and Servlet components tree structure looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Server
└── ServletContextHandler /shop
├── <em>ShopCartServlet /cart/*</em>
└── <em>CrossOriginFilter /*</em></code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how the Servlet components (they are not <code>Handler</code>s) are represented in <em>italic</em>.</p>
</div>
<div class="paragraph">
<p>Note also how adding a <code>Servlet</code> or a <code>Filter</code> returns a <em>holder</em> object that can be used to specify additional configuration for that particular <code>Servlet</code> or <code>Filter</code>.</p>
</div>
<div class="paragraph">
<p>When a request arrives to <code>ServletContextHandler</code> the request URI will be matched against the <code>Filter</code>s and <code>Servlet</code> mappings and only those that match will process the request, as dictated by the Servlet specification.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<code>ServletContextHandler</code> is a terminal <code>Handler</code>, that is it always calls <code>Request.setHandled(true)</code> when invoked.
Server applications must be careful when creating the <code>Handler</code> tree to put <code>ServletContextHandler</code>s as last <code>Handler</code>s in a <code>HandlerList</code> or as children of <code>ContextHandlerCollection</code>.
</td>
</tr>
</table>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-webapp-context"><a class="anchor" href="#pg-server-http-handler-use-webapp-context"></a><a class="link" href="#pg-server-http-handler-use-webapp-context">WebAppContext</a></h6>
<div class="paragraph">
<p><code>WebAppContext</code> is a <code>ServletContextHandler</code> that auto configures itself by reading a <code>web.xml</code> Servlet configuration file.</p>
</div>
<div class="paragraph">
<p>Server applications can specify a <code>*.war</code> file or a directory with the structure of a <code>*.war</code> file to <code>WebAppContext</code> to deploy a standard Servlet web application packaged as a <code>war</code> (as defined by the Servlet specification).</p>
</div>
<div class="paragraph">
<p>Where server applications using <code>ServletContextHandler</code> must manually invoke methods to add <code>Servlet</code>s and <code>Filter</code>s, <code>WebAppContext</code> reads <code>WEB-INF/web.xml</code> to add <code>Servlet</code>s and <code>Filter</code>s, and also enforces a number of restrictions defined by the Servlet specification, in particular related to class loading.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Create a WebAppContext.</span>
WebAppContext context = <span class="keyword">new</span> WebAppContext();
<span class="comment">// Configure the path of the packaged web application (file or directory).</span>
context.setWar(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/webapp.war</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Configure the contextPath.</span>
context.setContextPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/app</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Link the context to the server.</span>
server.setHandler(context);
server.start();</code></pre>
</div>
</div>
<div id="pg-server-http-handler-use-webapp-context-class-loading" class="paragraph">
<div class="title">WebAppContext Class Loading</div>
<p>The Servlet specification requires that a web application class loader must load the web application classes from <code>WEB-INF/classes</code> and <code>WEB_INF/lib</code>.
The web application class loader is special because it behaves differently from typical class loaders: where typical class loaders first delegate to their parent class loader and then try to find the class locally, the web application class loader first tries to find the class locally and then delegates to the parent class loader.
The typical class loading model, parent-first, is <em>inverted</em> for web application class loaders, as they use a child-first model.</p>
</div>
<div class="paragraph">
<p>Furthermore, the Servlet specification requires that web applications cannot load or otherwise access the Servlet container implementation classes, also called <em>server classes</em>.
In the Jetty case, the Servlet specification class <code>javax.servlet.http.HttpServletRequest</code> is implemented by <code>org.eclipse.jetty.server.Request</code>.
Web applications cannot downcast Servlet&#8217;s <code>HttpServletRequest</code> to Jetty&#8217;s <code>Request</code> to access Jetty specific features&#8201;&#8212;&#8201;this ensures maximum web application portability across Servlet container implementations.</p>
</div>
<div class="paragraph">
<p>Lastly, the Servlet specification requires that other classes, also called <em>system classes</em>, such as <code>javax.servlet.http.HttpServletRequest</code> or JDK classes such as <code>java.lang.String</code> or <code>java.sql.Connection</code> cannot be modified by web applications by putting, for example, modified versions of those classes in <code>WEB-INF/classes</code> so that they are loaded first by the web application class loader (instead of the class-path class loader where they are normally loaded from).</p>
</div>
<div class="paragraph">
<p><code>WebAppContext</code> implements this class loader logic using a single class loader, <code>org.eclipse.jetty.webapp.WebAppClassLoader</code>, with filtering capabilities: when it loads a class, it checks whether the class is a <em>system class</em> or a <em>server class</em> and acts according to the Servlet specification.</p>
</div>
<div class="paragraph">
<p>When <code>WebAppClassLoader</code> is asked to load a class, it first tries to find the class locally (since it must use the inverted child-first model); if the class is found, and it is not a <em>system class</em>, the class is loaded; otherwise the class is not found locally.
If the class is not found locally, the parent class loader is asked to load the class; the parent class loader uses the standard parent-first model, so it delegates the class loading to its parent, and so on.
If the class is found, and it is not a <em>server class</em>, the class is loaded; otherwise the class is not found and a <code>ClassNotFoundException</code> is thrown.</p>
</div>
<div class="paragraph">
<p>Unfortunately, the Servlet specification does not define exactly which classes are <em>system classes</em> and which classes are <em>server classes</em>.
However, Jetty picks good defaults and allows server applications to customize <em>system classes</em> and <em>server classes</em> in <code>WebAppContext</code>.</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-use-default-servlet"><a class="anchor" href="#pg-server-http-handler-use-default-servlet"></a><a class="link" href="#pg-server-http-handler-use-default-servlet">DefaultServlet&#8201;&#8212;&#8201;Static Content for Servlets</a></h6>
<div class="paragraph">
<p>If you have a <a href="#pg-server-http-handler-use-servlet-context">Servlet web application</a>, you may want to use a <code>DefaultServlet</code> instead of <code>ResourceHandler</code>.
The features are similar, but <code>DefaultServlet</code> is more commonly used to serve static files for Servlet web applications.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create a ServletContextHandler with contextPath.</span>
ServletContextHandler context = <span class="keyword">new</span> ServletContextHandler();
context.setContextPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/app</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Add the DefaultServlet to serve static content.</span>
ServletHolder servletHolder = context.addServlet(DefaultServlet.class, <span class="string"><span class="delimiter">&quot;</span><span class="content">/</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Configure the DefaultServlet with init-parameters.</span>
servletHolder.setInitParameter(<span class="string"><span class="delimiter">&quot;</span><span class="content">resourceBase</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/static/resources/</span><span class="delimiter">&quot;</span></span>);
servletHolder.setAsyncSupported(<span class="predefined-constant">true</span>);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-http-handler-implement"><a class="anchor" href="#pg-server-http-handler-implement"></a><a class="link" href="#pg-server-http-handler-implement">Implementing Handler</a></h5>
<div class="paragraph">
<p>The <code>Handler</code> API consist fundamentally of just one method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
{
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>target</code> parameter is an identifier for the resource.
This is normally the URI that is parsed from an HTTP request.
However, a request could be forwarded to either a named resource, in which case <code>target</code> will be the name of the resource, or to a different URI, in which case <code>target</code> will be the new URI.</p>
</div>
<div class="paragraph">
<p>Applications may wrap the request or response (or both) and forward the wrapped request or response to a different URI (which may be possibly handled by a different <code>Handler</code>).
This is the reason why there are two request parameters in the <code>Handler</code> APIs: the first is the unwrapped, original, request that also gives access to Jetty-specific APIs, while the second is the application-wrapped Servlet request.</p>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-impl-hello"><a class="anchor" href="#pg-server-http-handler-impl-hello"></a><a class="link" href="#pg-server-http-handler-impl-hello">Hello World Handler</a></h6>
<div class="paragraph">
<p>A simple "Hello World" <code>Handler</code> is the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">HelloWorldHandler</span> <span class="directive">extends</span> AbstractHandler
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) <span class="directive">throws</span> <span class="exception">IOException</span>
{
<span class="comment">// Mark the request as handled by this Handler.</span>
jettyRequest.setHandled(<span class="predefined-constant">true</span>);
response.setStatus(<span class="integer">200</span>);
response.setContentType(<span class="string"><span class="delimiter">&quot;</span><span class="content">text/html; charset=UTF-8</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Write a Hello World response.</span>
response.getWriter().print(<span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;!DOCTYPE html&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;html&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;head&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content"> &lt;title&gt;Jetty Hello World Handler&lt;/title&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;/head&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;body&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content"> &lt;p&gt;Hello World&lt;/p&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;/body&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;/html&gt;</span><span class="delimiter">&quot;</span></span> +
<span class="string"><span class="delimiter">&quot;</span><span class="delimiter">&quot;</span></span>);
}
}
Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Set the Hello World Handler.</span>
server.setHandler(<span class="keyword">new</span> HelloWorldHandler());
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Such a simple <code>Handler</code> extends from <code>AbstractHandler</code> and can access the request and response main features, such as reading request headers and content, or writing response headers and content.</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-handler-impl-filter"><a class="anchor" href="#pg-server-http-handler-impl-filter"></a><a class="link" href="#pg-server-http-handler-impl-filter">Filtering Handler</a></h6>
<div class="paragraph">
<p>A filtering <code>Handler</code> is a handler that perform some modification to the request or response, and then either forwards the request to another <code>Handler</code> or produces an error response:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">FilterHandler</span> <span class="directive">extends</span> HandlerWrapper
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) <span class="directive">throws</span> <span class="exception">IOException</span>, ServletException
{
<span class="predefined-type">String</span> path = request.getRequestURI();
<span class="keyword">if</span> (path.startsWith(<span class="string"><span class="delimiter">&quot;</span><span class="content">/old_path/</span><span class="delimiter">&quot;</span></span>))
{
<span class="comment">// Rewrite old paths to new paths.</span>
HttpURI uri = jettyRequest.getHttpURI();
<span class="predefined-type">String</span> newPath = <span class="string"><span class="delimiter">&quot;</span><span class="content">/new_path/</span><span class="delimiter">&quot;</span></span> + path.substring(<span class="string"><span class="delimiter">&quot;</span><span class="content">/old_path/</span><span class="delimiter">&quot;</span></span>.length());
HttpURI newURI = HttpURI.build(uri).path(newPath);
<span class="comment">// Modify the request object.</span>
jettyRequest.setHttpURI(newURI);
}
<span class="comment">// This Handler is not handling the request, so</span>
<span class="comment">// it does not call jettyRequest.setHandled(true).</span>
<span class="comment">// Forward to the next Handler.</span>
<span class="local-variable">super</span>.handle(target, jettyRequest, request, response);
}
}
Server server = <span class="keyword">new</span> Server();
Connector connector = <span class="keyword">new</span> ServerConnector(server);
server.addConnector(connector);
<span class="comment">// Link the Handlers.</span>
FilterHandler filter = <span class="keyword">new</span> FilterHandler();
filter.setHandler(<span class="keyword">new</span> HelloWorldHandler());
server.setHandler(filter);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how a filtering <code>Handler</code> extends from <code>HandlerWrapper</code> and as such needs another handler to forward the request processing to, and how the two <code>Handler</code>s needs to be linked together to work properly.</p>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-http-security"><a class="anchor" href="#pg-server-http-security"></a><a class="link" href="#pg-server-http-security">Securing HTTP Server Applications</a></h5>
<div class="paragraph">
<p>TODO</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-http-application"><a class="anchor" href="#pg-server-http-application"></a><a class="link" href="#pg-server-http-application">Writing HTTP Server Applications</a></h5>
<div class="paragraph">
<p>Writing HTTP applications is typically simple, especially when using blocking APIs.
However, there are subtle cases where it is worth clarifying what a server application should do to obtain the desired results when run by Jetty.</p>
</div>
<div class="sect5">
<h6 id="pg-server-http-application-1xx"><a class="anchor" href="#pg-server-http-application-1xx"></a><a class="link" href="#pg-server-http-application-1xx">Sending 1xx Responses</a></h6>
<div class="paragraph">
<p>The <a href="https://tools.ietf.org/html/rfc7231#section-5.1.1">HTTP/1.1 RFC</a> allows for <code>1xx</code> informational responses to be sent before a real content response.
Unfortunately the servlet specification does not provide a way for these to be sent, so Jetty has had to provide non-standard handling of these headers.</p>
</div>
</div>
<div class="sect5">
<h6 id="pg-server-http-application-100"><a class="anchor" href="#pg-server-http-application-100"></a><a class="link" href="#pg-server-http-application-100">100 Continue</a></h6>
<div class="paragraph">
<p>The <code>100 Continue</code> response should be sent by the server when a client sends a request with an <code>Expect: 100-continue</code> header, as the client will not send the body of the request until the <code>100 Continue</code> response has been sent.</p>
</div>
<div class="paragraph">
<p>The intent of this feature is to allow a server to inspect the headers and to tell the client to not send a request body that might be too large or insufficiently private or otherwise unable to be handled.</p>
</div>
<div class="paragraph">
<p>Jetty achieves this by waiting until the input stream or reader is obtained by the filter/servlet, before sending the <code>100 Continue</code> response.
Thus a filter/servlet may inspect the headers of a request before getting the input stream and send an error response (or redirect etc.) rather than the 100 continues.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">Continue100HttpServlet</span> <span class="directive">extends</span> HttpServlet
{
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> service(HttpServletRequest request, HttpServletResponse response) <span class="directive">throws</span> <span class="exception">IOException</span>
{
<span class="comment">// Inspect the method and headers.</span>
<span class="type">boolean</span> isPost = HttpMethod.POST.is(request.getMethod());
<span class="type">boolean</span> expects100 = HttpHeaderValue.CONTINUE.is(request.getHeader(<span class="string"><span class="delimiter">&quot;</span><span class="content">Expect</span><span class="delimiter">&quot;</span></span>));
<span class="type">long</span> contentLength = request.getContentLengthLong();
<span class="keyword">if</span> (isPost &amp;&amp; expects100)
{
<span class="keyword">if</span> (contentLength &gt; <span class="integer">1024</span> * <span class="integer">1024</span>)
{
<span class="comment">// Rejects uploads that are too large.</span>
response.sendError(HttpStatus.PAYLOAD_TOO_LARGE_413);
}
<span class="keyword">else</span>
{
<span class="comment">// Getting the request InputStream indicates that</span>
<span class="comment">// the application wants to read the request content.</span>
<span class="comment">// Jetty will send the 100 Continue response at this</span>
<span class="comment">// point, and the client will send the request content.</span>
ServletInputStream input = request.getInputStream();
<span class="comment">// Read and process the request input.</span>
}
}
<span class="keyword">else</span>
{
<span class="comment">// Process normal requests.</span>
}
}
}</code></pre>
</div>
</div>
</div>
<div class="sect5">
<h6 id="jetty-102-processing"><a class="anchor" href="#jetty-102-processing"></a><a class="link" href="#jetty-102-processing">102 Processing</a></h6>
<div class="paragraph">
<p><a href="https://tools.ietf.org/html/rfc2518">RFC 2518</a> defined the <code>102 Processing</code> status code that can be sent:</p>
</div>
<div class="quoteblock">
<blockquote>
when the server has a reasonable expectation that the request will take significant time to complete.
As guidance, if a method is taking longer than 20 seconds (a reasonable, but arbitrary value) to process the server SHOULD return a <code>102 Processing</code> response.
</blockquote>
<div class="attribution">
&#8212; RFC 2518 section 10.1
</div>
</div>
<div class="paragraph">
<p>However, a later update of RFC 2518, <a href="https://tools.ietf.org/html/rfc4918">RFC 4918</a>, removed the <code>102 Processing</code> status code for <a href="https://tools.ietf.org/html/rfc4918#appendix-F.3">"lack of implementation"</a>.</p>
</div>
<div class="paragraph">
<p>Jetty supports the <code>102 Processing</code> status code.
If a request is received with the <code>Expect: 102-processing</code> header, then a filter/servlet may send a <code>102 Processing</code> response (without terminating further processing) by calling <code>response.sendError(102)</code>.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-server-http2"><a class="anchor" href="#pg-server-http2"></a><a class="link" href="#pg-server-http2">HTTP/2 Server Library</a></h3>
<div class="paragraph">
<p>In the vast majority of cases, server applications should use the generic, high-level, <a href="#pg-server-http">HTTP server library</a> that also provides HTTP/2 support via the HTTP/2 <code>ConnectionFactory</code>s as described in details <a href="#pg-server-http-connector-protocol-http2">here</a>.</p>
</div>
<div class="paragraph">
<p>The low-level HTTP/2 server library has been designed for those applications that need low-level access to HTTP/2 features such as <em>sessions</em>, <em>streams</em> and <em>frames</em>, and this is quite a rare use case.</p>
</div>
<div class="paragraph">
<p>See also the correspondent <a href="#pg-client-http2">HTTP/2 client library</a>.</p>
</div>
<div class="sect3">
<h4 id="pg-server-http2-intro"><a class="anchor" href="#pg-server-http2-intro"></a><a class="link" href="#pg-server-http2-intro">Introduction</a></h4>
<div class="paragraph">
<p>The Maven artifact coordinates for the HTTP/2 client library are the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty.http2<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>http2-server<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>HTTP/2 is a multiplexed protocol: it allows multiple HTTP/2 requests to be sent on the same TCP connection.
Each request/response cycle is represented by a <em>stream</em>.
Therefore, a single <em>session</em> manages multiple concurrent <em>streams</em>.
A <em>stream</em> has typically a very short life compared to the <em>session</em>: a <em>stream</em> only exists for the duration of the request/response cycle and then disappears.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http2-flow-control"><a class="anchor" href="#pg-server-http2-flow-control"></a><a class="link" href="#pg-server-http2-flow-control">HTTP/2 Flow Control</a></h4>
<div class="paragraph">
<p>The HTTP/2 protocol is <em>flow controlled</em> (see <a href="https://tools.ietf.org/html/rfc7540#section-5.2">the specification</a>).
This means that a sender and a receiver maintain a <em>flow control window</em> that tracks the number of data bytes sent and received, respectively.
When a sender sends data bytes, it reduces its flow control window.
When a receiver receives data bytes, it also reduces its flow control window, and then passes the received data bytes to the application.
The application consumes the data bytes and tells back the receiver that it has consumed the data bytes.
The receiver then enlarges the flow control window, and arranges to send a message to the sender with the number of bytes consumed, so that the sender can enlarge its flow control window.</p>
</div>
<div class="paragraph">
<p>A sender can send data bytes up to its whole flow control window, then it must stop sending until it receives a message from the receiver that the data bytes have been consumed, which enlarges the flow control window, which allows the sender to send more data bytes.</p>
</div>
<div class="paragraph">
<p>HTTP/2 defines <em>two</em> flow control windows: one for each <em>session</em>, and one for each <em>stream</em>.
Let&#8217;s see with an example how they interact, assuming that in this example the session flow control window is 120 bytes and the stream flow control window is 100 bytes.</p>
</div>
<div class="paragraph">
<p>The sender opens a session, and then opens <code>stream_1</code> on that session, and sends <code>80</code> data bytes.
At this point the session flow control window is <code>40</code> bytes (<code>120 - 80</code>), and <code>stream_1</code>'s flow control window is <code>20</code> bytes (<code>100 - 80</code>).
The sender now opens <code>stream_2</code> on the same session and sends <code>40</code> data bytes.
At this point, the session flow control window is <code>0</code> bytes (<code>40 - 40</code>), while <code>stream_2</code>'s flow control window is <code>60</code> (<code>100 - 40</code>).
Since now the session flow control window is <code>0</code>, the sender cannot send more data bytes, neither on <code>stream_1</code> nor on <code>stream_2</code> despite both have their stream flow control windows greater than <code>0</code>.</p>
</div>
<div class="paragraph">
<p>The receiver consumes <code>stream_2</code>'s <code>40</code> data bytes and sends a message to the sender with this information.
At this point, the session flow control window is <code>40</code> (<code>0 40</code>), <code>stream_1</code>'s flow control window is still <code>20</code> and <code>stream_2</code>'s flow control window is <code>100</code> (<code>60 40</code>).
If the sender opens <code>stream_3</code> and would like to send 50 data bytes, it would only be able to send <code>40</code> because that is the maximum allowed by the session flow control window at this point.</p>
</div>
<div class="paragraph">
<p>It is therefore very important that applications notify the fact that they have consumed data bytes as soon as possible, so that the implementation (the receiver) can send a message to the sender (in the form of a <code>WINDOW_UPDATE</code> frame) with the information to enlarge the flow control window, therefore reducing the possibility that sender stalls due to the flow control windows being reduced to <code>0</code>.</p>
</div>
<div class="paragraph">
<p>How a server application should handle HTTP/2 flow control is discussed in details in <a href="#pg-server-http2-request">this section</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http2-setup"><a class="anchor" href="#pg-server-http2-setup"></a><a class="link" href="#pg-server-http2-setup">Server Setup</a></h4>
<div class="paragraph">
<p>The low-level HTTP/2 support is provided by <code>org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory</code> and <code>org.eclipse.jetty.http2.api.server.ServerSessionListener</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create a Server instance.</span>
Server server = <span class="keyword">new</span> Server();
ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter();
<span class="comment">// Create a ServerConnector with RawHTTP2ServerConnectionFactory.</span>
RawHTTP2ServerConnectionFactory http2 = <span class="keyword">new</span> RawHTTP2ServerConnectionFactory(sessionListener);
<span class="comment">// Configure RawHTTP2ServerConnectionFactory, for example:</span>
<span class="comment">// Configure the max number of concurrent requests.</span>
http2.setMaxConcurrentStreams(<span class="integer">128</span>);
<span class="comment">// Enable support for CONNECT.</span>
http2.setConnectProtocolEnabled(<span class="predefined-constant">true</span>);
<span class="comment">// Create the ServerConnector.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, http2);
<span class="comment">// Add the Connector to the Server</span>
server.addConnector(connector);
<span class="comment">// Start the Server so it starts accepting connections from clients.</span>
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>Where server applications using the <a href="#pg-server-http">high-level server library</a> deal with HTTP requests and responses in <code>Handler</code>s, server applications using the low-level HTTP/2 server library deal directly with HTTP/2 <em>session</em>s, <em>stream</em>s and <em>frame</em>s in a <code>ServerSessionListener</code> implementation.</p>
</div>
<div class="paragraph">
<p>The <code>ServerSessionListener</code> interface defines a number of methods that are invoked by the implementation upon the occurrence of HTTP/2 events, and that server applications can override to react to those events.</p>
</div>
<div class="paragraph">
<p>Please refer to the `ServerSessionListener`<a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/http2/api/server/ServerSessionListener.html">javadocs</a> for the complete list of events.</p>
</div>
<div class="paragraph">
<p>The first event is the <em>accept</em> event and happens when a client opens a new TCP connection to the server and the server accepts the connection.
This is the first occasion where server applications have access to the HTTP/2 <code>Session</code> object:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onAccept(Session session)
{
<span class="predefined-type">SocketAddress</span> remoteAddress = session.getRemoteSocketAddress();
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">http2</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Connection from {0}</span><span class="delimiter">&quot;</span></span>, remoteAddress);
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>After connecting to the server, a compliant HTTP/2 client must send the <a href="https://tools.ietf.org/html/rfc7540#section-3.5">HTTP/2 client preface</a>, and when the server receives it, it generates the <em>preface</em> event on the server.
This is where server applications can customize the connection settings by returning a map of settings that the implementation will send to the client:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Map</span>&lt;<span class="predefined-type">Integer</span>, <span class="predefined-type">Integer</span>&gt; onPreface(Session session)
{
<span class="comment">// Customize the settings, for example:</span>
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">Integer</span>, <span class="predefined-type">Integer</span>&gt; settings = <span class="keyword">new</span> <span class="predefined-type">HashMap</span>&lt;&gt;();
<span class="comment">// Tell the client that HTTP/2 push is disabled.</span>
settings.put(SettingsFrame.ENABLE_PUSH, <span class="integer">0</span>);
<span class="keyword">return</span> settings;
}
};</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http2-request"><a class="anchor" href="#pg-server-http2-request"></a><a class="link" href="#pg-server-http2-request">Receiving a Request</a></h4>
<div class="paragraph">
<p>Receiving an HTTP request from the client, and sending a response, creates a <em>stream</em> that encapsulates the exchange of HTTP/2 frames that compose the request and the response.</p>
</div>
<div class="paragraph">
<p>An HTTP request is made of a <code>HEADERS</code> frame, that carries the request method, the request URI and the request headers, and optional <code>DATA</code> frames that carry the request content.</p>
</div>
<div class="paragraph">
<p>Receiving the <code>HEADERS</code> frame opens the <code>Stream</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
<span class="comment">// This is the &quot;new stream&quot; event, so it's guaranteed to be a request.</span>
MetaData.Request request = (MetaData.Request)frame.getMetaData();
<span class="comment">// Return a Stream.Listener to handle the request events,</span>
<span class="comment">// for example request content events or a request reset.</span>
<span class="keyword">return</span> <span class="keyword">new</span> Stream.Listener.Adapter();
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Server applications should return a <code>Stream.Listener</code> implementation from <code>onNewStream(&#8230;&#8203;)</code> to be notified of events generated by the client, such as <code>DATA</code> frames carrying request content, or a <code>RST_STREAM</code> frame indicating that the client wants to <em>reset</em> the request, or an idle timeout event indicating that the client was supposed to send more frames but it did not.</p>
</div>
<div class="paragraph">
<p>The example below shows how to receive request content:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Request request = (MetaData.Request)frame.getMetaData();
<span class="comment">// Return a Stream.Listener to handle the request events.</span>
<span class="keyword">return</span> <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onData(Stream stream, DataFrame frame, <span class="predefined-type">Callback</span> callback)
{
<span class="comment">// Get the content buffer.</span>
<span class="predefined-type">ByteBuffer</span> buffer = frame.getData();
<span class="comment">// Consume the buffer, here - as an example - just log it.</span>
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">http2</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Consuming buffer {0}</span><span class="delimiter">&quot;</span></span>, buffer);
<span class="comment">// Tell the implementation that the buffer has been consumed.</span>
callback.succeeded();
<span class="comment">// By returning from the method, implicitly tell the implementation</span>
<span class="comment">// to deliver to this method more DATA frames when they are available.</span>
}
};
}
};</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Returning from the <code>onData(&#8230;&#8203;)</code> method implicitly demands for more <code>DATA</code> frames (unless the one just delivered was the last).
Additional <code>DATA</code> frames may be delivered immediately if they are available or later, asynchronously, when they arrive.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Applications that consume the content buffer within <code>onData(&#8230;&#8203;)</code> (for example, writing it to a file, or copying the bytes to another storage) should succeed the callback as soon as they have consumed the content buffer.
This allows the implementation to reuse the buffer, reducing the memory requirements needed to handle the content buffers.</p>
</div>
<div class="paragraph">
<p>Alternatively, a client application may store away <em>both</em> the buffer and the callback to consume the buffer bytes later, or pass <em>both</em> the buffer and the callback to another asynchronous API (this is typical in proxy applications).</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Completing the <code>Callback</code> is very important not only to allow the implementation to reuse the buffer, but also tells the implementation to enlarge the stream and session flow control windows so that the sender will be able to send more <code>DATA</code> frames without stalling.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Applications can also precisely control <em>when</em> to demand more <code>DATA</code> frames, by implementing the <code>onDataDemanded(&#8230;&#8203;)</code> method instead of <code>onData(&#8230;&#8203;)</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">Chunk</span>
{
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">ByteBuffer</span> buffer;
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">Callback</span> callback;
Chunk(<span class="predefined-type">ByteBuffer</span> buffer, <span class="predefined-type">Callback</span> callback)
{
<span class="local-variable">this</span>.buffer = buffer;
<span class="local-variable">this</span>.callback = callback;
}
}
<span class="comment">// A queue that consumers poll to consume content asynchronously.</span>
<span class="predefined-type">Queue</span>&lt;Chunk&gt; dataQueue = <span class="keyword">new</span> <span class="predefined-type">ConcurrentLinkedQueue</span>&lt;&gt;();
<span class="comment">// Implementation of Stream.Listener.onDataDemanded(...)</span>
<span class="comment">// in case of asynchronous content consumption and demand.</span>
Stream.Listener listener = <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onDataDemanded(Stream stream, DataFrame frame, <span class="predefined-type">Callback</span> callback)
{
<span class="comment">// Get the content buffer.</span>
<span class="predefined-type">ByteBuffer</span> buffer = frame.getData();
<span class="comment">// Store buffer to consume it asynchronously, and wrap the callback.</span>
dataQueue.offer(<span class="keyword">new</span> Chunk(buffer, <span class="predefined-type">Callback</span>.from(() -&gt;
{
<span class="comment">// When the buffer has been consumed, then:</span>
<span class="comment">// A) succeed the nested callback.</span>
callback.succeeded();
<span class="comment">// B) demand more DATA frames.</span>
stream.demand(<span class="integer">1</span>);
}, callback::failed)));
<span class="comment">// Do not demand more content here, to avoid to overflow the queue.</span>
}
};</code></pre>
</div>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Applications that implement <code>onDataDemanded(&#8230;&#8203;)</code> must remember to call <code>Stream.demand(&#8230;&#8203;)</code>.
If they don&#8217;t, the implementation will not deliver <code>DATA</code> frames and the application will stall threadlessly until an idle timeout fires to close the stream or the session.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http2-response"><a class="anchor" href="#pg-server-http2-response"></a><a class="link" href="#pg-server-http2-response">Sending a Response</a></h4>
<div class="paragraph">
<p>After receiving an HTTP request, a server application must send an HTTP response.</p>
</div>
<div class="paragraph">
<p>An HTTP response is typically composed of a <code>HEADERS</code> frame containing the HTTP status code and the response headers, and optionally one or more <code>DATA</code> frames containing the response content bytes.</p>
</div>
<div class="paragraph">
<p>The HTTP/2 protocol also supports response trailers (that is, headers that are sent after the response content) that also are sent using a <code>HEADERS</code> frame.</p>
</div>
<div class="paragraph">
<p>A server application can send a response in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
<span class="comment">// Send a response after reading the request.</span>
MetaData.Request request = (MetaData.Request)frame.getMetaData();
<span class="keyword">if</span> (frame.isEndStream())
{
respond(stream, request);
<span class="keyword">return</span> <span class="predefined-constant">null</span>;
}
<span class="keyword">else</span>
{
<span class="keyword">return</span> <span class="keyword">new</span> Stream.Listener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onData(Stream stream, DataFrame frame, <span class="predefined-type">Callback</span> callback)
{
<span class="comment">// Consume the request content.</span>
callback.succeeded();
<span class="keyword">if</span> (frame.isEndStream())
respond(stream, request);
}
};
}
}
<span class="directive">private</span> <span class="type">void</span> respond(Stream stream, MetaData.Request request)
{
<span class="comment">// Prepare the response HEADERS frame.</span>
<span class="comment">// The response HTTP status and HTTP headers.</span>
MetaData.Response response = <span class="keyword">new</span> MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
<span class="keyword">if</span> (HttpMethod.GET.is(request.getMethod()))
{
<span class="comment">// The response content.</span>
<span class="predefined-type">ByteBuffer</span> resourceBytes = getResourceBytes(request);
<span class="comment">// Send the HEADERS frame with the response status and headers,</span>
<span class="comment">// and a DATA frame with the response content bytes.</span>
stream.headers(<span class="keyword">new</span> HeadersFrame(stream.getId(), response, <span class="predefined-constant">null</span>, <span class="predefined-constant">false</span>))
.thenCompose(s -&gt; s.data(<span class="keyword">new</span> DataFrame(s.getId(), resourceBytes, <span class="predefined-constant">true</span>)));
}
<span class="keyword">else</span>
{
<span class="comment">// Send just the HEADERS frame with the response status and headers.</span>
stream.headers(<span class="keyword">new</span> HeadersFrame(stream.getId(), response, <span class="predefined-constant">null</span>, <span class="predefined-constant">true</span>));
}
}
};</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http2-reset"><a class="anchor" href="#pg-server-http2-reset"></a><a class="link" href="#pg-server-http2-reset">Resetting a Request</a></h4>
<div class="paragraph">
<p>A server application may decide that it does not want to accept the request.
For example, it may throttle the client because it sent too many requests in a time window, or the request is invalid (and does not deserve a proper HTTP response), etc.</p>
</div>
<div class="paragraph">
<p>A request can be reset in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
<span class="type">float</span> requestRate = calculateRequestRate();
<span class="keyword">if</span> (requestRate &gt; maxRequestRate)
{
stream.reset(<span class="keyword">new</span> ResetFrame(stream.getId(), ErrorCode.REFUSED_STREAM_ERROR.code), <span class="predefined-type">Callback</span>.NOOP);
<span class="keyword">return</span> <span class="predefined-constant">null</span>;
}
<span class="keyword">else</span>
{
<span class="comment">// The request is accepted.</span>
MetaData.Request request = (MetaData.Request)frame.getMetaData();
<span class="comment">// Return a Stream.Listener to handle the request events.</span>
<span class="keyword">return</span> <span class="keyword">new</span> Stream.Listener.Adapter();
}
}
};</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-http2-push"><a class="anchor" href="#pg-server-http2-push"></a><a class="link" href="#pg-server-http2-push">HTTP/2 Push of Resources</a></h4>
<div class="paragraph">
<p>A server application may <em>push</em> secondary resources related to a primary resource.</p>
</div>
<div class="paragraph">
<p>A client may inform the server that it does not accept pushed resources(see <a href="https://tools.ietf.org/html/rfc7540#section-8.2">this section</a> of the specification) via a <code>SETTINGS</code> frame.
Server applications must track <code>SETTINGS</code> frames and verify whether the client supports HTTP/2 push, and only push if the client supports it:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// The favicon bytes.</span>
<span class="predefined-type">ByteBuffer</span> faviconBuffer = BufferUtil.toBuffer(Resource.newResource(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/favicon.ico</span><span class="delimiter">&quot;</span></span>), <span class="predefined-constant">true</span>);
ServerSessionListener sessionListener = <span class="keyword">new</span> ServerSessionListener.Adapter()
{
<span class="comment">// By default, push is enabled.</span>
<span class="directive">private</span> <span class="type">boolean</span> pushEnabled = <span class="predefined-constant">true</span>;
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onSettings(Session session, SettingsFrame frame)
{
<span class="comment">// Check whether the client sent an ENABLE_PUSH setting.</span>
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">Integer</span>, <span class="predefined-type">Integer</span>&gt; settings = frame.getSettings();
<span class="predefined-type">Integer</span> enablePush = settings.get(SettingsFrame.ENABLE_PUSH);
<span class="keyword">if</span> (enablePush != <span class="predefined-constant">null</span>)
pushEnabled = enablePush == <span class="integer">1</span>;
}
<span class="annotation">@Override</span>
<span class="directive">public</span> Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
MetaData.Request request = (MetaData.Request)frame.getMetaData();
<span class="keyword">if</span> (pushEnabled &amp;&amp; request.getURIString().endsWith(<span class="string"><span class="delimiter">&quot;</span><span class="content">/index.html</span><span class="delimiter">&quot;</span></span>))
{
<span class="comment">// Push the favicon.</span>
HttpURI pushedURI = HttpURI.build(request.getURI()).path(<span class="string"><span class="delimiter">&quot;</span><span class="content">/favicon.ico</span><span class="delimiter">&quot;</span></span>);
MetaData.Request pushedRequest = <span class="keyword">new</span> MetaData.Request(<span class="string"><span class="delimiter">&quot;</span><span class="content">GET</span><span class="delimiter">&quot;</span></span>, pushedURI, HttpVersion.HTTP_2, HttpFields.EMPTY);
PushPromiseFrame promiseFrame = <span class="keyword">new</span> PushPromiseFrame(stream.getId(), <span class="integer">0</span>, pushedRequest);
stream.push(promiseFrame, <span class="keyword">new</span> Stream.Listener.Adapter())
.thenCompose(pushedStream -&gt;
{
<span class="comment">// Send the favicon &quot;response&quot;.</span>
MetaData.Response pushedResponse = <span class="keyword">new</span> MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, HttpFields.EMPTY);
<span class="keyword">return</span> pushedStream.headers(<span class="keyword">new</span> HeadersFrame(pushedStream.getId(), pushedResponse, <span class="predefined-constant">null</span>, <span class="predefined-constant">false</span>))
.thenCompose(pushed -&gt; pushed.data(<span class="keyword">new</span> DataFrame(pushed.getId(), faviconBuffer, <span class="predefined-constant">true</span>)));
});
}
<span class="comment">// Return a Stream.Listener to handle the request events.</span>
<span class="keyword">return</span> <span class="keyword">new</span> Stream.Listener.Adapter();
}
};</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-server-session"><a class="anchor" href="#pg-server-session"></a><a class="link" href="#pg-server-session">HTTP Session Management</a></h3>
<div class="paragraph">
<p>Sessions are a concept within the Servlet API which allow requests to store and retrieve information across the time a user spends in an application.
Jetty provides a number of pluggable options for managing sessions.
In this section we&#8217;ll look at the architecture of session support in Jetty, review the various pluggable options available and indicate what and how to customize should none of the existing options suit your usecase.</p>
</div>
<div class="sect3">
<h4 id="pg-server-session-architecture"><a class="anchor" href="#pg-server-session-architecture"></a><a class="link" href="#pg-server-session-architecture">Session Architecture</a></h4>
<div class="dlist">
<dl>
<dt class="hdlist1">Terminology</dt>
<dd>
<div class="dlist">
<dl>
<dt class="hdlist1">SessionIdManager</dt>
<dd>
<p>is responsible for allocation of session ids</p>
</dd>
<dt class="hdlist1">HouseKeeper</dt>
<dd>
<p>is responsible for orchestrating the detection and removal of expired sessions</p>
</dd>
<dt class="hdlist1">SessionHandler</dt>
<dd>
<p>is responsible for managing the lifecycle of sessions within its associated context</p>
</dd>
<dt class="hdlist1">SessionCache</dt>
<dd>
<p>is an L1 cache of in-use <code>Session</code> objects</p>
</dd>
<dt class="hdlist1">Session</dt>
<dd>
<p>is a stateful object representing a <code>HttpSession</code></p>
</dd>
<dt class="hdlist1">SessionData</dt>
<dd>
<p>encapsulates the attributes and metadata associated with a <code>Session</code></p>
</dd>
<dt class="hdlist1">SessionDataStore</dt>
<dd>
<p>is responsible for creating, storing and reading <code>SessionData</code></p>
</dd>
<dt class="hdlist1">CachingSessionDataStore</dt>
<dd>
<p>is an L2 cache of <code>SessionData</code></p>
</dd>
</dl>
</div>
</dd>
</dl>
</div>
<div class="paragraph">
<p>The session architecture can be represented like so:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-ec0156d64fc9a225c5e022fc352d7d46.png" alt="Diagram" width="511" height="539">
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-session-idmgr"><a class="anchor" href="#pg-server-session-idmgr"></a><a class="link" href="#pg-server-session-idmgr">The SessionIdManager</a></h4>
<div class="paragraph">
<p>There is a maximum of one <code>SessionIdManager</code> per <code>Server</code> instance.
Its purpose is to generate fresh, unique session ids and to coordinate the re-use of session ids amongst co-operating contexts.</p>
</div>
<div class="paragraph">
<p>The <code>SessionIdManager</code> is agnostic with respect to the type of clustering technology chosen.</p>
</div>
<div class="paragraph">
<p>Jetty provides a default implementation - the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionIdManager.html">DefaultSessionIdManager</a> - which should meet the needs of most users.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If you do not explicitly configure a <code>SessionIdManager</code>, then when the <code>SessionHandler</code> starts, it will use an instance of the <code>DefaultSessionIdManager</code>.
</td>
</tr>
</table>
</div>
<div class="sect4">
<h5 id="pg-server-session-defaultidmgr"><a class="anchor" href="#pg-server-session-defaultidmgr"></a><a class="link" href="#pg-server-session-defaultidmgr">The DefaultSessionIdManager</a></h5>
<div class="paragraph">
<p>At startup, if no instance of the <code>HouseKeeper</code> has been explicitly set, the <code>DefaultSessionIdManager</code> will create one.</p>
</div>
<div id="pg-server-session-workername" class="paragraph">
<p>Also at startup, the <code>workerName</code> is determined.
The <code>workerName</code> must be unique per <code>Server</code>, and identifies the server in a cluster.
If a <code>workerName</code> has not been explicitly set, then the value is derived as follows:</p>
</div>
<div class="paragraph">
<p>node[JETTY_WORKER_NAME]</p>
</div>
<div class="paragraph">
<p>where <code>JETTY_WORKER_NAME</code> is an environment variable whose value can be an integer or string.
If the environment variable is not set, then it defaults to <code>0</code>, yielding the default <code>workerName</code> of <code>"node0"</code>.</p>
</div>
<div class="paragraph">
<p>The <code>DefaultSessionIdManager</code> uses <code>SecureRandom</code> to generate unique session ids.</p>
</div>
<div class="paragraph">
<p>The <code>SessionHandler</code> class, which is used by both the <code>ServletContextHandler</code> and the <code>WebAppContext</code> classes, will instantiate a <code>DefaultSessionIdManager</code> on startup if it does not detect one already present for the <code>Server</code>.</p>
</div>
<div class="paragraph">
<p>Here is an example of explicitly setting up a <code>DefaultSessionIdManager</code> with a <code>workerName</code> of <code>server3</code> in code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
DefaultSessionIdManager idMgr = <span class="keyword">new</span> DefaultSessionIdManager(server);
<span class="comment">//you must set the workerName unless you set the env viable JETTY_WORKER_NAME</span>
idMgr.setWorkerName(<span class="string"><span class="delimiter">&quot;</span><span class="content">server3</span><span class="delimiter">&quot;</span></span>);
server.setSessionIdManager(idMgr);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-implementing-a-custom-sessionidmanager"><a class="anchor" href="#pg-implementing-a-custom-sessionidmanager"></a><a class="link" href="#pg-implementing-a-custom-sessionidmanager">Implementing a Custom SessionIdManager</a></h4>
<div class="paragraph">
<p>If the <code>DefaultSessionIdManager</code> does not meet your needs, you can extend it, or implement the <code>SessionIdManager</code> interface directly.</p>
</div>
<div class="paragraph">
<p>When implementing a <code>SessionIdManager</code> pay particular attention to the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the <code>getWorkerName()</code> method <em>must</em> return a name that is unique to the <code>Server</code> instance.
The <code>workerName</code> becomes important in clustering scenarios because sessions can migrate from node to node: the <code>workerName</code> identifies which node was last managing a <code>Session</code>.</p>
</li>
<li>
<p>the contract of the <code>isIdInUse(String id)</code> method is very specific: a session id may <em>only</em> be reused <em>iff</em> it is already in use by another context.
This restriction is important to support cross-context dispatch.</p>
</li>
<li>
<p>you should be <em>very</em> careful to ensure that the <code>newSessionId(HttpServletRequest request, long created)</code> method does not return duplicate or predictable session ids.</p>
</li>
</ul>
</div>
<div class="sect4">
<h5 id="pg-server-session-housekeeper"><a class="anchor" href="#pg-server-session-housekeeper"></a><a class="link" href="#pg-server-session-housekeeper">The HouseKeeper</a></h5>
<div class="paragraph">
<p>There is a maximum of one <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/HouseKeeper.html">HouseKeeper</a> per <code>SessionIdManager</code>.
Its purpose is to periodically poll the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/SessionHandler.html">SessionHandlers</a> to clean out expired sessions.
This operation is usually referred to as "scavenging" expired sessions.
The scavenging interval is configured by the <code>setIntervalSec(long)</code> method.
The default value is <code>600</code>sec, ie <code>10</code>mins.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The HouseKeeper semi-randomly adds an additional <code>10%</code> of the configured <code>intervalSec</code>.
This is to help prevent sync-ing up of servers in a cluster that are all restarted at once, and slightly stagger their scavenge cycles to ensure any load on the persistent storage mechanism is spread out.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This code example shows how to configure a <code>HouseKeeper</code>, along with a <code>DefaultSessionIdManager</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
DefaultSessionIdManager idMgr = <span class="keyword">new</span> DefaultSessionIdManager(server);
idMgr.setWorkerName(<span class="string"><span class="delimiter">&quot;</span><span class="content">server7</span><span class="delimiter">&quot;</span></span>);
server.setSessionIdManager(idMgr);
HouseKeeper houseKeeper = <span class="keyword">new</span> HouseKeeper();
houseKeeper.setSessionIdManager(idMgr);
<span class="comment">//set the frequency of scavenge cycles</span>
houseKeeper.setIntervalSec(<span class="integer">600L</span>);
idMgr.setSessionHouseKeeper(houseKeeper);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-session-handler"><a class="anchor" href="#pg-server-session-handler"></a><a class="link" href="#pg-server-session-handler">The SessionHandler</a></h4>
<div class="paragraph">
<p>Each context can have a single <code>SessionHandler</code>.
The purpose of the <code>SessionHandler</code> is to interact with the <code>Request</code> and <code>Response</code> to create, maintain and propagate sessions.
It also calls the context-level session listeners at appropriate points in the session lifecycle.</p>
</div>
<div class="sect4">
<h5 id="pg-configuration"><a class="anchor" href="#pg-configuration"></a><a class="link" href="#pg-configuration">Configuration</a></h5>
<div class="paragraph">
<p>The majority of configuration for the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/SessionHandler.html">SessionHandler</a> can be done via <code>web.xml</code> <code>&lt;session-config&gt;</code> declarations, or the <code>javax.servlet.SessionCookieConfig</code> api.
There are also a few jetty-specific configuration options that we will cover here:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">checkingRemoteSessionIdEncoding</dt>
<dd>
<p>Boolean, default <code>false</code>.
This controls whether or not the <code>javax.servlet.http.Response.encodeURL(String)</code> method will include the session id as a path parameter when the URL is destined for a remote node.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>setting the <code>org.eclipse.jetty.servlet.CheckingRemoteSessionIdEncoding</code> context init paramter</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">setMaxInactiveInterval</dt>
<dd>
<p>Integer, seconds.
This is the amount of time after which an unused session may be scavenged.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>defining the <code>&lt;session-config&gt;&lt;session-timeout/&gt;&lt;/session-config&gt;</code> element in <code>web.xml</code>, although take note that this element is specified in <em>minutes</em> but this method uses <em>seconds</em>.</p>
</li>
<li>
<p>calling the <code>javax.servlet.ServletContext.setSessionTimeout(int)</code> method, where the timeout is configured in <em>minutes</em>.</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">setHttpOnly</dt>
<dd>
<p>Boolean, default <code>false</code>.
If <code>true</code>, the session cookie will not be exposed to client-side scripting code.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>using <code>javax.servlet.SessionCookieConfig.setHttpOnly(boolean)</code> method</p>
</li>
<li>
<p>defining the <code>&lt;session-config&gt;&lt;cookie-config&gt;&lt;http-only/&gt;&lt;/cookie-config&gt;&lt;/session-config&gt;</code> element in <code>web.xml</code></p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
<div id="pg-server-session-handler-refreshcookie" class="dlist">
<dl>
<dt class="hdlist1">refreshCookieAge</dt>
<dd>
<p>Integer, seconds, default is <code>-1</code>.
This controls resetting the session cookie when <code>SessionCookieConfig.setMaxAge(int)</code> is non-zero.
See also <a href="#pg-server-session-maxAge">setting the max session cookie age with an init parameter</a>.
If the amount of time since the session cookie was last set exceeds this time, the session cookie is regenerated to keep the session cookie valid.</p>
</dd>
<dt class="hdlist1">sameSite</dt>
<dd>
<p><code>HttpCookie.SameSite</code>, default <code>null</code>.
The values are <code>HttpCookie.SameSite.NONE</code>, <code>HttpCookie.SameSite.STRICT</code>, <code>HttpCookie.SameSite.LAX</code>.</p>
</dd>
<dt class="hdlist1">secureRequestOnly</dt>
<dd>
<p>Boolean, default <code>true</code>.
If <code>true</code> and the request is HTTPS, the set session cookie will be marked as <code>secure</code>, meaning the client will only send the session cookie to the server on subsequent requests over HTTPS.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>using the <code>javax.servlet.SessionCookieConfig.setSecure(true)</code> method, in which case the set session cookie will <em>always</em> be marked as <code>secure</code>, even if the request triggering the creation of the cookie was not over HTTPS.</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">sessionCookie</dt>
<dd>
<p>String, default is <code>JSESSIONID</code>.
This is the name of the session cookie.
It can alternatively be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>using <code>javax.servlet.SessionCookieConfig.setName(String)</code> method</p>
</li>
<li>
<p>setting the <code>org.eclipse.jetty.servlet.SessionCookie</code> context init parameter.</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">sessionIdPathParameterName</dt>
<dd>
<p>String, default is <code>jsessionid</code>.
This is the name of the path parameter used to transmit the session id on request URLs, and on encoded URLS in responses.
It can alternatively be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>setting the <code>org.eclipse.jetty.servlet.SessionIdPathParameterName</code> context init parameter</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">sessionTrackingModes</dt>
<dd>
<p><code>Set&lt;javax.servlet.SessionTrackingMode&gt;</code>.
Default is <code>SessionTrackingMode.COOKIE</code>, <code>SessionTrackingMode.URL</code>.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>using the <code>setSessionTrackingModes(Set&lt;javax.servlet.SessionTrackingMode&gt;)</code> method</p>
</li>
<li>
<p>using the <code>javax.servlet.ServletContext.setSessionTrackingModes&lt;Set&lt;javax.servlet.SessionTrackingMode&gt;)</code> method</p>
</li>
<li>
<p>defining up to three <code>&lt;tracking-mode&gt;</code>s for the <code>&lt;session-config&gt;</code> element in <code>web.xml</code></p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">usingCookies</dt>
<dd>
<p>Boolean, default <code>true</code>.
Determines whether or not the <code>SessionHandler</code> will look for session cookies on requests, and will set session cookies on responses.
If <code>false</code> session ids must be transmitted as path params on URLs.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>using the <code>setSessionTrackingModes(Set&lt;javax.servlet.SessionTrackingMode&gt;)</code> method</p>
</li>
<li>
<p>using the <code>javax.servlet.ServletContext.setSessionTrackingModes&lt;Set&lt;javax.servlet.SessionTrackingMode&gt;)</code> method</p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
<div class="paragraph">
<p>There are also a few session settings that do not have SessionHandler setters, but can be configured with context init parameters:</p>
</div>
<div id="pg-server-session-handler-maxAge" class="dlist">
<dl>
<dt class="hdlist1">org.eclipse.jetty.servlet.MaxAge</dt>
<dd>
<p>This is the maximum number of seconds that the session cookie will be considered to be valid.
By default, the cookie has no maximum validity time.
See also <a href="#pg-server-session-refreshcookie">refreshing the session cookie</a>.
The value can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>calling the <code>SessionCookieConfig.setMaxAge(int)</code> method.</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">org.eclipse.jetty.servlet.SessionDomain</dt>
<dd>
<p>String, default <code>null</code>.
This is the domain of the session cookie.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>using the <code>javax.servlet.SessionCookieConfig.setDomain(String)</code> method</p>
</li>
<li>
<p>defining the <code>&lt;session-config&gt;&lt;cookie-config&gt;&lt;domain/&gt;&lt;/cookie-config&gt;&lt;/session-config&gt;</code> element in <code>web.xml</code></p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">org.eclipse.jetty.servlet.SessionPath</dt>
<dd>
<p>String, default <code>null</code>.
This is used when creating a new session cookie.
If nothing is configured, the context path is used instead, defaulting to <code>/</code>.
This can also be configured by:</p>
<div class="ulist">
<ul>
<li>
<p>using the <code>javax.servlet.SessionCookieConfig.setPath(String)</code> method</p>
</li>
<li>
<p>defining the <code>&lt;session-config&gt;&lt;cookie-config&gt;&lt;path/&gt;&lt;/cookie-config&gt;&lt;/session-config&gt;</code> element in <code>web.xml</code></p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
</div>
<div class="sect4">
<h5 id="pg-statistics"><a class="anchor" href="#pg-statistics"></a><a class="link" href="#pg-statistics">Statistics</a></h5>
<div class="paragraph">
<p>Some statistics about the sessions for a context can be obtained from the <code>SessionHandler</code>, either by calling the methods directly or via <code>jmx</code>:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">sessionsCreated</dt>
<dd>
<p>This is the total number of sessions that have been created for this context since Jetty started.</p>
</dd>
<dt class="hdlist1">sessionTimeMax</dt>
<dd>
<p>The longest period of time a session was valid in this context before being invalidated.</p>
</dd>
<dt class="hdlist1">sessionTimeMean</dt>
<dd>
<p>The average period of time a session in this context was valid.</p>
</dd>
<dt class="hdlist1">sessionTimeStdDev</dt>
<dd>
<p>The standard deviation of the session validity times for this context.</p>
</dd>
<dt class="hdlist1">sessionTimeTotal</dt>
<dd>
<p>The total time that all sessions in this context have remained valid.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>You can reset the statistics counters by either calling the following method directly on the the <code>SessionHandler</code>, or using <code>jmx</code>:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">statsReset</dt>
<dd>
<p>Resets the <code>SessionHandler</code> statistics counters.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-session-cache"><a class="anchor" href="#pg-server-session-cache"></a><a class="link" href="#pg-server-session-cache">The SessionCache</a></h4>
<div class="paragraph">
<p>There is one <code>SessionCache</code> per <code>SessionHandler</code>, and thus one per context.
Its purpose is to provide an L1 cache of <code>Session</code> objects.
Having a working set of <code>Session</code> objects in memory allows multiple simultaneous requests for the same session to share the same <code>Session</code> object.
A <code>SessionCache</code> uses a <code>SessionDataStore</code> to create, read, store and delete the <code>SessionData</code> associated with the <code>Session</code>.</p>
</div>
<div class="paragraph">
<p>There are two ways to create a <code>SessionCache</code> for a <code>SessionHandler</code>:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>allow the <code>SessionHandler</code> to create one lazily at startup.
The <code>SessionHandler</code> looks for a <code>SessionCacheFactory</code> bean on the server to produce the <code>SessionCache</code> instance.
It then looks for a <code>SessionDataStoreFactory</code> bean on the server to produce a <code>SessionDataStore</code> instance to use with the <code>SessionCache</code>.</p>
</li>
<li>
<p>pass a fully configured <code>SessionCache</code> instance to the <code>SessionHandler</code>.
You are responsible for configuring both the <code>SessionCache</code> instance and its <code>SessionDataStore</code></p>
</li>
</ol>
</div>
<div class="paragraph">
<p>More on <code>SessionDataStore</code>s <a href="#pg-server-session-datastore">later</a>, in this section we will concentrate on the <code>SessionCache</code> and <code>SessionCacheFactory</code>.</p>
</div>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/AbstractSessionCache.html">AbstractSessionCache</a> provides most of the behaviour of <code>SessionCache</code>s.
If you are implementing a custom <code>SessionCache</code> we strongly recommend you extend this base class, as the Servlet Specification has many subtleties and extending the base class ensures that your implementation will take account of them.</p>
</div>
<div class="paragraph">
<p>Some of the important behaviours of <code>SessionCache</code>s are:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">eviction</dt>
<dd>
<p>By default, sessions remain in a cache until they are expired or invalidated.
If you have many or large sessions that are infrequently referenced you can use eviction to reduce the memory consumed by the cache.
When a session is evicted, it is removed from the cache but it is <em>not</em> invalidated.
If you have configured a <code>SessionDataStore</code> that persists or distributes the session in some way, it will continue to exist, and can be read back in when it needs to be referenced again.
The eviction strategies are:</p>
<div class="dlist">
<dl>
<dt class="hdlist1">NEVER_EVICT</dt>
<dd>
<p>This is the default, sessions remain in the cache until expired or invalidated.</p>
</dd>
<dt class="hdlist1">EVICT_ON_SESSION_EXIT</dt>
<dd>
<p>When the last simultaneous request for a session finishes, the session will be evicted from the cache.</p>
</dd>
<dt class="hdlist1">EVICT_ON_INACTIVITY</dt>
<dd>
<p>If a session has not been referenced for a configurable number of seconds, then it will be evicted from the cache.</p>
</dd>
</dl>
</div>
</dd>
<dt class="hdlist1">saveOnInactiveEviction</dt>
<dd>
<p>This controls whether a session will be persisted to the <code>SessionDataStore</code> if it is being evicted due to the EVICT_ON_INACTIVITY policy.
Usually sessions are written to the <code>SessionDataStore</code> whenever the last simultaneous request exits the session.
However, as <code>SessionDataStores</code> can be configured to <a href="#pg-server-session-datastore-skip">skip some writes</a>, this option ensures that the session will be written out.</p>
</dd>
<dt class="hdlist1">saveOnCreate</dt>
<dd>
<p>Usually a session will be written through to the configured <code>SessionDataStore</code> when the last request for it finishes.
In the case of a freshly created session, this means that it will not be persisted until the request is fully finished.
If your application uses context forwarding or including, the newly created session id will not be available in the subsequent contexts.
You can enable this feature to ensure that a freshly created session is immediately persisted after creation: in this way the session id will be available for use in other contexts accessed during the same request.</p>
</dd>
<dt class="hdlist1">removeUnloadableSessions</dt>
<dd>
<p>If a session becomes corrupted in the persistent store, it cannot be re-loaded into the <code>SessionCache</code>.
This can cause noisy log output during scavenge cycles, when the same corrupted session fails to load over and over again.
To prevent his, enable this feature and the <code>SessionCache</code> will ensure that if a session fails to be loaded, it will be deleted.</p>
</dd>
<dt class="hdlist1">invalidateOnShutdown</dt>
<dd>
<p>Some applications want to ensure that all cached sessions are removed when the server shuts down.
This option will ensure that all cached sessions are invalidated.
The <code>AbstractSessionCache</code> does not implement this behaviour, a subclass must implement the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/SessionCache.html#shutdown()">SessionCache.shutdown()</a> method.</p>
</dd>
<dt class="hdlist1">flushOnResponseCommit</dt>
<dd>
<p>This forces a "dirty" session to be written to the <code>SessionDataStore</code> just before a response is returned to the client, rather than waiting until the request is finished.
A "dirty" session is one whose attributes have changed, or it has been freshly created.
Using this option ensures that all subsequent requests - either to the same or a different node - will see the latest changes to the session.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Jetty provides two <code>SessionCache</code> implementations: the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionCache.html">DefaultSessionCache</a> and the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/NullSessionCache.html">NullSessionCache</a>.</p>
</div>
<div class="sect4">
<h5 id="pg-server-session-hash"><a class="anchor" href="#pg-server-session-hash"></a><a class="link" href="#pg-server-session-hash">The DefaultSessionCache</a></h5>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionCache.html">DefaultSessionCache</a> retains <code>Session</code> objects in memory in a <code>ConcurrentHashMap</code>.
It is suitable for non-clustered and clustered deployments.
For clustered deployments, a sticky load balancer is <strong>strongly</strong> recommended, otherwise you risk indeterminate session state as the session bounces around multiple nodes.</p>
</div>
<div class="paragraph">
<p>It implements the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/SessionCache.html#shutdown()">SessionCache.shutdown()</a> method.</p>
</div>
<div class="paragraph">
<p>It also provides some statistics on sessions, which are convenient to access either directly in code or remotely via jmx:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">current sessions</dt>
<dd>
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionCache.html#getSessionsCurrent()">DefaultSessionCache.getSessionsCurrent()</a> reports the number of sessions in the cache at the time of the method call.</p>
</dd>
<dt class="hdlist1">max sessions</dt>
<dd>
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionCache.html#getSessionsCurrent()">DefaultSessionCache.getSessionsMax()</a> reports the highest number of sessions in the cache at the time of the method call.</p>
</dd>
<dt class="hdlist1">total sessions</dt>
<dd>
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionCache.html#getSessionsTotal()">DefaultSessionCache.getSessionsTotal()</a> reports the cumulative total of the number of sessions in the cache at the time of the method call.</p>
</dd>
<dt class="hdlist1">reset</dt>
<dd>
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionCache.html#resetStats()">DefaultSessionCache.resetStats()</a> zeros out the statistics counters.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>If you create a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.html">DefaultSessionFactory</a> and register it as <code>Server</code> bean, a <code>SessionHandler</code> will be able to lazily create a <code>DefaultSessionCache</code>.
The <code>DefaultSessionCacheFactory</code> has all of the same configuration setters as a <code>DefaultSessionCache</code>.
Alternatively, if you only have a single <code>SessionHandler</code>, or you need to configure a <code>DefaultSessionCache</code> differently for every <code>SessionHandler</code>, then you could dispense with the <code>DefaultSessionCacheFactory</code> and simply instantiate, configure and pass in the <code>DefaultSessionCache</code> yourself.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
DefaultSessionCacheFactory cacheFactory = <span class="keyword">new</span> DefaultSessionCacheFactory();
<span class="comment">//EVICT_ON_INACTIVE: evict a session after 60sec inactivity</span>
cacheFactory.setEvictionPolicy(<span class="integer">60</span>);
<span class="comment">//Only useful with the EVICT_ON_INACTIVE policy</span>
cacheFactory.setSaveOnInactiveEvict(<span class="predefined-constant">true</span>);
cacheFactory.setFlushOnResponseCommit(<span class="predefined-constant">true</span>);
cacheFactory.setInvalidateOnShutdown(<span class="predefined-constant">false</span>);
cacheFactory.setRemoveUnloadableSessions(<span class="predefined-constant">true</span>);
cacheFactory.setSaveOnCreate(<span class="predefined-constant">true</span>);
<span class="comment">//Add the factory as a bean to the server, now whenever a</span>
<span class="comment">//SessionHandler starts it will consult the bean to create a new DefaultSessionCache</span>
server.addBean(cacheFactory);</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If you don&#8217;t configure any <code>SessionCache</code> or <code>SessionCacheFactory</code>, the <code>SessionHandler</code> will automatically create a <code>DefaultSessionCache</code>.
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-session-null"><a class="anchor" href="#pg-server-session-null"></a><a class="link" href="#pg-server-session-null">The NullSessionCache</a></h5>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/NullSessionCache.html">NullSessionCache</a> does not actually cache any objects: each request uses a fresh <code>Session</code> object.
It is suitable for clustered deployments without a sticky load balancer and non-clustered deployments when purely minimal support for sessions is needed.</p>
</div>
<div class="paragraph">
<p>As no sessions are actually cached, of course functions like <code>invalidateOnShutdown</code> and all of the eviction strategies have no meaning for the <code>NullSessionCache</code>.</p>
</div>
<div class="paragraph">
<p>There is a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/NullSessionCacheFactory.html">NullSessionCacheFactory</a> which you can instantiate, configure and set as a <code>Server</code> bean to enable the <code>SessionHandler</code> to automatically create new <code>NullCache</code>s as needed.
All of the same configuration options are available on the <code>NullSessionCacheFactory</code> as the <code>NullSessionCache</code> itself.
Alternatively, if you only have a single <code>SessionHandler</code>, or you need to configure a <code>NullSessionCache</code> differently for every <code>SessionHandler</code>, then you could dispense with the <code>NullSessionCacheFactory</code> and simply instantiate, configure and pass in the <code>NullSessionCache</code> yourself.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
NullSessionCacheFactory cacheFactory = <span class="keyword">new</span> NullSessionCacheFactory();
cacheFactory.setFlushOnResponseCommit(<span class="predefined-constant">true</span>);
cacheFactory.setRemoveUnloadableSessions(<span class="predefined-constant">true</span>);
cacheFactory.setSaveOnCreate(<span class="predefined-constant">true</span>);
<span class="comment">//Add the factory as a bean to the server, now whenever a</span>
<span class="comment">//SessionHandler starts it will consult the bean to create a new NullSessionCache</span>
server.addBean(cacheFactory);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-session-customcache"><a class="anchor" href="#pg-server-session-customcache"></a><a class="link" href="#pg-server-session-customcache">Implementing a Custom SessionCache</a></h5>
<div class="paragraph">
<p>As previously mentioned, we highly recommend that you extend the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/AbstractSessionCache.html">AbstractSessionCache</a>.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-heterogeneous-caching"><a class="anchor" href="#pg-heterogeneous-caching"></a><a class="link" href="#pg-heterogeneous-caching">Heterogeneous Caching</a></h5>
<div class="paragraph">
<p>Using one of the <code>SessionCacheFactory</code>s will ensure that every time a <code>SessionHandler</code> starts it will create a new instance of the corresponding type of <code>SessionCache</code>.</p>
</div>
<div class="paragraph">
<p>But, what if you deploy multiple webapps, and for one of them, you don&#8217;t want to use sessions?
Or alternatively, you don&#8217;t want to use sessions, but you have one webapp that now needs them?
In that case, you can configure the <code>SessionCacheFactory</code> appropriate to the majority, and then specifically create the right type of <code>SessionCache</code> for the others.
Here&#8217;s an example where we configure the <code>DefaultSessionCacheFactory</code> to handle most webapps, but then specifically use a <code>NullSessionCache</code> for another:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
DefaultSessionCacheFactory cacheFactory = <span class="keyword">new</span> DefaultSessionCacheFactory();
<span class="comment">//NEVER_EVICT</span>
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
cacheFactory.setFlushOnResponseCommit(<span class="predefined-constant">true</span>);
cacheFactory.setInvalidateOnShutdown(<span class="predefined-constant">false</span>);
cacheFactory.setRemoveUnloadableSessions(<span class="predefined-constant">true</span>);
cacheFactory.setSaveOnCreate(<span class="predefined-constant">true</span>);
<span class="comment">//Add the factory as a bean to the server, now whenever a</span>
<span class="comment">//SessionHandler starts it will consult the bean to create a new DefaultSessionCache</span>
server.addBean(cacheFactory);
ContextHandlerCollection contexts = <span class="keyword">new</span> ContextHandlerCollection();
server.setHandler(contexts);
<span class="comment">//Add a webapp that will use a DefaultSessionCache via the DefaultSessionCacheFactory</span>
WebAppContext app1 = <span class="keyword">new</span> WebAppContext();
app1.setContextPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/app1</span><span class="delimiter">&quot;</span></span>);
contexts.addHandler(app1);
<span class="comment">//Add a webapp that uses an explicit NullSessionCache instead</span>
WebAppContext app2 = <span class="keyword">new</span> WebAppContext();
app2.setContextPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/app2</span><span class="delimiter">&quot;</span></span>);
NullSessionCache nullSessionCache = <span class="keyword">new</span> NullSessionCache(app2.getSessionHandler());
nullSessionCache.setFlushOnResponseCommit(<span class="predefined-constant">true</span>);
nullSessionCache.setRemoveUnloadableSessions(<span class="predefined-constant">true</span>);
nullSessionCache.setSaveOnCreate(<span class="predefined-constant">true</span>);
<span class="comment">//If we pass an existing SessionCache instance to the SessionHandler, it must be</span>
<span class="comment">//fully configured: this means we must also provide SessionDataStore</span>
nullSessionCache.setSessionDataStore(<span class="keyword">new</span> NullSessionDataStore());
app2.getSessionHandler().setSessionCache(nullSessionCache);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-session-datastore"><a class="anchor" href="#pg-server-session-datastore"></a><a class="link" href="#pg-server-session-datastore">The SessionDataStore</a></h4>
<div class="paragraph">
<p>A <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/SessionDataStore.html">SessionDataStore</a> mediates the storage, retrieval and deletion of <code>SessionData</code>.
There is one <code>SessionDataStore</code> per <code>SessionCache</code>.
The server libraries provide a number of alternative <code>SessionDataStore</code> implementations.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-fb3e088ea5480f2b172677334c79d51f.png" alt="Diagram" width="1210" height="303">
</div>
</div>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/AbstractSessionDataStore.html">AbstractSessionDataStore</a> provides most of the behaviour common to <code>SessionDataStore</code>s:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">passivation</dt>
<dd>
<p>Supporting passivation means that session data is serialized.
Some persistence mechanisms serialize, such as JDBC, GCloud Datastore etc.
Others store an object in shared memory, e.g. Infinispan and thus don&#8217;t serialize session data.
Whether or not a persistence technology entails passivation controls whether or not <code>HttpSessionActivationListener</code>s will be called.
When implementing a custom <code>SessionDataStore</code> you need to decide whether or not passivation will be supported.</p>
</dd>
</dl>
</div>
<div id="pg-server-session-datastore-skip" class="dlist">
<dl>
<dt class="hdlist1">savePeriod</dt>
<dd>
<p>This is an interval defined in seconds.
It is used to reduce the frequency with which <code>SessionData</code> is written.
Normally, whenever the last concurrent request leaves a <code>Session</code>, the <code>SessionData</code> for that <code>Session</code> is always persisted, even if the only thing that changed is the <code>lastAccessTime</code>.
If the <code>savePeriod</code> is non-zero, the <code>SessionData</code> will not be persisted if no session attributes changed, <em>unless</em> the time since the last save exceeds the <code>savePeriod</code>.
Setting a non-zero value can reduce the load on the persistence mechanism, but in a clustered environment runs the risk that other nodes will see the session as expired because it has not been persisted sufficiently recently.</p>
</dd>
</dl>
</div>
<div id="pg-server-session-datastore-grace" class="dlist">
<dl>
<dt class="hdlist1">gracePeriod</dt>
<dd>
<p>The <code>gracePeriod</code> is an interval defined in seconds.
It is an attempt to deal with the non-transactional nature of sessions with regard to finding sessions that have expired.
In a clustered configuration - even with a sticky load balancer - it is always possible that a session is "live" on a node but not yet updated in the persistent store.
This means that it can be hard to determine at any given moment whether a clustered session has truly expired.
Thus, we use the <code>gracePeriod</code> to provide a bit of leeway around the moment of expiry during <a href="#pg-server-session-housekeeper">scavenge</a>:</p>
<div class="ulist">
<ul>
<li>
<p>on every <a href="#pg-server-session-housekeeper">scavenge</a> cycle an <code>AbstractSessionDataStore</code> searches for sessions that belong to the context that expired at least one <code>gracePeriod</code> ago</p>
</li>
<li>
<p>infrequently the <code>AbstractSessionDataStore</code> searches for and summarily deletes sessions - from any context - that expired at least 10 <code>gracePeriod</code>s ago</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">NOTE</dt>
<dd>
<p>The trivial <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/NullSessionDataStore.html">NullSessionDataStore</a> - which does not persist sessions - is the default used by the <code>SessionHandler</code>.</p>
</dd>
</dl>
</div>
<div class="sect4">
<h5 id="pg-server-session-datastore-file"><a class="anchor" href="#pg-server-session-datastore-file"></a><a class="link" href="#pg-server-session-datastore-file">The FileSessionDataStore</a></h5>
<div class="paragraph">
<p>The <code>FileSessionDataStore</code> supports persistent storage of session data in a filesystem.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
Persisting sessions to the local file system should <strong>never</strong> be used in a clustered environment.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>One file represents one session in one context.</p>
</div>
<div class="paragraph">
<p>File names follow this pattern:</p>
</div>
<div class="paragraph">
<p>[expiry]_[contextpath]_[virtualhost]_[id]</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">expiry</dt>
<dd>
<p>This is the expiry time in milliseconds since the epoch.</p>
</dd>
<dt class="hdlist1">contextpath</dt>
<dd>
<p>This is the context path with any special characters, including <code>/</code>, replaced by the <code><em></code> underscore character.
For example, a context path of <code>/catalog</code> would become <code>_catalog</code>.
A context path of simply <code>/</code> becomes just <code>_</em></code>.</p>
</dd>
<dt class="hdlist1">virtualhost</dt>
<dd>
<p>This is the first virtual host associated with the context and has the form of 4 digits separated by <code>.</code> characters.
If there are no virtual hosts associated with a context, then <code>0.0.0.0</code> is used:</p>
<div class="literalblock">
<div class="content">
<pre>[digit].[digit].[digit].[digit]</pre>
</div>
</div>
</dd>
<dt class="hdlist1">id</dt>
<dd>
<p>This is the unique id of the session.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Putting all of the above together as an example, a session with an id of <code>node0ek3vx7x2y1e7pmi3z00uqj1k0</code> for the context with path <code>/test</code> with no virtual hosts and an expiry of <code>1599558193150</code> would have a file name of:</p>
</div>
<div class="paragraph">
<p><code>1599558193150__test_0.0.0.0_node0ek3vx7x2y1e7pmi3z00uqj1k0</code></p>
</div>
<div class="sect5">
<h6 id="pg-configuration-2"><a class="anchor" href="#pg-configuration-2"></a><a class="link" href="#pg-configuration-2">Configuration</a></h6>
<div class="paragraph">
<p>You can configure either a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/FileSessionDataStore.html">FileSessionDataStore</a> individually, or a <code>FileSessionDataStoreFactory</code> if you want multiple <code>SessionHandler</code>s to use <code>FileSessionDataStore</code>s that are identically configured.
The configuration methods are:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">storeDir</dt>
<dd>
<p>This is a File that defines the location for storage of session files.
If the directory does not exist at startup, it will be created.
If you use the same <code>storeDir</code> for multiple <code>SessionHandlers</code>, then the sessions for all of those contexts are stored in the same directory.
This is not a problem, as the name of the file is unique because it contains the context information.
You <em>must</em> supply a value for this, otherwise startup of the <code>FileSessionDataStore</code> will fail.</p>
</dd>
<dt class="hdlist1">deleteUnrestorableFiles</dt>
<dd>
<p>Boolean, default <code>false</code>.
If set to <code>true</code>, unreadable files will be deleted.
This is useful to prevent repeated logging of the same error when the <a href="#pg-server-session-housekeeper">scavenger</a> periodically (re-)attempts to load the corrupted information for a session in order to expire it.</p>
</dd>
<dt class="hdlist1">savePeriod</dt>
<dd>
<p>This is an interval defined in seconds.
It is used to reduce the frequency with which <code>SessionData</code> is written.
Normally, whenever the last concurrent request leaves a <code>Session</code>, the <code>SessionData</code> for that <code>Session</code> is always persisted, even if the only thing that changed is the <code>lastAccessTime</code>.
If the <code>savePeriod</code> is non-zero, the <code>SessionData</code> will not be persisted if no session attributes changed, <em>unless</em> the time since the last save exceeds the <code>savePeriod</code>.
Setting a non-zero value can reduce the load on the persistence mechanism, but in a clustered environment runs the risk that other nodes will see the session as expired because it has not been persisted sufficiently recently.</p>
</dd>
</dl>
</div>
<div id="pg-server-session-datastore-grace" class="dlist">
<dl>
<dt class="hdlist1">gracePeriod</dt>
<dd>
<p>The <code>gracePeriod</code> is an interval defined in seconds.
It is an attempt to deal with the non-transactional nature of sessions with regard to finding sessions that have expired.
In a clustered configuration - even with a sticky load balancer - it is always possible that a session is "live" on a node but not yet updated in the persistent store.
This means that it can be hard to determine at any given moment whether a clustered session has truly expired.
Thus, we use the <code>gracePeriod</code> to provide a bit of leeway around the moment of expiry during <a href="#pg-server-session-housekeeper">scavenge</a>:</p>
<div class="ulist">
<ul>
<li>
<p>on every <a href="#pg-server-session-housekeeper">scavenge</a> cycle an <code>AbstractSessionDataStore</code> searches for sessions that belong to the context that expired at least one <code>gracePeriod</code> ago</p>
</li>
<li>
<p>infrequently the <code>AbstractSessionDataStore</code> searches for and summarily deletes sessions - from any context - that expired at least 10 <code>gracePeriod</code>s ago</p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Let&#8217;s look at an example of configuring a <code>FileSessionDataStoreFactory</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">//First lets configure a DefaultSessionCacheFactory</span>
DefaultSessionCacheFactory cacheFactory = <span class="keyword">new</span> DefaultSessionCacheFactory();
<span class="comment">//NEVER_EVICT</span>
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
cacheFactory.setFlushOnResponseCommit(<span class="predefined-constant">true</span>);
cacheFactory.setInvalidateOnShutdown(<span class="predefined-constant">false</span>);
cacheFactory.setRemoveUnloadableSessions(<span class="predefined-constant">true</span>);
cacheFactory.setSaveOnCreate(<span class="predefined-constant">true</span>);
<span class="comment">//Add the factory as a bean to the server, now whenever a</span>
<span class="comment">//SessionHandler starts it will consult the bean to create a new DefaultSessionCache</span>
server.addBean(cacheFactory);
<span class="comment">//Now, lets configure a FileSessionDataStoreFactory</span>
FileSessionDataStoreFactory storeFactory = <span class="keyword">new</span> FileSessionDataStoreFactory();
storeFactory.setStoreDir(<span class="keyword">new</span> <span class="predefined-type">File</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">/tmp/sessions</span><span class="delimiter">&quot;</span></span>));
storeFactory.setGracePeriodSec(<span class="integer">3600</span>);
storeFactory.setSavePeriodSec(<span class="integer">0</span>);
<span class="comment">//Add the factory as a bean on the server, now whenever a</span>
<span class="comment">//SessionHandler starts, it will consult the bean to create a new FileSessionDataStore</span>
<span class="comment">//for use by the DefaultSessionCache</span>
server.addBean(storeFactory);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Here&#8217;s an alternate example, configuring a <code>FileSessionDataStore</code> directly:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">//create a context</span>
WebAppContext app1 = <span class="keyword">new</span> WebAppContext();
app1.setContextPath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/app1</span><span class="delimiter">&quot;</span></span>);
<span class="comment">//First, we create a DefaultSessionCache</span>
DefaultSessionCache cache = <span class="keyword">new</span> DefaultSessionCache(app1.getSessionHandler());
cache.setEvictionPolicy(SessionCache.NEVER_EVICT);
cache.setFlushOnResponseCommit(<span class="predefined-constant">true</span>);
cache.setInvalidateOnShutdown(<span class="predefined-constant">false</span>);
cache.setRemoveUnloadableSessions(<span class="predefined-constant">true</span>);
cache.setSaveOnCreate(<span class="predefined-constant">true</span>);
<span class="comment">//Now, we configure a FileSessionDataStore</span>
FileSessionDataStore store = <span class="keyword">new</span> FileSessionDataStore();
store.setStoreDir(<span class="keyword">new</span> <span class="predefined-type">File</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">/tmp/sessions</span><span class="delimiter">&quot;</span></span>));
store.setGracePeriodSec(<span class="integer">3600</span>);
store.setSavePeriodSec(<span class="integer">0</span>);
<span class="comment">//Tell the cache to use the store</span>
cache.setSessionDataStore(store);
<span class="comment">//Tell the contex to use the cache/store combination</span>
app1.getSessionHandler().setSessionCache(cache);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-session-datastore-jdbc"><a class="anchor" href="#pg-server-session-datastore-jdbc"></a><a class="link" href="#pg-server-session-datastore-jdbc">The JDBCSessionDataStore</a></h5>
<div class="paragraph">
<p>The <code>JDBCSessionDataStore</code> supports persistent storage of session data in a relational database.
To do that, it requires a <code>DatabaseAdaptor</code> that handles the differences between databases (eg Oracle, Postgres etc), and a <code>SessionTableSchema</code> that allows for the customization of table and column names.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-8bbf1fa0b84011383e811eaf9e630100.png" alt="Diagram" width="336" height="174">
</div>
</div>
<div class="paragraph">
<p><code>SessionData</code> is stored in a table with one row per session.
This is the table, with the table name, column names and type keywords at their default settings:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table:JettySessions</caption>
<colgroup>
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3333%;">
<col style="width: 8.3337%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">sessionId</th>
<th class="tableblock halign-left valign-top">contextPath</th>
<th class="tableblock halign-left valign-top">virtualHost</th>
<th class="tableblock halign-left valign-top">lastNode</th>
<th class="tableblock halign-left valign-top">accessTime</th>
<th class="tableblock halign-left valign-top">lastAccessTime</th>
<th class="tableblock halign-left valign-top">createTime</th>
<th class="tableblock halign-left valign-top">cookieTime</th>
<th class="tableblock halign-left valign-top">lastSavedTime</th>
<th class="tableblock halign-left valign-top">expiryTime</th>
<th class="tableblock halign-left valign-top">maxInterval</th>
<th class="tableblock halign-left valign-top">map</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">120 varchar</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">60 varchar</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">60 varchar</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">60 varchar</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">long</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">long</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">long</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">long</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">long</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">long</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">long</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">blob</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The name of the table and all columns can be configured using the <code>SessionTableSchema</code> class described below.
Many databases use different keywords for the <code>long</code>, <code>blob</code> and <code>varchar</code> types, so you can explicitly configure these if jetty cannot determine what they should be at runtime based on the metadata available from a db connection using the <code>DatabaseAdaptor</code> class described below.</p>
</div>
<div class="sect5">
<h6 id="pg-configuration-3"><a class="anchor" href="#pg-configuration-3"></a><a class="link" href="#pg-configuration-3">Configuration</a></h6>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/JDBCSessionDataStore.html">JDBCSessionDataStore</a> and corresponding <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/JDBCSessionDataStoreFactory.html">JDBCSessionDataStoreFactory</a> supports the following configuration:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">savePeriod</dt>
<dd>
<p>This is an interval defined in seconds.
It is used to reduce the frequency with which <code>SessionData</code> is written.
Normally, whenever the last concurrent request leaves a <code>Session</code>, the <code>SessionData</code> for that <code>Session</code> is always persisted, even if the only thing that changed is the <code>lastAccessTime</code>.
If the <code>savePeriod</code> is non-zero, the <code>SessionData</code> will not be persisted if no session attributes changed, <em>unless</em> the time since the last save exceeds the <code>savePeriod</code>.
Setting a non-zero value can reduce the load on the persistence mechanism, but in a clustered environment runs the risk that other nodes will see the session as expired because it has not been persisted sufficiently recently.</p>
</dd>
</dl>
</div>
<div id="pg-server-session-datastore-grace" class="dlist">
<dl>
<dt class="hdlist1">gracePeriod</dt>
<dd>
<p>The <code>gracePeriod</code> is an interval defined in seconds.
It is an attempt to deal with the non-transactional nature of sessions with regard to finding sessions that have expired.
In a clustered configuration - even with a sticky load balancer - it is always possible that a session is "live" on a node but not yet updated in the persistent store.
This means that it can be hard to determine at any given moment whether a clustered session has truly expired.
Thus, we use the <code>gracePeriod</code> to provide a bit of leeway around the moment of expiry during <a href="#pg-server-session-housekeeper">scavenge</a>:</p>
<div class="ulist">
<ul>
<li>
<p>on every <a href="#pg-server-session-housekeeper">scavenge</a> cycle an <code>AbstractSessionDataStore</code> searches for sessions that belong to the context that expired at least one <code>gracePeriod</code> ago</p>
</li>
<li>
<p>infrequently the <code>AbstractSessionDataStore</code> searches for and summarily deletes sessions - from any context - that expired at least 10 <code>gracePeriod</code>s ago</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">DatabaseAdaptor</dt>
<dd>
<p>The <code>DatabaseAdaptor</code> can connect to a database either via a <code>javax.sql.Datasource</code> or a <code>java.sql.Driver</code>.
Additionally, a database-specific keyword can be configured for the <code>blob</code>, <code>varchar</code> and <code>long</code> types.
Note that the <code>DatabaseAdaptor</code> tries to automatically detect the type of the database from the first connection and select the appropriate type keywords, however you may need to explicitly configure them if you&#8217;re not using <code>Postgres</code> or <code>Oracle</code>.</p>
<div class="dlist">
<dl>
<dt class="hdlist1">datasource</dt>
<dd>
<p>This can either be a <code>Datasource</code> instance or the jndi name of a <code>Datasource</code> to look up.</p>
</dd>
</dl>
</div>
</dd>
</dl>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">DatabaseAdaptor datasourceAdaptor = <span class="keyword">new</span> DatabaseAdaptor();
datasourceAdaptor.setDatasourceName(<span class="string"><span class="delimiter">&quot;</span><span class="content">/jdbc/myDS</span><span class="delimiter">&quot;</span></span>);</code></pre>
</div>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">driverInfo</dt>
<dd>
<p>This is the name or instance of a jdbc <code>Driver</code> class and a connection url.</p>
</dd>
</dl>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">DatabaseAdaptor driverAdaptor = <span class="keyword">new</span> DatabaseAdaptor();
driverAdaptor.setDriverInfo(<span class="string"><span class="delimiter">&quot;</span><span class="content">com.mysql.jdbc.Driver</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">jdbc:mysql://127.0.0.1:3306/sessions?user=sessionsadmin</span><span class="delimiter">&quot;</span></span>);</code></pre>
</div>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">blobType</dt>
<dd>
<p>Default <code>blob</code> or <code>bytea</code> for Postgres.</p>
</dd>
<dt class="hdlist1">longType</dt>
<dd>
<p>Default <code>bigint</code> or <code>number(20)</code> for Oracle.</p>
</dd>
<dt class="hdlist1">stringType</dt>
<dd>
<p>Default <code>varchar</code>.</p>
<div class="dlist">
<dl>
<dt class="hdlist1">SessionTableSchema</dt>
</dl>
</div>
</dd>
<dt class="hdlist1">schemaName</dt>
<dt class="hdlist1">catalogName</dt>
<dd>
<p>The exact meaning of these two are dependent on your database vendor, but can broadly be described as further scoping for the session table name.
See <a href="https://en.wikipedia.org/wiki/Database_schema" class="bare">https://en.wikipedia.org/wiki/Database_schema</a> and <a href="https://en.wikipedia.org/wiki/Database_catalog" class="bare">https://en.wikipedia.org/wiki/Database_catalog</a>.
These extra scoping names can come into play at startup time when Jetty determines if the session table already exists, or otherwise creates it on-the-fly.
If you have employed either of these concepts when you pre-created the session table, or you want to ensure that Jetty uses them when it auto-creates the session table, then you have two options: either set them explicitly, or let Jetty infer them from a database connection.
If you leave them unset, then no scoping will be done.
If you use the special value <code>INFERRED</code>, Jetty will determine them from a database connection.</p>
</dd>
<dt class="hdlist1">tableName</dt>
<dd>
<p>Default <code>JettySessions</code>.
This is the name of the table in which session data is stored.</p>
</dd>
<dt class="hdlist1">accessTimeColumn</dt>
<dd>
<p>Default <code>accessTime</code>.
This is the name of the column that stores the time - in ms since the epoch - at which a session was last accessed</p>
</dd>
<dt class="hdlist1">contextPathColumn</dt>
<dd>
<p>Default <code>contextPath</code>.
This is the name of the column that stores the <code>contextPath</code> of a session.</p>
</dd>
<dt class="hdlist1">cookieTimeColumn</dt>
<dd>
<p>Default <code>cookieTime</code>.
This is the name of the column that stores the time - in ms since the epoch - that the cookie was last set for a session.</p>
</dd>
<dt class="hdlist1">createTimeColumn</dt>
<dd>
<p>Default <code>createTime</code>.
This is the name of the column that stores the time - in ms since the epoch - at which a session was created.</p>
</dd>
<dt class="hdlist1">expiryTimeColumn</dt>
<dd>
<p>Default <code>expiryTime</code>.
This is name of the column that stores - in ms since the epoch - the time at which a session will expire.</p>
</dd>
<dt class="hdlist1">lastAccessTimeColumn</dt>
<dd>
<p>Default <code>lastAccessTime</code>.
This is the name of the column that stores the time - in ms since the epoch - that a session was previously accessed.</p>
</dd>
<dt class="hdlist1">lastSavedTimeColumn</dt>
<dd>
<p>Default <code>lastSavedTime</code>.
This is the name of the column that stores the time - in ms since the epoch - at which a session was last written.</p>
</dd>
<dt class="hdlist1">idColumn</dt>
<dd>
<p>Default <code>sessionId</code>.
This is the name of the column that stores the id of a session.</p>
</dd>
<dt class="hdlist1">lastNodeColumn</dt>
<dd>
<p>Default <code>lastNode</code>.
This is the name of the column that stores the <code>workerName</code> of the last node to write a session.</p>
</dd>
<dt class="hdlist1">virtualHostColumn</dt>
<dd>
<p>Default <code>virtualHost</code>.
This is the name of the column that stores the first virtual host of the context of a session.</p>
</dd>
<dt class="hdlist1">maxIntervalColumn</dt>
<dd>
<p>Default <code>maxInterval</code>.
This is the name of the column that stores the interval - in ms - during which a session can be idle before being considered expired.</p>
</dd>
<dt class="hdlist1">mapColumn</dt>
<dd>
<p>Default <code>map</code>.
This is the name of the column that stores the serialized attributes of a session.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-session-datastore-mongo"><a class="anchor" href="#pg-server-session-datastore-mongo"></a><a class="link" href="#pg-server-session-datastore-mongo">The MongoSessionDataStore</a></h5>
<div class="paragraph">
<p>The <code>MongoSessionDataStore</code> supports persistence of <code>SessionData</code> in a nosql database.</p>
</div>
<div class="paragraph">
<p>The best description for the document model for session information is found in the javadoc for the <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.html">MongoSessionDataStore</a>.
In overview, it can be represented thus:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-ae4b86cecdafb2b8e1afb35b06f359a1.png" alt="Diagram" width="177" height="218">
</div>
</div>
<div class="paragraph">
<p>The database contains a document collection for the sessions.
Each document represents a session id, and contains one nested document per context in which that session id is used.
For example, the session id <code>abcd12345</code> might be used by two contexts, one with path <code>/contextA</code> and one with path <code>/contextB</code>.
In that case, the outermost document would refer to <code>abcd12345</code> and it would have a nested document for <code>/contextA</code> containing the session attributes for that context, and another nested document for <code>/contextB</code> containing the session attributes for that context.
Remember, according to the Servlet Specification, a session id can be shared by many contexts, but the attributes must be unique per context.</p>
</div>
<div class="paragraph">
<p>The outermost document contains these fields:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">id</dt>
<dd>
<p>The session id.</p>
</dd>
<dt class="hdlist1">created</dt>
<dd>
<p>The time (in ms since the epoch) at which the session was first created in any context.</p>
</dd>
<dt class="hdlist1">maxIdle</dt>
<dd>
<p>The time (in ms) for which an idle session is regarded as valid.
As maxIdle times can be different for <code>Session</code>s from different contexts, this is the <em>shortest</em> maxIdle time.</p>
</dd>
<dt class="hdlist1">expiry</dt>
<dd>
<p>The time (in ms since the epoch) at which the session will expire.
As the expiry time can be different for <code>Session</code>s from different contexts, this is the <em>shortest</em> expiry time.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Each nested context-specific document contains:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">attributes</dt>
<dd>
<p>The session attributes as a serialized map.</p>
</dd>
<dt class="hdlist1">lastSaved</dt>
<dd>
<p>The time (in ms since the epoch) at which the session in this context was saved.</p>
</dd>
<dt class="hdlist1">lastAccessed</dt>
<dd>
<p>The time (in ms since the epoch) at which the session in this context was previously accessed.</p>
</dd>
<dt class="hdlist1">accessed</dt>
<dd>
<p>The time (in ms since the epoch) at which this session was most recently accessed.</p>
</dd>
<dt class="hdlist1">lastNode</dt>
<dd>
<p>The <a href="#pg-server-session-workername">workerName</a> of the last server that saved the session data.</p>
</dd>
<dt class="hdlist1">version</dt>
<dd>
<p>An object that is updated every time a session is written out for a context.</p>
</dd>
</dl>
</div>
<div class="sect5">
<h6 id="pg-configuration-4"><a class="anchor" href="#pg-configuration-4"></a><a class="link" href="#pg-configuration-4">Configuration</a></h6>
<div class="paragraph">
<p>You can configure either a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.html">MongoSessionDataStore</a> individually, or a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.html">MongoSessionDataStoreFactory</a> if you want multiple <code>SessionHandler</code>s to use <code>MongoSessionDataStore</code>s that are identically configured.
The configuration methods for the <code>MongoSessionDataStoreFactory</code> are:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">savePeriod</dt>
<dd>
<p>This is an interval defined in seconds.
It is used to reduce the frequency with which <code>SessionData</code> is written.
Normally, whenever the last concurrent request leaves a <code>Session</code>, the <code>SessionData</code> for that <code>Session</code> is always persisted, even if the only thing that changed is the <code>lastAccessTime</code>.
If the <code>savePeriod</code> is non-zero, the <code>SessionData</code> will not be persisted if no session attributes changed, <em>unless</em> the time since the last save exceeds the <code>savePeriod</code>.
Setting a non-zero value can reduce the load on the persistence mechanism, but in a clustered environment runs the risk that other nodes will see the session as expired because it has not been persisted sufficiently recently.</p>
</dd>
</dl>
</div>
<div id="pg-server-session-datastore-grace" class="dlist">
<dl>
<dt class="hdlist1">gracePeriod</dt>
<dd>
<p>The <code>gracePeriod</code> is an interval defined in seconds.
It is an attempt to deal with the non-transactional nature of sessions with regard to finding sessions that have expired.
In a clustered configuration - even with a sticky load balancer - it is always possible that a session is "live" on a node but not yet updated in the persistent store.
This means that it can be hard to determine at any given moment whether a clustered session has truly expired.
Thus, we use the <code>gracePeriod</code> to provide a bit of leeway around the moment of expiry during <a href="#pg-server-session-housekeeper">scavenge</a>:</p>
<div class="ulist">
<ul>
<li>
<p>on every <a href="#pg-server-session-housekeeper">scavenge</a> cycle an <code>AbstractSessionDataStore</code> searches for sessions that belong to the context that expired at least one <code>gracePeriod</code> ago</p>
</li>
<li>
<p>infrequently the <code>AbstractSessionDataStore</code> searches for and summarily deletes sessions - from any context - that expired at least 10 <code>gracePeriod</code>s ago</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">dbName</dt>
<dd>
<p>This is the name of the database.</p>
</dd>
<dt class="hdlist1">collectionName</dt>
<dd>
<p>The name of the document collection.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>There are two alternative ways to specify the connection to mongodb:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">connectionString</dt>
<dd>
<p>This is a mongodb url, eg <code>mongodb://localhost</code></p>
</dd>
<dt class="hdlist1">host</dt>
<dt class="hdlist1">port</dt>
<dd>
<p>This is the hostname and port number of the mongodb instance to contact.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Let&#8217;s look at an example of configuring a <code>MongoSessionDataStoreFactory</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
MongoSessionDataStoreFactory mongoSessionDataStoreFactory = <span class="keyword">new</span> MongoSessionDataStoreFactory();
mongoSessionDataStoreFactory.setGracePeriodSec(<span class="integer">3600</span>);
mongoSessionDataStoreFactory.setSavePeriodSec(<span class="integer">0</span>);
mongoSessionDataStoreFactory.setDbName(<span class="string"><span class="delimiter">&quot;</span><span class="content">HttpSessions</span><span class="delimiter">&quot;</span></span>);
mongoSessionDataStoreFactory.setCollectionName(<span class="string"><span class="delimiter">&quot;</span><span class="content">JettySessions</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Either set the connectionString</span>
mongoSessionDataStoreFactory.setConnectionString(<span class="string"><span class="delimiter">&quot;</span><span class="content">mongodb:://localhost:27017</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// or alternatively set the host and port.</span>
mongoSessionDataStoreFactory.setHost(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>);
mongoSessionDataStoreFactory.setPort(<span class="integer">27017</span>);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-server-session-cachingsessiondatastore"><a class="anchor" href="#pg-server-session-cachingsessiondatastore"></a><a class="link" href="#pg-server-session-cachingsessiondatastore">The CachingSessionDataStore</a></h5>
<div class="imageblock">
<div class="content">
<img src="diag-3e23a5cd9673dbe358271d004cc0d714.png" alt="Diagram" width="341" height="282">
</div>
</div>
<div class="paragraph">
<p>The <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/CachingSessionDataStore.html">CachingSessionDataStore</a> is a special type of <code>SessionDataStore</code> that checks an L2 cache for <code>SessionData</code> before checking a delegate <code>SessionDataStore</code>.
This can improve the performance of slow stores.</p>
</div>
<div class="paragraph">
<p>The L2 cache is an instance of a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/session/SessionDataMap.html">SessionDataMap</a>.
Jetty provides one implementation of this L2 cache based on <code>memcached</code>, <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.html">MemcachedSessionDataMap</a>.</p>
</div>
<div class="sect5">
<h6 id="pg-configuration-5"><a class="anchor" href="#pg-configuration-5"></a><a class="link" href="#pg-configuration-5">Configuration</a></h6>
<div class="paragraph">
<p>Here&#8217;s an example of how to programmatically configure <code>CachingSessionDataStore</code>s, using a <a href="#pg-server-session-datastore-file">FileSessionDataStore</a> as a delegate, and <code>memcached</code> as the L2 cache:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">//Make a factory for memcached L2 caches for SessionData</span>
MemcachedSessionDataMapFactory mapFactory = <span class="keyword">new</span> MemcachedSessionDataMapFactory();
mapFactory.setExpirySec(<span class="integer">0</span>); <span class="comment">//items in memcached don't expire</span>
mapFactory.setHeartbeats(<span class="predefined-constant">true</span>); <span class="comment">//tell memcached to use heartbeats</span>
mapFactory.setAddresses(<span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">localhost</span><span class="delimiter">&quot;</span></span>, <span class="integer">11211</span>)); <span class="comment">//use a local memcached instance</span>
mapFactory.setWeights(<span class="keyword">new</span> <span class="type">int</span><span class="type">[]</span> {<span class="integer">100</span>}); <span class="comment">//set the weighting</span>
<span class="comment">//Make a FileSessionDataStoreFactory for creating FileSessionDataStores</span>
<span class="comment">//to persist the session data</span>
FileSessionDataStoreFactory storeFactory = <span class="keyword">new</span> FileSessionDataStoreFactory();
storeFactory.setStoreDir(<span class="keyword">new</span> <span class="predefined-type">File</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">/tmp/sessions</span><span class="delimiter">&quot;</span></span>));
storeFactory.setGracePeriodSec(<span class="integer">3600</span>);
storeFactory.setSavePeriodSec(<span class="integer">0</span>);
<span class="comment">//Make a factory that plugs the L2 cache into the SessionDataStore</span>
CachingSessionDataStoreFactory cachingSessionDataStoreFactory = <span class="keyword">new</span> CachingSessionDataStoreFactory();
cachingSessionDataStoreFactory.setSessionDataMapFactory(mapFactory);
cachingSessionDataStoreFactory.setSessionStoreFactory(storeFactory);
<span class="comment">//Register it as a bean so that all SessionHandlers will use it</span>
<span class="comment">//to make FileSessionDataStores that use memcached as an L2 SessionData cache.</span>
server.addBean(cachingSessionDataStoreFactory);</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-server-websocket"><a class="anchor" href="#pg-server-websocket"></a><a class="link" href="#pg-server-websocket">WebSocket Server Libraries</a></h3>
<div class="paragraph">
<p>TODO</p>
</div>
</div>
<div class="sect2">
<h3 id="pg-server-io-arch"><a class="anchor" href="#pg-server-io-arch"></a><a class="link" href="#pg-server-io-arch">Server Libraries I/O Architecture</a></h3>
<div class="paragraph">
<p>The Jetty server libraries provide the basic components and APIs to implement a network server.</p>
</div>
<div class="paragraph">
<p>They build on the common <a href="#pg-arch-io">Jetty I/O Architecture</a> and provide server specific concepts.</p>
</div>
<div class="paragraph">
<p>The central I/O server-side component is <code>org.eclipse.jetty.server.ServerConnector</code>.
A <code>ServerConnector</code> manages a list of <code>ConnectionFactory</code>s, that indicate what protocols the connector is able to speak.</p>
</div>
<div class="sect3">
<h4 id="pg-server-io-arch-connection-factory"><a class="anchor" href="#pg-server-io-arch-connection-factory"></a><a class="link" href="#pg-server-io-arch-connection-factory">Creating Connections with <code>ConnectionFactory</code></a></h4>
<div class="paragraph">
<p>Recall from the <a href="#pg-arch-io-connection"><code>Connection</code> section</a> of the Jetty I/O architecture that <code>Connection</code> instances are responsible for parsing bytes read from a TCP connection and generating bytes to write to that TCP connection.</p>
</div>
<div class="paragraph">
<p>On the server-side, a <code>ConnectionFactory</code> creates <code>Connection</code> instances that know how to parse and generate bytes for the specific protocol they support&#8201;&#8212;&#8201;it can be either HTTP/1.1, or TLS, or FastCGI, or the <a href="https://www.haproxy.org/download/2.1/doc/proxy-protocol.txt">PROXY protocol</a>.</p>
</div>
<div class="paragraph">
<p>For example, this is how clear-text HTTP/1.1 is configured:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create the HTTP/1.1 ConnectionFactory.</span>
HttpConnectionFactory http = <span class="keyword">new</span> HttpConnectionFactory();
Server server = <span class="keyword">new</span> Server();
<span class="comment">// Create the connector with the ConnectionFactory.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, http);
connector.setPort(<span class="integer">8080</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>With this configuration, the <code>ServerConnector</code> will listen on port <code>8080</code>.
When a new TCP connection is established, <code>ServerConnector</code> delegates to the <code>ConnectionFactory</code> the creation of the <code>Connection</code> instance for that TCP connection, that is linked to the corresponding <code>EndPoint</code>:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-00a63842ecad6f53a729253fd05edf2b.png" alt="Diagram" width="628" height="109">
</div>
</div>
<div class="paragraph">
<p>For every TCP connection there will be an <code>EndPoint</code> + <code>Connection</code> pair.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-io-arch-connection-factory-wrapping"><a class="anchor" href="#pg-server-io-arch-connection-factory-wrapping"></a><a class="link" href="#pg-server-io-arch-connection-factory-wrapping">Wrapping a <code>ConnectionFactory</code></a></h4>
<div class="paragraph">
<p>A <code>ConnectionFactory</code> may wrap another <code>ConnectionFactory</code>; for example, the TLS protocol provides encryption for any other protocol.
Therefore, to support encrypted HTTP/1.1 (also known as <code>https</code>), you need to configure the <code>ServerConnector</code> with two <code>ConnectionFactory</code>s&#8201;&#8212;&#8201;one for the TLS protocol and one for the HTTP/1.1 protocol, like in the example below:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create the HTTP/1.1 ConnectionFactory.</span>
HttpConnectionFactory http = <span class="keyword">new</span> HttpConnectionFactory();
<span class="comment">// Create and configure the TLS context factory.</span>
SslContextFactory.Server sslContextFactory = <span class="keyword">new</span> SslContextFactory.Server();
sslContextFactory.setKeyStorePath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keystore.p12</span><span class="delimiter">&quot;</span></span>);
sslContextFactory.setKeyStorePassword(<span class="string"><span class="delimiter">&quot;</span><span class="content">secret</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Create the TLS ConnectionFactory,</span>
<span class="comment">// setting HTTP/1.1 as the wrapped protocol.</span>
SslConnectionFactory tls = <span class="keyword">new</span> SslConnectionFactory(sslContextFactory, http.getProtocol());
Server server = <span class="keyword">new</span> Server();
<span class="comment">// Create the connector with both ConnectionFactories.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, tls, http);
connector.setPort(<span class="integer">8443</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>With this configuration, the <code>ServerConnector</code> will listen on port <code>8443</code>.
When a new TCP connection is established, the first <code>ConnectionFactory</code> configured in <code>ServerConnector</code> is invoked to create a <code>Connection</code>.
In the example above, <code>SslConnectionFactory</code> creates a <code>SslConnection</code> and then asks to its wrapped <code>ConnectionFactory</code> (in the example, <code>HttpConnectionFactory</code>) to create the wrapped <code>Connection</code> (an <code>HttpConnection</code>) and will then link the two <code>Connection</code>s together, in this way:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="diag-2ddf657fd45a511dea7478530a23f3ab.png" alt="Diagram" width="846" height="250">
</div>
</div>
<div class="paragraph">
<p>Bytes read by the <code>SocketEndPoint</code> will be interpreted as TLS bytes by the <code>SslConnection</code>, then decrypted and made available to the <code>DecryptedEndPoint</code> (a component part of <code>SslConnection</code>), which will then provide them to <code>HttpConnection</code>.</p>
</div>
<div class="paragraph">
<p>The application writes bytes through the <code>HttpConnection</code> to the <code>DecryptedEndPoint</code>, which will encrypt them through the <code>SslConnection</code> and write the encrypted bytes to the <code>SocketEndPoint</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-io-arch-connection-factory-detecting"><a class="anchor" href="#pg-server-io-arch-connection-factory-detecting"></a><a class="link" href="#pg-server-io-arch-connection-factory-detecting">Choosing <code>ConnectionFactory</code> via Bytes Detection</a></h4>
<div class="paragraph">
<p>Typically, a network port is associated with a specific protocol.
For example, port <code>80</code> is associated with clear-text HTTP, while port <code>443</code> is associated with encrypted HTTP (that is, the TLS protocol wrapping the HTTP protocol, also known as <code>https</code>).</p>
</div>
<div class="paragraph">
<p>In certain cases, applications need to listen to the same port for two or more protocols, or for different but incompatible versions of the same protocol, which can only be distinguished by reading the initial bytes and figuring out to what protocol they belong to.</p>
</div>
<div class="paragraph">
<p>The Jetty server libraries support this case by placing a <code>DetectorConnectionFactory</code> in front of other <code>ConnectionFactory</code>s.
<code>DetectorConnectionFactory</code> accepts a list of <code>ConnectionFactory</code>s that implement <code>ConnectionFactory.Detecting</code>, which will be called to see if one of them recognizes the initial bytes.</p>
</div>
<div class="paragraph">
<p>In the example below you can see how to support both clear-text and encrypted HTTP/1.1 (i.e. both <code>http</code> and <code>https</code>) <em>on the same network port</em>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Create the HTTP/1.1 ConnectionFactory.</span>
HttpConnectionFactory http = <span class="keyword">new</span> HttpConnectionFactory();
<span class="comment">// Create and configure the TLS context factory.</span>
SslContextFactory.Server sslContextFactory = <span class="keyword">new</span> SslContextFactory.Server();
sslContextFactory.setKeyStorePath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keystore.p12</span><span class="delimiter">&quot;</span></span>);
sslContextFactory.setKeyStorePassword(<span class="string"><span class="delimiter">&quot;</span><span class="content">secret</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Create the TLS ConnectionFactory,</span>
<span class="comment">// setting HTTP/1.1 as the wrapped protocol.</span>
SslConnectionFactory tls = <span class="keyword">new</span> SslConnectionFactory(sslContextFactory, http.getProtocol());
Server server = <span class="keyword">new</span> Server();
<span class="comment">// Create the detector ConnectionFactory to</span>
<span class="comment">// detect whether the initial bytes are TLS.</span>
DetectorConnectionFactory tlsDetector = <span class="keyword">new</span> DetectorConnectionFactory(tls); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="comment">// Create the connector with both ConnectionFactories.</span>
ServerConnector connector = <span class="keyword">new</span> ServerConnector(server, tlsDetector, http); <i class="conum" data-value="2"></i><b>(2)</b>
connector.setPort(<span class="integer">8181</span>);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Creates the <code>DetectorConnectionFactory</code> with the <code>SslConnectionFactory</code> as the only detecting <code>ConnectionFactory</code>.
With this configuration, the detector will delegate to <code>SslConnectionFactory</code> to recognize the initial bytes, which will detect whether the bytes are TLS protocol bytes.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Creates the <code>ServerConnector</code> with <code>DetectorConnectionFactory</code> as the first <code>ConnectionFactory</code>, and <code>HttpConnectionFactory</code> as the next <code>ConnectionFactory</code> to invoke if the detection fails.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In the example above <code>ServerConnector</code> will listen on port 8181.
When a new TCP connection is established, <code>DetectorConnectionFactory</code> is invoked to create a <code>Connection</code>, because it is the first <code>ConnectionFactory</code> specified in the <code>ServerConnector</code> list.
<code>DetectorConnectionFactory</code> reads the initial bytes and asks to its detecting <code>ConnectionFactory</code>s if they recognize the bytes.
In the example above, the detecting <code>ConnectionFactory</code> is <code>SslConnectionFactory</code> which will therefore detect whether the initial bytes are TLS bytes.
If one of the detecting <code>ConnectionFactory</code>s recognizes the bytes, it creates a <code>Connection</code>; otherwise <code>DetectorConnectionFactory</code> will try the next <code>ConnectionFactory</code> after itself in the <code>ServerConnector</code> list.
In the example above, the next <code>ConnectionFactory</code> after <code>DetectorConnectionFactory</code> is <code>HttpConnectionFactory</code>.</p>
</div>
<div class="paragraph">
<p>The final result is that when new TCP connection is established, the initial bytes are examined: if they are TLS bytes, a <code>SslConnectionFactory</code> will create a <code>SslConnection</code> that wraps an <code>HttpConnection</code> as explained <a href="#pg-server-io-arch-connection-factory-wrapping">here</a>, therefore supporting <code>https</code>; otherwise they are not TLS bytes and an <code>HttpConnection</code> is created, therefore supporting <code>http</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-server-io-arch-connection-factory-custom"><a class="anchor" href="#pg-server-io-arch-connection-factory-custom"></a><a class="link" href="#pg-server-io-arch-connection-factory-custom">Writing a Custom <code>ConnectionFactory</code></a></h4>
<div class="paragraph">
<p>This section explains how to use the Jetty server-side libraries to write a generic network server able to parse and generate any protocol based on TCP.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s suppose that we want to write a custom protocol that is based on JSON but has the same semantic as HTTP; let&#8217;s call this custom protocol <code>JSONHTTP</code>, so that a request would look like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="json">{
<span class="key"><span class="delimiter">&quot;</span><span class="content">type</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">request</span><span class="delimiter">&quot;</span></span>,
<span class="key"><span class="delimiter">&quot;</span><span class="content">method</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">GET</span><span class="delimiter">&quot;</span></span>,
<span class="key"><span class="delimiter">&quot;</span><span class="content">version</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">HTTP/1.1</span><span class="delimiter">&quot;</span></span>,
<span class="key"><span class="delimiter">&quot;</span><span class="content">uri</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">http://localhost/path</span><span class="delimiter">&quot;</span></span>,
<span class="key"><span class="delimiter">&quot;</span><span class="content">fields</span><span class="delimiter">&quot;</span></span>: {
<span class="key"><span class="delimiter">&quot;</span><span class="content">content-type</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">text/plain;charset=ASCII</span><span class="delimiter">&quot;</span></span>
},
<span class="key"><span class="delimiter">&quot;</span><span class="content">content</span><span class="delimiter">&quot;</span></span>: <span class="string"><span class="delimiter">&quot;</span><span class="content">HELLO</span><span class="delimiter">&quot;</span></span>
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In order to implement this custom protocol, we need to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>implement a <code>JSONHTTPConnectionFactory</code></p>
</li>
<li>
<p>implement a <code>JSONHTTPConnection</code></p>
</li>
<li>
<p>parse bytes and generate bytes in the <code>JSONHTTP</code> format</p>
</li>
<li>
<p>design an easy to use API that applications use to process requests and respond</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>First, the <code>JSONHTTPConnectionFactory</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">JSONHTTPConnectionFactory</span> <span class="directive">extends</span> AbstractConnectionFactory
{
<span class="directive">public</span> JSONHTTPConnectionFactory()
{
<span class="local-variable">super</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">JSONHTTP</span><span class="delimiter">&quot;</span></span>);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Connection</span> newConnection(Connector connector, EndPoint endPoint)
{
JSONHTTPConnection connection = <span class="keyword">new</span> JSONHTTPConnection(endPoint, connector.getExecutor());
<span class="comment">// Call configure() to apply configurations common to all connections.</span>
<span class="keyword">return</span> configure(connection, connector, endPoint);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note how <code>JSONHTTPConnectionFactory</code> extends <code>AbstractConnectionFactory</code> to inherit facilities common to all <code>ConnectionFactory</code> implementations.</p>
</div>
<div class="paragraph">
<p>Second, the <code>JSONHTTPConnection</code>.
Recall from the <a href="#pg-arch-io-echo">echo <code>Connection</code> example</a> that you need to override <code>onOpen()</code> to call <code>fillInterested()</code> so that the Jetty I/O system will notify your <code>Connection</code> implementation when there are bytes to read by calling <code>onFillable()</code>.
Furthermore, because the Jetty libraries are non-blocking and asynchronous, you need to use <code>IteratingCallback</code> to implement <code>onFillable()</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">JSONHTTPConnection</span> <span class="directive">extends</span> AbstractConnection
{
<span class="comment">// The asynchronous JSON parser.</span>
<span class="directive">private</span> <span class="directive">final</span> AsyncJSON parser = <span class="keyword">new</span> AsyncJSON.Factory().newAsyncJSON();
<span class="directive">private</span> <span class="directive">final</span> IteratingCallback callback = <span class="keyword">new</span> JSONHTTPIteratingCallback();
<span class="directive">public</span> JSONHTTPConnection(EndPoint endPoint, <span class="predefined-type">Executor</span> executor)
{
<span class="local-variable">super</span>(endPoint, executor);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onOpen()
{
<span class="local-variable">super</span>.onOpen();
<span class="comment">// Declare interest in being called back when</span>
<span class="comment">// there are bytes to read from the network.</span>
fillInterested();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onFillable()
{
callback.iterate();
}
<span class="directive">private</span> <span class="type">class</span> <span class="class">JSONHTTPIteratingCallback</span> <span class="directive">extends</span> IteratingCallback
{
<span class="directive">private</span> <span class="predefined-type">ByteBuffer</span> buffer;
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="predefined-type">Action</span> process() <span class="directive">throws</span> <span class="predefined-type">Throwable</span>
{
<span class="keyword">if</span> (buffer == <span class="predefined-constant">null</span>)
buffer = BufferUtil.allocate(getInputBufferSize(), <span class="predefined-constant">true</span>);
<span class="keyword">while</span> (<span class="predefined-constant">true</span>)
{
<span class="type">int</span> filled = getEndPoint().fill(buffer);
<span class="keyword">if</span> (filled &gt; <span class="integer">0</span>)
{
<span class="type">boolean</span> parsed = parser.parse(buffer);
<span class="keyword">if</span> (parsed)
{
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; request = parser.complete();
<span class="comment">// Allow applications to process the request.</span>
invokeApplication(request, <span class="local-variable">this</span>);
<span class="comment">// Signal that the iteration should resume when</span>
<span class="comment">// the application completed the request processing.</span>
<span class="keyword">return</span> <span class="predefined-type">Action</span>.SCHEDULED;
}
<span class="keyword">else</span>
{
<span class="comment">// Did not receive enough JSON bytes,</span>
<span class="comment">// loop around to try to read more.</span>
}
}
<span class="keyword">else</span> <span class="keyword">if</span> (filled == <span class="integer">0</span>)
{
<span class="comment">// We don't need the buffer anymore, so</span>
<span class="comment">// don't keep it around while we are idle.</span>
buffer = <span class="predefined-constant">null</span>;
<span class="comment">// No more bytes to read, declare</span>
<span class="comment">// again interest for fill events.</span>
fillInterested();
<span class="comment">// Signal that the iteration is now IDLE.</span>
<span class="keyword">return</span> <span class="predefined-type">Action</span>.IDLE;
}
<span class="keyword">else</span>
{
<span class="comment">// The other peer closed the connection,</span>
<span class="comment">// the iteration completed successfully.</span>
<span class="keyword">return</span> <span class="predefined-type">Action</span>.SUCCEEDED;
}
}
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> onCompleteSuccess()
{
getEndPoint().close();
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> onCompleteFailure(<span class="predefined-type">Throwable</span> cause)
{
getEndPoint().close(cause);
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Again, note how <code>JSONHTTPConnection</code> extends <code>AbstractConnection</code> to inherit facilities that you would otherwise need to re-implement from scratch.</p>
</div>
<div class="paragraph">
<p>When <code>JSONHTTPConnection</code> receives a full JSON object it calls <code>invokeApplication(&#8230;&#8203;)</code> to allow the application to process the incoming request and produce a response.</p>
</div>
<div class="paragraph">
<p>At this point you need to design a non-blocking asynchronous API that takes a <code>Callback</code> parameter so that applications can signal to the implementation when the request processing is complete (either successfully or with a failure).</p>
</div>
<div class="paragraph">
<p>A simple example of this API design could be the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Wrap the JSON <code>Map</code> into a <code>JSONHTTPRequest</code> parameter so that applications may use more specific HTTP APIs such as <code>JSONHTTPRequest.getMethod()</code> rather than a generic <code>Map.get("method")</code></p>
</li>
<li>
<p>Provide an equivalent <code>JSONHTTPResponse</code> parameter so that applications may use more specific APIs such as <code>JSONHTTPResponse.setStatus(int)</code> rather than a generic <code>Map.put("status", 200)</code></p>
</li>
<li>
<p>Provide a <code>Callback</code> (or a <code>CompletableFuture</code>) parameter so that applications may indicate when the request processing is complete</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This results in the following API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">JSONHTTPRequest</span>
{
<span class="comment">// Request APIs</span>
}
<span class="type">class</span> <span class="class">JSONHTTPResponse</span>
{
<span class="comment">// Response APIs</span>
}
<span class="type">interface</span> <span class="class">JSONHTTPService</span>
{
<span class="type">void</span> service(JSONHTTPRequest request, JSONHTTPResponse response, <span class="predefined-type">Callback</span> callback);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The important part of this simple API example is the <code>Callback</code> parameter that makes the API non-blocking and asynchronous.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="maven-and-jetty"><a class="anchor" href="#maven-and-jetty"></a><a class="link" href="#maven-and-jetty">Maven and Jetty</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="jetty-maven-helloworld"><a class="anchor" href="#jetty-maven-helloworld"></a><a class="link" href="#jetty-maven-helloworld">Using Maven</a></h3>
<div class="paragraph">
<p><a href="http://maven.apache.org/">Apache Maven</a> is a software project management and comprehension tool.
Based on the concept of a project object model (POM), Maven can manage a project&#8217;s build, reporting and documentation from a central piece of information.</p>
</div>
<div class="paragraph">
<p>It is an ideal tool to build a web application project, and such projects can use the <a href="#jetty-maven-plugin">jetty-maven-plugin</a> to easily run the web application and save time in development.
You can also use Maven to build, test and run a project which embeds Jetty.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Use of Maven and the jetty-maven-plugin is <strong>not</strong> required.
Using Maven for Jetty implementations is a popular choice, but users encouraged to manage their projects in whatever way suits their needs.
Other popular tools include Ant and Gradle.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>First we&#8217;ll have a look at a very simple HelloWorld java application that embeds Jetty, then a simple webapp which makes use of the <a href="#jetty-maven-plugin">jetty-maven-plugin</a> to speed up the development cycle.</p>
</div>
<div class="sect3">
<h4 id="configuring-embedded-jetty-with-maven"><a class="anchor" href="#configuring-embedded-jetty-with-maven"></a><a class="link" href="#configuring-embedded-jetty-with-maven">Using Embedded Jetty with Maven</a></h4>
<div class="paragraph">
<p>To understand the basic operations of building and running against Jetty, first review:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#advanced-embedding">Embedding with Jetty</a></p>
</li>
<li>
<p><a href="#jetty-helloworld">Jetty HelloWorld example</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Maven uses convention over configuration, so it is best to use the project structure Maven recommends.
You can use <em><a href="#archetypes"><a href="http://maven.apache.org/guides/introduction/introduction-to-archetypes.html">archetypes</a></a></em> to quickly setup Maven projects, but we will set up the structure manually for this simple tutorial example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; mkdir JettyMavenHelloWorld
&gt; cd JettyMavenHelloWorld
&gt; mkdir -p src/main/java/org/example</pre>
</div>
</div>
<div class="sect4">
<h5 id="creating-helloworld-class"><a class="anchor" href="#creating-helloworld-class"></a><a class="link" href="#creating-helloworld-class">Creating the HelloWorld Class</a></h5>
<div class="paragraph">
<p>Use an editor to create the file <code>src/main/java/org/example/HelloWorld.java</code> with the following contents:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">org.example</span>;
<span class="keyword">import</span> <span class="include">javax.servlet.http.HttpServletRequest</span>;
<span class="keyword">import</span> <span class="include">javax.servlet.http.HttpServletResponse</span>;
<span class="keyword">import</span> <span class="include">javax.servlet.ServletException</span>;
<span class="keyword">import</span> <span class="include">java.io.IOException</span>;
<span class="keyword">import</span> <span class="include">org.eclipse.jetty.server.Server</span>;
<span class="keyword">import</span> <span class="include">org.eclipse.jetty.server.Request</span>;
<span class="keyword">import</span> <span class="include">org.eclipse.jetty.server.handler.AbstractHandler</span>;
<span class="directive">public</span> <span class="type">class</span> <span class="class">HelloWorld</span> <span class="directive">extends</span> AbstractHandler
{
<span class="directive">public</span> <span class="type">void</span> handle(<span class="predefined-type">String</span> target,
Request baseRequest,
HttpServletRequest request,
HttpServletResponse response)
<span class="directive">throws</span> <span class="exception">IOException</span>, ServletException
{
response.setContentType(<span class="string"><span class="delimiter">&quot;</span><span class="content">text/html;charset=utf-8</span><span class="delimiter">&quot;</span></span>);
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(<span class="predefined-constant">true</span>);
response.getWriter().println(<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;h1&gt;Hello World&lt;/h1&gt;</span><span class="delimiter">&quot;</span></span>);
}
<span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> args) <span class="directive">throws</span> <span class="exception">Exception</span>
{
Server server = <span class="keyword">new</span> Server(<span class="integer">8080</span>);
server.setHandler(<span class="keyword">new</span> HelloWorld());
server.start();
server.join();
}
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="creating-embedded-pom-descriptor"><a class="anchor" href="#creating-embedded-pom-descriptor"></a><a class="link" href="#creating-embedded-pom-descriptor">Creating the POM Descriptor</a></h5>
<div class="paragraph">
<p>The <code>pom.xml</code> file declares the project name and its dependencies.
Use an editor to create the file <code>pom.xml</code> in the <code>JettyMavenHelloWorld</code> directory with the following contents:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;project</span> <span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://maven.apache.org/POM/4.0.0</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">xmlns:xsi</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://www.w3.org/2001/XMLSchema-instance</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">xsi:schemaLocation</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;modelVersion&gt;</span>4.0.0<span class="tag">&lt;/modelVersion&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.example<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>hello-world<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>0.1-SNAPSHOT<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;packaging&gt;</span>jar<span class="tag">&lt;/packaging&gt;</span>
<span class="tag">&lt;name&gt;</span>Jetty HelloWorld<span class="tag">&lt;/name&gt;</span>
<span class="tag">&lt;properties&gt;</span>
<span class="comment">&lt;!-- Adapt this to a version found on
https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-maven-plugin/
--&gt;</span>
<span class="tag">&lt;jettyVersion&gt;</span>{VERSION}<span class="tag">&lt;/jettyVersion&gt;</span>
<span class="tag">&lt;/properties&gt;</span>
<span class="tag">&lt;dependencies&gt;</span>
<span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-server<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>${jettyVersion}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span>
<span class="tag">&lt;/dependencies&gt;</span>
<span class="tag">&lt;build&gt;</span>
<span class="tag">&lt;plugins&gt;</span>
<span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.codehaus.mojo<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>exec-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>1.1<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;executions&gt;</span>
<span class="tag">&lt;execution&gt;</span><span class="tag">&lt;goals&gt;</span><span class="tag">&lt;goal&gt;</span>java<span class="tag">&lt;/goal&gt;</span><span class="tag">&lt;/goals&gt;</span><span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;/executions&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;mainClass&gt;</span>org.example.HelloWorld<span class="tag">&lt;/mainClass&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span>
<span class="tag">&lt;/plugins&gt;</span>
<span class="tag">&lt;/build&gt;</span>
<span class="tag">&lt;/project&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="buildng-and-running-embedded-helloworld"><a class="anchor" href="#buildng-and-running-embedded-helloworld"></a><a class="link" href="#buildng-and-running-embedded-helloworld">Building and Running Embedded HelloWorld</a></h5>
<div class="paragraph">
<p>You can now compile and execute the HelloWorld class by using these commands:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; mvn clean compile exec:java</pre>
</div>
</div>
<div class="paragraph">
<p>You can point your browser to <code><a href="http://localhost:8080" class="bare">http://localhost:8080</a></code> to see the <em>Hello World</em> page.
You can observe what Maven is doing for you behind the scenes by using the <code>mvn dependency:tree</code> command, which reveals the transitive dependency resolved and downloaded as:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; mvn dependency:tree
[INFO] Scanning for projects...
...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Jetty HelloWorld 0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ hello-world ---
...
[INFO] org.example:hello-world:jar:0.1-SNAPSHOT
[INFO] \- org.eclipse.jetty:jetty-server:jar:9.3.9.v20160517:compile
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:compile
[INFO] +- org.eclipse.jetty:jetty-http:jar:9.3.9.v20160517:compile
[INFO] | \- org.eclipse.jetty:jetty-util:jar:9.3.9.v20160517:compile
[INFO] \- org.eclipse.jetty:jetty-io:jar:9.3.9.v20160517:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.145 s
[INFO] Finished at: 2016-08-01T13:46:42-04:00
[INFO] Final Memory: 15M/209M
[INFO] ------------------------------------------------------------------------</pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="developing-standard-webapp-with-jetty-and-maven"><a class="anchor" href="#developing-standard-webapp-with-jetty-and-maven"></a><a class="link" href="#developing-standard-webapp-with-jetty-and-maven">Developing a Standard WebApp with Jetty and Maven</a></h4>
<div class="paragraph">
<p>The previous section demonstrated how to use Maven with an application that embeds Jetty.
Now we will examine instead how to develop a standard webapp with Maven and Jetty.
First create the Maven structure (you can use the maven webapp archetype instead if you prefer):</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; mkdir JettyMavenHelloWarApp
&gt; cd JettyMavenHelloWebApp
&gt; mkdir -p src/main/java/org/example
&gt; mkdir -p src/main/webapp/WEB-INF</pre>
</div>
</div>
<div class="sect4">
<h5 id="creating-servlet"><a class="anchor" href="#creating-servlet"></a><a class="link" href="#creating-servlet">Creating a Servlet</a></h5>
<div class="paragraph">
<p>Use an editor to create the file <code>src/main/java/org/example/HelloServlet.java</code> with the following contents:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">org.example</span>;
<span class="keyword">import</span> <span class="include">java.io.IOException</span>;
<span class="keyword">import</span> <span class="include">javax.servlet.ServletException</span>;
<span class="keyword">import</span> <span class="include">javax.servlet.http.HttpServlet</span>;
<span class="keyword">import</span> <span class="include">javax.servlet.http.HttpServletRequest</span>;
<span class="keyword">import</span> <span class="include">javax.servlet.http.HttpServletResponse</span>;
<span class="directive">public</span> <span class="type">class</span> <span class="class">HelloServlet</span> <span class="directive">extends</span> HttpServlet
{
<span class="directive">protected</span> <span class="type">void</span> doGet(HttpServletRequest request, HttpServletResponse response) <span class="directive">throws</span> ServletException, <span class="exception">IOException</span>
{
response.setContentType(<span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>);
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println(<span class="string"><span class="delimiter">&quot;</span><span class="content">&lt;h1&gt;Hello Servlet&lt;/h1&gt;</span><span class="delimiter">&quot;</span></span>);
response.getWriter().println(<span class="string"><span class="delimiter">&quot;</span><span class="content">session=</span><span class="delimiter">&quot;</span></span> + request.getSession(<span class="predefined-constant">true</span>).getId());
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You need to declare this servlet in the deployment descriptor, so create the file <code>src/main/webapp/WEB-INF/web.xml</code> and add the following contents:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span>
<span class="tag">&lt;web-app</span>
<span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://xmlns.jcp.org/xml/ns/javaee</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">xmlns:xsi</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://www.w3.org/2001/XMLSchema-instance</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">xsi:schemaLocation</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">metadata-complete</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">false</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">version</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">3.1</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;servlet&gt;</span>
<span class="tag">&lt;servlet-name&gt;</span>Hello<span class="tag">&lt;/servlet-name&gt;</span>
<span class="tag">&lt;servlet-class&gt;</span>org.example.HelloServlet<span class="tag">&lt;/servlet-class&gt;</span>
<span class="tag">&lt;/servlet&gt;</span>
<span class="tag">&lt;servlet-mapping&gt;</span>
<span class="tag">&lt;servlet-name&gt;</span>Hello<span class="tag">&lt;/servlet-name&gt;</span>
<span class="tag">&lt;url-pattern&gt;</span>/hello/*<span class="tag">&lt;/url-pattern&gt;</span>
<span class="tag">&lt;/servlet-mapping&gt;</span>
<span class="tag">&lt;/web-app&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="creating-plugin-pom-descriptor"><a class="anchor" href="#creating-plugin-pom-descriptor"></a><a class="link" href="#creating-plugin-pom-descriptor">Creating the POM Descriptor</a></h5>
<div class="paragraph">
<p>The <code>pom.xml</code> file declares the project name and its dependencies.
Use an editor to create the file <code>pom.xml</code> with the following contents in the <code>JettyMavenHelloWarApp</code> directory, noting particularly the declaration of the <a href="#jetty-maven-plugin">jetty-maven-plugin</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;project</span> <span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://maven.apache.org/POM/4.0.0</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">xmlns:xsi</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://www.w3.org/2001/XMLSchema-instance</span><span class="delimiter">&quot;</span></span>
<span class="attribute-name">xsi:schemaLocation</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;modelVersion&gt;</span>4.0.0<span class="tag">&lt;/modelVersion&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.example<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>hello-world<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>0.1-SNAPSHOT<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;packaging&gt;</span>war<span class="tag">&lt;/packaging&gt;</span>
<span class="tag">&lt;name&gt;</span>Jetty HelloWorld WebApp<span class="tag">&lt;/name&gt;</span>
<span class="tag">&lt;properties&gt;</span>
<span class="tag">&lt;jettyVersion&gt;</span>{VERSION}<span class="tag">&lt;/jettyVersion&gt;</span>
<span class="tag">&lt;/properties&gt;</span>
<span class="tag">&lt;dependencies&gt;</span>
<span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>javax.servlet<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>javax.servlet-api<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>3.1.0<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;scope&gt;</span>provided<span class="tag">&lt;/scope&gt;</span>
<span class="tag">&lt;/dependency&gt;</span>
<span class="tag">&lt;/dependencies&gt;</span>
<span class="tag">&lt;build&gt;</span>
<span class="tag">&lt;plugins&gt;</span>
<span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>${jettyVersion}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/plugin&gt;</span>
<span class="tag">&lt;/plugins&gt;</span>
<span class="tag">&lt;/build&gt;</span>
<span class="tag">&lt;/project&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="building-and-running-web-application"><a class="anchor" href="#building-and-running-web-application"></a><a class="link" href="#building-and-running-web-application">Building and Running the Web Application</a></h5>
<div class="paragraph">
<p>Now you can both build and run the web application without needing to assemble it into a war by using the <a href="#jetty-maven-plugin">jetty-maven-plugin</a> via the command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; mvn jetty:run</pre>
</div>
</div>
<div class="paragraph">
<p>You can see the static and dynamic content at <code><a href="http://localhost:8080/hello" class="bare">http://localhost:8080/hello</a></code></p>
</div>
<div class="paragraph">
<p>There are a great deal of configuration options available for the jetty-maven-plugin to help you build and run your webapp.
The full reference is at <a href="#jetty-maven-plugin">Configuring the Jetty Maven Plugin</a>.</p>
</div>
</div>
<div class="sect4">
<h5 id="building-war-file"><a class="anchor" href="#building-war-file"></a><a class="link" href="#building-war-file">Building a WAR file</a></h5>
<div class="paragraph">
<p>You can create a Web Application Archive (WAR) file from the project with the command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&gt; mvn package</pre>
</div>
</div>
<div class="paragraph">
<p>The resulting war file is in the <code>target</code> directory and may be deployed on any standard servlet server, including <a href="#configuring-deployment">Jetty</a>.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="jetty-maven-plugin"><a class="anchor" href="#jetty-maven-plugin"></a><a class="link" href="#jetty-maven-plugin">Using the Jetty Maven Plugin</a></h3>
<div class="paragraph">
<p>The Jetty Maven plugin is useful for rapid development and testing.
It can optionally periodically scan your project for changes and automatically redeploy the webapp if any are found.
This makes the development cycle more productive by eliminating the build and deploy steps: you use your IDE to make changes to the project, and the running web container automatically picks them up, allowing you to test them straight away.</p>
</div>
<div class="paragraph">
<p>The plugin has been substantially re-architected in jetty-10 to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>have less goals</p>
</li>
<li>
<p>make deployment modes (embedded, forked or to a jetty distribution) apply uniformly across all goals</p>
</li>
<li>
<p>simplify configuration options</p>
</li>
<li>
<p>make the purpose and operation of each goal clearer</p>
</li>
<li>
<p>rearchitect with composition rather than inheritance to make future extensions easier</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>There are now only 4 goals to run a webapp in jetty:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#jetty-run-goal">jetty:run</a></p>
</li>
<li>
<p><a href="#jetty-run-war-goal">jetty:run-war</a></p>
</li>
<li>
<p><a href="#jetty-start-goal">jetty:start</a></p>
</li>
<li>
<p><a href="#jetty-start-war-goal">jetty:start-war</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Plus two utility goals:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#jetty-stop-goal">jetty:stop</a></p>
</li>
<li>
<p><a href="#jetty-effective-web-xml-goal">jetty:effective-web-xml</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>jetty:run</code> and <code>jetty:start</code> are alike in that they both run an unassembled webapp in jetty,however <code>jetty:run</code> is designed to be used at the command line, whereas <code>jetty:start</code> is specifically designed to be bound to execution phases in the build lifecycle.
<code>jetty:run</code> will pause maven while jetty is running, echoing all output to the console, and then stop maven when jetty exits.
<code>jetty:start</code> will not pause maven, will write all its output to a file, and will not stop maven when jetty exits.</p>
</div>
<div class="paragraph">
<p><code>jetty:run-war</code> and <code>jetty:start-war</code> are similar in that they both run an <em>assembled</em> war file in jetty.
However, <code>jetty:run-war</code> is designed to be run at the command line, whereas <code>jetty:start-war</code> is specifically designed to be bound to execution phases in the build lifecycle.
<code>jetty:run-war</code> will pause maven while jetty is running, echoing all output to the console, and then stop maven when jetty exits.
<code>jetty:start-war</code> will not not pause maven, will write all its output to a file, and will not stop maven when jetty exits.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>While the Jetty Maven Plugin can be very useful for development we do not recommend its use in a <em>production capacity</em>.
In order for the plugin to work it needs to leverage many internal Maven apis and Maven itself it not a production deployment tool.
We recommend either the traditional <a href="{DISTGUIDE}">distribution</a> deployment approach or using <a href="#advanced-embedding">embedded Jetty</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="get-up-and-running"><a class="anchor" href="#get-up-and-running"></a><a class="link" href="#get-up-and-running">Get Up and Running</a></h4>
<div class="paragraph">
<p>First, add <code>jetty-maven-plugin</code> to your <code>pom.xml</code> definition:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then, from the same directory as your root <code>pom.xml</code>, type:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>mvn jetty:run</pre>
</div>
</div>
<div class="paragraph">
<p>This starts Jetty and serves up your project on <a href="http://localhost:8080/" class="bare">http://localhost:8080/</a>.</p>
</div>
<div class="paragraph">
<p>Jetty will continue to run until you stop it.
By default, it will not automatically restart your webapp.
Set a non-zero <code>&lt;scan&gt;</code> value to have jetty scan your webapp for changes and automatically redeploy, or set <code>&lt;scan&gt;</code> to <code>0</code> to cause manual redeployment by hitting the <kbd>Enter</kbd> key.</p>
</div>
<div class="paragraph">
<p>You can terminate the plugin with a <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>c</kbd></span> in the terminal window where it is running.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The classpath of the running Jetty instance and its deployed webapp are managed by Maven, and may not be exactly what you expect.
For example: a webapp&#8217;s dependent jars might be referenced via the local repository, or other projects in the reactor, not the <code>WEB-INF/lib</code> directory.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="supported-goals"><a class="anchor" href="#supported-goals"></a><a class="link" href="#supported-goals">Supported Goals</a></h4>
<div class="paragraph">
<p>The goals prefixed with <code>"run"</code> are designed to be used at the <em>command line</em>.
They first run a maven build on your project to ensure at least the classes are all built.
They then start jetty and pause the maven build process until jetty is manually terminated, at which time the build will also be terminated.
Jetty can scan various files in your project for changes and redeploy the webapp as necessary, or you can choose to manually trigger a redeploy if you prefer.
All output from jetty is echoed to the console.</p>
</div>
<div class="paragraph">
<p>The goals prefixed with <code>"start"</code> are designed to be used with <em>build lifecycle bindings in the pom</em>, and <em>not</em> at the command line.
No part of your project will be rebuilt by invoking these goals - you should ensure that your bind the execution to a build phase where all necessary parts of your project have been built.
Maven will start and terminate jetty at the appropriate points in the build lifecycle, continuing with the build.
Jetty will <em>not</em> scan any files in your project for changes, and your webapp will <em>not</em> be redeployed either automatically or manually.
Output from jetty is directed to a file in the <code>target</code> directory.</p>
</div>
<div class="paragraph">
<p>To see a list of all goals supported by the Jetty Maven plugin, do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>mvn jetty:help</pre>
</div>
</div>
<div class="paragraph">
<p>To see the detailed list of parameters that can be configured for a particular goal, in addition to its description, do:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>mvn jetty:help -Ddetail=true -Dgoal= &lt;goal name&gt;</pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="deployment-modes"><a class="anchor" href="#deployment-modes"></a><a class="link" href="#deployment-modes">Deployment Modes</a></h4>
<div class="paragraph">
<p>All of the <code>"run"</code> and <code>"start"</code> goals can deploy your webapp either into the running maven process, or forked into a new child process, or forked into a jetty distribution on disk.</p>
</div>
<div class="paragraph">
<p>This is controlled by setting the <code>deployMode</code> configuration parameter in the pom, but can also be set by defining the maven property 'jetty.deployMode'.</p>
</div>
<div class="sect4">
<h5 id="pg-embedded"><a class="anchor" href="#pg-embedded"></a><a class="link" href="#pg-embedded">Embedded</a></h5>
<div class="paragraph">
<p><code>deployMode</code> of <code>EMBED</code>.
This is the "classic" jetty maven plugin deployment mode, running in-process with maven.
This is the <em>default</em> mode.</p>
</div>
<div class="paragraph">
<p>These extra configuration parameters are available:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">httpConnector</dt>
<dd>
<p>Optional.
NOTE to configure a https connector, you will need to use xml configuration files instead, setting the <code>jettyXmls</code> parameter.
This parameter can only be used to configure a standard http connector.
If not specified, Jetty will create a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/ServerConnector.html">ServerConnector</a> instance listening on port 8080.
You can change this default port number by using the system property <code>jetty.http.port</code> on the command line, for example, <code>mvn -Djetty.http.port=9999 jetty:run</code>.
Alternatively, you can use this configuration element to set up the information for the ServerConnector.
The following are the valid configuration sub-elements:</p>
<div class="dlist">
<dl>
<dt class="hdlist1">port</dt>
<dd>
<p>The port number for the connector to listen on.
By default it is 8080.</p>
</dd>
<dt class="hdlist1">host</dt>
<dd>
<p>The particular interface for the connector to listen on.
By default, all interfaces.</p>
</dd>
<dt class="hdlist1">name</dt>
<dd>
<p>The name of the connector, which is useful for <a href="#serving-webapp-from-particular-port">configuring contexts to respond only on particular connectors</a>.</p>
</dd>
<dt class="hdlist1">idleTimeout</dt>
<dd>
<p>Maximum idle time for a connection.
You could instead configure the connectors in a standard <a href="#jetty-xml-config">jetty xml config file</a> and put its location into the <code>jettyXml</code> parameter.
Note that since Jetty 9.0 it is no longer possible to configure a <a href="#maven-config-https">https connector</a> directly in the pom.xml: you need to <a href="#maven-config-https">use jetty xml config files to do it</a>.</p>
</dd>
</dl>
</div>
</dd>
<dt class="hdlist1">loginServices</dt>
<dd>
<p>Optional.
A list of <code>org.eclipse.jetty.security.LoginService</code> implementations. Note that there is no default realm.
If you use a realm in your <code>web.xml</code> you can specify a corresponding realm here.
You could instead configure the login services in a jetty xml file and add its location to the <code>jettyXml</code> parameter.
See <a href="#configuring-security-settings">Configuring Security</a>.</p>
</dd>
<dt class="hdlist1">requestLog</dt>
<dd>
<p>Optional.
An implementation of the <code>org.eclipse.jetty.server.RequestLog</code> request log interface.
An implementation that respects the NCSA format is available as <code>org.eclipse.jetty.server.NCSARequestLog</code>.
There are three other ways to configure the RequestLog:</p>
<div class="ulist">
<ul>
<li>
<p>In a jetty xml config file, as specified in the <code>jettyXml</code> parameter.</p>
</li>
<li>
<p>In a context xml config file, as specified in the <code>contextXml</code> parameter.</p>
</li>
<li>
<p>In the <code>webApp</code> element.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>See <a href="#configuring-jetty-request-logs">Configuring Request Logs</a> for more information.</p>
</div>
</dd>
<dt class="hdlist1">server</dt>
<dd>
<p>Optional as of Jetty 9.3.1.
This would configure an instance of the <a href="https://github.com/eclipse/jetty.project/tree/master/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java"><code>org.eclipse.jetty.server.Server</code></a> for the plugin to use, however it is usually <em>not</em> necessary to configure this, as the plugin will automatically configure one for you.
In particular, if you use the <code>jettyXmls</code> element, then you generally <em>don&#8217;t</em> want to define this element, as you are probably using the <code>jettyXmls</code> file/s to configure up a Server with a special constructor argument, such as a custom threadpool.
If you define both a <code>server</code> element and use a <code>jettyXmls</code> element which points to a config file that has a line like <code>&lt;Configure id="Server" class="org.eclipse.jetty.server.Server"&gt;</code> then the the xml configuration will override what you configure for the <code>server</code> in the <code>pom.xml</code>.</p>
</dd>
<dt class="hdlist1">useProvidedScope</dt>
<dd>
<p>Default value is <code>false</code>.
If true, the dependencies with <code>&lt;scope&gt;provided&lt;/scope&gt;</code> are placed onto the <em>container classpath</em>.
Be aware that this is <em>not</em> the webapp classpath, as <code>provided</code> indicates that these dependencies would normally be expected to be provided by the container.
You should very rarely ever need to use this.
See <a href="#container-classpath">Container Classpath vs WebApp Classpath</a>.</p>
</dd>
</dl>
</div>
</div>
<div class="sect4">
<h5 id="pg-forked"><a class="anchor" href="#pg-forked"></a><a class="link" href="#pg-forked">Forked</a></h5>
<div class="paragraph">
<p><code>deployMode</code> of <code>FORK</code>.
This is similar to the old "jetty:run-forked" goal - a separate process is forked to run your webapp embedded into jetty.
These extra configuration parameters are available:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">env</dt>
<dd>
<p>Optional.
Map of key/value pairs to pass as environment to the forked JVM.</p>
</dd>
<dt class="hdlist1">jvmArgs</dt>
<dd>
<p>Optional.
A space separated string representing arbitrary arguments to pass to the forked JVM.</p>
</dd>
<dt class="hdlist1">forkWebXml</dt>
<dd>
<p>Optional.
Defaults to <code>target/fork-web.xml</code>.
This is the location of a quickstart web xml file that will be <em>generated</em> during the forking of the jetty process.
You should not need to set this parameter, but it is available if you wish to control the name and location of that file.</p>
</dd>
<dt class="hdlist1">useProvidedScope</dt>
<dd>
<p>Default value is <code>false</code>.
If true, the dependencies with <code>&lt;scope&gt;provided&lt;/scope&gt;</code> are placed onto the <em>container classpath</em>.
Be aware that this is NOT the webapp classpath, as "provided" indicates that these dependencies would normally be expected to be provided by the container.
You should very rarely ever need to use this.
See <a href="#container-classpath">Container Classpath vs WebApp Classpath</a>.</p>
</dd>
</dl>
</div>
</div>
<div class="sect4">
<h5 id="pg-in-a-jetty-distribution"><a class="anchor" href="#pg-in-a-jetty-distribution"></a><a class="link" href="#pg-in-a-jetty-distribution">In a jetty distribution</a></h5>
<div class="paragraph">
<p><code>deployMode</code> of <code>EXTERNAL</code>.
This is similar to the old "jetty:run-distro" goal - your webapp is deployed into a dynamically downloaded, unpacked and configured jetty distribution.
A separate process is forked to run it.
These extra configuration parameters are available:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">jettyBase</dt>
<dd>
<p>Optional.
The location of an existing jetty base directory to use to deploy the webapp.
The existing base will be copied to the <code>target/</code> directory before the webapp is deployed.
If there is no existing jetty base, a fresh one will be made in <code>target/jetty-base</code>.</p>
</dd>
<dt class="hdlist1">jettyHome</dt>
<dd>
<p>Optional.
The location of an existing unpacked jetty distribution.
If one does not exist, a fresh jetty distribution will be downloaded from maven and installed to the <code>target</code> directory.</p>
</dd>
<dt class="hdlist1">jettyOptions</dt>
<dd>
<p>Optional.
A space separated string representing extra arguments to the synthesized jetty command line.
Values for these arguments can be found in the section titled "Options" in the output of <code>java -jar $jetty.home/start.jar --help</code>.</p>
</dd>
<dt class="hdlist1">jvmArgs</dt>
<dd>
<p>Optional.
A space separated string representing arguments that should be passed to the jvm of the child process running the distro.</p>
</dd>
<dt class="hdlist1">modules</dt>
<dd>
<p>Optional.
An array of names of additional jetty modules that the jetty child process will activate.
Use this to change the <a href="#container-classpath">container classpath</a> instead of <code>useProvidedScope</code>.
These modules are enabled by default: <code>server,http,webapp,deploy</code>.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect3">
<h4 id="common-configuration"><a class="anchor" href="#common-configuration"></a><a class="link" href="#common-configuration">Common Configuration</a></h4>
<div class="paragraph">
<p>The following configuration parameters are common to all of the <code>"run-"</code> and <code>"start-"</code> goals:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">deployMode</dt>
<dd>
<p>One of <code>EMBED</code>, <code>FORK</code> or <code>EXTERNAL</code>.
Default <code>EMBED</code>.
Can also be configured by setting the Maven property <code>jetty.deployMode</code>.
This parameter determines whether the webapp will run in jetty in-process with Maven, forked into a new process, or deployed into a jetty distribution.
See <a href="#deployment-modes">Deployment Modes</a>.</p>
</dd>
<dt class="hdlist1">jettyXmls</dt>
<dd>
<p>Optional.
A comma separated list of locations of jetty xml files to apply in addition to any plugin configuration parameters.
You might use it if you have other webapps, handlers, specific types of connectors etc., to deploy, or if you have other Jetty objects that you cannot configure from the plugin.</p>
</dd>
<dt class="hdlist1">skip</dt>
<dd>
<p>Default is false.
If true, the execution of the plugin exits.
Same as setting the SystemProperty <code>-Djetty.skip</code> on the command line.
This is most useful when configuring Jetty for execution during integration testing and you want to skip the tests.</p>
</dd>
<dt class="hdlist1">excludedGoals</dt>
<dd>
<p>Optional.
A list of Jetty plugin goal names that will cause the plugin to print an informative message and exit.
Useful if you want to prevent users from executing goals that you know cannot work with your project.</p>
</dd>
<dt class="hdlist1">supportedPackagings</dt>
<dd>
<p>Optional.
Defaults to <code>war</code>.
This is a list of maven &lt;packaging&gt; types that can work with the jetty plugin.
Usually, only <code>war</code> projects are suitable, however, you may configure other types.
The plugin will refuse to start if the &lt;packaging&gt; type in the pom is not in list of <code>supportedPackagings</code>.</p>
</dd>
<dt class="hdlist1">systemProperties</dt>
<dd>
<p>Optional.
Allows you to configure System properties for the execution of the plugin.
For more information, see <a href="#setting-system-properties">Setting System Properties</a>.</p>
</dd>
<dt class="hdlist1">systemPropertiesFile</dt>
<dd>
<p>Optional.
A file containing System properties to set for the execution of the plugin.
By default, settings that you make here <strong>do not</strong> override any system properties already set on the command line, by the JVM, or in the POM via <code>systemProperties</code>.
Read <a href="#setting-system-properties">Setting System Properties</a> for how to force overrides.</p>
</dd>
<dt class="hdlist1">jettyProperties</dt>
<dd>
<p>Optional.
A map of property name, value pairs.
Allows you to configure standard jetty properties.</p>
</dd>
</dl>
</div>
</div>
<div class="sect3">
<h4 id="container-classpath"><a class="anchor" href="#container-classpath"></a><a class="link" href="#container-classpath">Container Classpath vs WebApp Classpath</a></h4>
<div class="paragraph">
<p>The Servlet Specification makes a strong distinction between the classpath for a webapp, and the classpath of the container.
When running in maven, the plugin&#8217;s classpath is equivalent to the container classpath.
It will make a classpath for the webapp to be deployed comprised of &lt;dependencies&gt; specified in the pom.</p>
</div>
<div class="paragraph">
<p>If your production environment places specific jars onto the container&#8217;s classpath, the equivalent way to do this with maven is to define these as &lt;dependencies&gt; for the <em>plugin</em> itself, not the <em>project</em>. See <a href="http://maven.apache.org/pom.html#Plugins">configuring maven plugins</a>.
This is suitable if you are using either <code>EMBED</code> or <code>FORK</code> mode.
If you are using <code>EXTERNAL</code> mode, then you should configure the <code>modules</code> parameter with the names of the jetty modules that place these jars onto the container classpath.</p>
</div>
<div class="paragraph">
<p>Note that in <code>EMBED</code> or <code>FORK</code> mode, you could also influence the container classpath by setting the <code>useProvidedScope</code> parameter to <code>true</code>: this will place any dependencies with &lt;scope&gt;provided&lt;scope&gt; onto the plugin&#8217;s classpath.
Use this very cautiously: as the plugin already automatically places most jetty jars onto the classpath, you could wind up with duplicate jars.</p>
</div>
</div>
<div class="sect3">
<h4 id="jetty-run-goal"><a class="anchor" href="#jetty-run-goal"></a><a class="link" href="#jetty-run-goal">jetty:run</a></h4>
<div class="paragraph">
<p>The <code>run</code> goal deploys a webapp that is <em>not</em> first built into a WAR.
A virtual webapp is constructed from the project&#8217;s sources and its dependencies.
It looks for the constituent parts of a webapp in the maven default project locations, although you can override these in the plugin configuration.
For example, by default it looks for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>resources in <code>${project.basedir}/src/main/webapp</code></p>
</li>
<li>
<p>classes in <code>${project.build.outputDirectory}</code></p>
</li>
<li>
<p><code>web.xml</code> in <code>${project.basedir}/src/main/webapp/WEB-INF/</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The plugin first runs a maven parallel build to ensure that the classes are built and up-to-date before deployment.
If you change the source of a class and your IDE automatically compiles it in the background, the plugin picks up the changed class (note you need to configure a non-zero <code>scan</code> interval for automatic redeployment).</p>
</div>
<div class="paragraph">
<p>If the plugin is invoked in a multi-module build, any dependencies that are also in the maven reactor are used from their compiled classes.
Prior to jetty-9.4.7 any dependencies needed to be built first.</p>
</div>
<div class="paragraph">
<p>Once invoked, you can configure the plugin to run continuously, scanning for changes in the project and automatically performing a hot redeploy when necessary.
Any changes you make are immediately reflected in the running instance of Jetty, letting you quickly jump from coding to testing, rather than going through the cycle of: code, compile, reassemble, redeploy, test.</p>
</div>
<div class="paragraph">
<p>The maven build will be paused until jetty exits, at which time maven will also exit.</p>
</div>
<div class="paragraph">
<p>Stopping jetty is accomplished by typing <code>cntrl-c</code> at the command line.</p>
</div>
<div class="paragraph">
<p>Output from jetty will be logged to the console.</p>
</div>
<div class="paragraph">
<p>Here is an example, which turns on scanning for changes every ten seconds, and sets the webapp context path to <code>/test</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;scan&gt;</span>10<span class="tag">&lt;/scan&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/test<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="sect4">
<h5 id="pg-configuration-6"><a class="anchor" href="#pg-configuration-6"></a><a class="link" href="#pg-configuration-6">Configuration</a></h5>
<div class="dlist">
<dl>
<dt class="hdlist1">webApp</dt>
<dd>
<p>This is an instance of <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/maven/plugin/MavenWebAppContext.html">org.eclipse.jetty.maven.plugin.MavenWebAppContext</a>, which is an extension to the class <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/webapp/WebAppContext.hml"><code>org.eclipse.jetty.webapp.WebAppContext</code></a>.
You can use any of the setter methods on this object to configure your webapp.
Here are a few of the most useful ones:</p>
<div class="dlist">
<dl>
<dt class="hdlist1">contextPath</dt>
<dd>
<p>The context path for your webapp. By default, this is set to <code>/</code>.
If using a custom value for this parameter, you should include the leading <code>/</code>, example <code>/mycontext</code>.</p>
</dd>
<dt class="hdlist1">descriptor</dt>
<dd>
<p>The path to the <code>web.xml</code> file for your webapp.
By default, the plugin will look in <code>src/main/webapp/WEB-INF/web.xml</code>.</p>
</dd>
<dt class="hdlist1">defaultsDescriptor</dt>
<dd>
<p>The path to a <code>webdefault.xml</code> file that will be applied to your webapp before the <code>web.xml</code>.
If you don&#8217;t supply one, Jetty uses a default file baked into the <code>jetty-webapp.jar</code>.</p>
</dd>
<dt class="hdlist1">overrideDescriptor</dt>
<dd>
<p>The path to a <code>web.xml</code> file that Jetty applies after reading your <code>web.xml</code>.
You can use this to replace or add configuration.</p>
</dd>
<dt class="hdlist1">jettyEnvXml</dt>
<dd>
<p>Optional.
Location of a <code>jetty-env.xml</code> file, which allows you to make JNDI bindings that satisfy <code>env-entry</code>, <code>resource-env-ref</code>, and <code>resource-ref</code> linkages in the <code>web.xml</code> that are scoped only to the webapp and not shared with other webapps that you might be deploying at the same time (for example, by using a <code>jettyXml</code> file).</p>
</dd>
<dt class="hdlist1">tempDirectory</dt>
<dd>
<p>The path to a dir that Jetty can use to expand or copy jars and jsp compiles when your webapp is running.
The default is <code>${project.build.outputDirectory}/tmp</code>.</p>
</dd>
<dt class="hdlist1">baseResource</dt>
<dd>
<p>The path from which Jetty serves static resources.
Defaults to <code>src/main/webapp</code>.
If this location does not exist (because, for example, your project does not use static content), then the plugin will synthesize a virtual static resource location of <code>target/webapp-synth</code>.</p>
</dd>
<dt class="hdlist1">resourceBases</dt>
<dd>
<p>Use instead of <code>baseResource</code> if you have multiple directories from which you want to serve static content.
This is an array of directory locations, either as urls or file paths.</p>
</dd>
<dt class="hdlist1">baseAppFirst</dt>
<dd>
<p>Defaults to "true".
Controls whether any overlaid wars are added before or after the original base resource(s) of the webapp.
See the section on <a href="#using-overlaid-wars">overlaid wars</a> for more information.</p>
</dd>
<dt class="hdlist1">containerIncludeJarPattern</dt>
<dd>
<p>Defaults to <code>.<strong>/jetty-servlet-api-[<sup>/]</strong>\.jar$|.<strong>javax.servlet.jsp.jstl-[</sup>/]</strong>\.jar|.<strong>taglibs-standard-impl-.</strong>\.jar</code>.
This is a pattern that is applied to the names of the jars on the container&#8217;s classpath (ie the classpath of the plugin, not that of the webapp) that should be scanned for fragments, tlds, annotations etc.
This is analogous to the context attribute <a href="#container-include-jar-pattern">org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</a> that is documented <a href="#container-include-jar-pattern">here</a>.
You can define extra patterns of jars that will be included in the scan.</p>
</dd>
<dt class="hdlist1">webInfIncludeJarPattern</dt>
<dd>
<p>Defaults to matching <em>all</em> of the dependency jars for the webapp (ie the equivalent of WEB-INF/lib).
You can make this pattern more restrictive to only match certain jars by using this setter.
This is analogous to the context attribute <a href="#web-inf-include-jar-pattern">org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</a> that is documented <a href="#web-inf-include-jar-pattern">here</a>.</p>
</dd>
</dl>
</div>
</dd>
<dt class="hdlist1">contextXml</dt>
<dd>
<p>The path to a context xml file that is applied to your webapp AFTER the <code>webApp</code> element.</p>
</dd>
<dt class="hdlist1">classesDirectory</dt>
<dd>
<p>Location of your compiled classes for the webapp.
You should rarely need to set this parameter.
Instead, you should set <code>&lt;build&gt;&lt;outputDirectory&gt;</code> in your <code>pom.xml</code>.</p>
</dd>
<dt class="hdlist1">testClassesDirectory</dt>
<dd>
<p>Location of the compiled test classes for your webapp. By default this is <code>${project.build.testOutputDirectory}</code>.</p>
</dd>
<dt class="hdlist1">useTestScope</dt>
<dd>
<p>If true, the classes from <code>testClassesDirectory</code> and dependencies of scope "test" are placed first on the classpath.
By default this is false.</p>
</dd>
<dt class="hdlist1">scan</dt>
<dd>
<p>The pause in seconds between sweeps of the webapp to check for changes and automatically hot redeploy if any are detected.
<strong>By default this is <code>-1</code>, which disables hot redeployment scanning.</strong>
A value of <code>0</code> means no hot redeployment is done, and that you must use the <kbd>Enter</kbd> key to manually force a redeploy.
Any positive integer will enable hot redeployment, using the number as the sweep interval in seconds.</p>
</dd>
<dt class="hdlist1">scanTargetPatterns</dt>
<dd>
<p>Optional.
List of extra directories with glob-style include/excludes patterns (see <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-">javadoc</a> for <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-">FileSystem.getPathMatcher</a>) to specify other files to periodically scan for changes.</p>
</dd>
<dt class="hdlist1">scanClassesPattern</dt>
<dd>
<p>Optional.
Include and exclude patterns that can be applied to the classesDirectory for the purposes of scanning, it does <strong>not</strong> affect the classpath.
If a file or directory is excluded by the patterns then a change in that file (or subtree in the case of a directory) is ignored and will not cause the webapp to redeploy.
Patterns are specified as a relative path using a glob-like syntax as described in the <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-">javadoc</a> for <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-">FileSystem.getPathMatcher</a>.</p>
</dd>
<dt class="hdlist1">scanTestClassesPattern</dt>
<dd>
<p>Optional.
Include and exclude patterns that can be applied to the testClassesDirectory for the purposes of scanning, it does <strong>not</strong> affect the classpath.
If a file or directory is excluded by the patterns then a change in that file (or subtree in the case of a directory) is ignored and will not cause the webapp to redeploy.
Patterns are specified as a relative path using a glob-like syntax as described in the <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-">javadoc</a> for <a href="http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-">FileSystem.getPathMatcher</a>.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>See <a href="#deployment-modes">Deployment Modes</a> for other configuration parameters available when using the <code>run</code> goal in EMBED, FORK or EXTERNAL modes.</p>
</div>
<div class="paragraph">
<p>Here&#8217;s an example of a pom configuration for the plugin with the <code>run</code> goal:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;project&gt;</span>
...
<span class="tag">&lt;plugins&gt;</span>
...
<span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;descriptor&gt;</span>${project.basedir}/src/over/here/web.xml<span class="tag">&lt;/descriptor&gt;</span>
<span class="tag">&lt;jettyEnvXml&gt;</span>${project.basedir}/src/over/here/jetty-env.xml<span class="tag">&lt;/jettyEnvXml&gt;</span>
<span class="tag">&lt;baseResource&gt;</span>${project.basedir}/src/staticfiles<span class="tag">&lt;/baseResource&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;classesDirectory&gt;</span>${project.basedir}/somewhere/else<span class="tag">&lt;/classesDirectory&gt;</span>
<span class="tag">&lt;scanClassesPattern&gt;</span>
<span class="tag">&lt;excludes&gt;</span>
<span class="tag">&lt;exclude&gt;</span>**/Foo.class<span class="tag">&lt;/exclude&gt;</span>
<span class="tag">&lt;/excludes&gt;</span>
<span class="tag">&lt;/scanClassesPattern&gt;</span>
<span class="tag">&lt;scanTargetPatterns&gt;</span>
<span class="tag">&lt;scanTargetPattern&gt;</span>
<span class="tag">&lt;directory&gt;</span>src/other-resources<span class="tag">&lt;/directory&gt;</span>
<span class="tag">&lt;includes&gt;</span>
<span class="tag">&lt;include&gt;</span>**/*.xml<span class="tag">&lt;/include&gt;</span>
<span class="tag">&lt;include&gt;</span>**/*.properties<span class="tag">&lt;/include&gt;</span>
<span class="tag">&lt;/includes&gt;</span>
<span class="tag">&lt;excludes&gt;</span>
<span class="tag">&lt;exclude&gt;</span>**/myspecial.xml<span class="tag">&lt;/exclude&gt;</span>
<span class="tag">&lt;exclude&gt;</span>**/myspecial.properties<span class="tag">&lt;/exclude&gt;</span>
<span class="tag">&lt;/excludes&gt;</span>
<span class="tag">&lt;/scanTargetPattern&gt;</span>
<span class="tag">&lt;/scanTargetPatterns&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span>
<span class="tag">&lt;/plugins&gt;</span>
...
<span class="tag">&lt;/project&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>If, for whatever reason, you cannot run on an unassembled webapp, the goal <code>run-war</code> works on assembled webapps.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="jetty-run-war-goal"><a class="anchor" href="#jetty-run-war-goal"></a><a class="link" href="#jetty-run-war-goal">jetty:run-war</a></h4>
<div class="paragraph">
<p>When invoked at the command line this goal first executes a maven build of your project to the package phase.</p>
</div>
<div class="paragraph">
<p>By default it then deploys the resultant war to jetty, but you can use this goal instead to deploy <em>any</em> war file by simply setting the <code>&lt;webApp&gt;&lt;war&gt;</code> configuration parameter to its location.</p>
</div>
<div class="paragraph">
<p>If you set a non-zero <code>scan</code>, Jetty watches your <code>pom.xml</code> and the WAR file; if either changes, it redeploys the war.</p>
</div>
<div class="paragraph">
<p>The maven build is held up until jetty exits, which is achieved by typing <code>cntrl-c</code> at the command line.</p>
</div>
<div class="paragraph">
<p>All jetty output is directed to the console.</p>
</div>
<div class="sect4">
<h5 id="pg-configuration-7"><a class="anchor" href="#pg-configuration-7"></a><a class="link" href="#pg-configuration-7">Configuration</a></h5>
<div class="paragraph">
<p>Configuration parameters are:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">webApp</dt>
<dd>
<div class="dlist">
<dl>
<dt class="hdlist1">war</dt>
<dd>
<p>The location of the built WAR file. This defaults to <code>${project.build.directory}/${project.build.finalName}.war</code>.
You can set it to the location of any pre-built war file.</p>
</dd>
<dt class="hdlist1">contextPath</dt>
<dd>
<p>The context path for your webapp. By default, this is set to <code>/</code>.
If using a custom value for this parameter, you should include the leading <code>/</code>, example <code>/mycontext</code>.</p>
</dd>
<dt class="hdlist1">defaultsDescriptor</dt>
<dd>
<p>The path to a <code>webdefault.xml</code> file that will be applied to your webapp before the <code>web.xml</code>.
If you don&#8217;t supply one, Jetty uses a default file baked into the <code>jetty-webapp.jar</code>.</p>
</dd>
<dt class="hdlist1">overrideDescriptor</dt>
<dd>
<p>The path to a <code>web.xml</code> file that Jetty applies after reading your <code>web.xml</code>.
You can use this to replace or add configuration.</p>
</dd>
<dt class="hdlist1">containerIncludeJarPattern</dt>
<dd>
<p>Defaults to <code>.<strong>/jetty-servlet-api-[<sup>/]</strong>\.jar$|.<strong>javax.servlet.jsp.jstl-[</sup>/]</strong>\.jar|.<strong>taglibs-standard-impl-.</strong>\.jar</code>.
This is a pattern that is applied to the names of the jars on the container&#8217;s classpath (ie the classpath of the plugin, not that of the webapp) that should be scanned for fragments, tlds, annotations etc.
This is analogous to the context attribute <a href="#container-include-jar-pattern">org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</a> that is documented <a href="#container-include-jar-pattern">here</a>.
You can define extra patterns of jars that will be included in the scan.</p>
</dd>
<dt class="hdlist1">webInfIncludeJarPattern</dt>
<dd>
<p>Defaults to matching <em>all</em> of the dependency jars for the webapp (ie the equivalent of WEB-INF/lib).
You can make this pattern more restrictive to only match certain jars by using this setter.
This is analogous to the context attribute <a href="#web-inf-include-jar-pattern">org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</a> that is documented <a href="#web-inf-include-jar-pattern">here</a>.</p>
</dd>
<dt class="hdlist1">tempDirectory</dt>
<dd>
<p>The path to a dir that Jetty can use to expand or copy jars and jsp compiles when your webapp is running.
The default is <code>${project.build.outputDirectory}/tmp</code>.</p>
</dd>
<dt class="hdlist1">contextXml</dt>
<dd>
<p>The path to a context xml file that is applied to your webapp AFTER the <code>webApp</code> element.</p>
</dd>
</dl>
</div>
</dd>
<dt class="hdlist1">scan</dt>
<dd>
<p>The pause in seconds between sweeps of the webapp to check for changes and automatically hot redeploy if any are detected.
<strong>By default this is <code>-1</code>, which disables hot redeployment scanning.</strong>
A value of <code>0</code> means no hot redeployment is done, and that you must use the <kbd>Enter</kbd> key to manually force a redeploy.
Any positive integer will enable hot redeployment, using the number as the sweep interval in seconds.</p>
</dd>
<dt class="hdlist1">scanTargetPatterns</dt>
<dd>
<p>Optional.
List of directories with ant-style include/excludes patterns to specify other files to periodically scan for changes.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>See <a href="#deployment-modes">Deployment Modes</a> for other configuration parameters available when using the <code>run-war</code> goal in EMBED, FORK or EXTERNAL modes.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="jetty-start-goal"><a class="anchor" href="#jetty-start-goal"></a><a class="link" href="#jetty-start-goal">jetty:start</a></h4>
<div class="paragraph">
<p>This is similar to the <code>jetty:run</code> goal, however it is <em>not</em> designed to be run from the command line and does <em>not</em> first execute the build up until the <code>test-compile</code> phase to ensure that all necessary classes and files of the webapp have been generated.
It will <em>not</em> scan your project for changes and restart your webapp.
It does <em>not</em> pause maven until jetty is stopped.</p>
</div>
<div class="paragraph">
<p>Instead, it is designed to be used with build phase bindings in your pom.
For example to you can have maven start your webapp at the beginning of your tests and stop at the end.</p>
</div>
<div class="paragraph">
<p>If the plugin is invoked as part of a multi-module build, any dependencies that are also in the maven reactor are used from their compiled classes.
Prior to jetty-9.4.7 any dependencies needed to be built first.</p>
</div>
<div class="paragraph">
<p>Here&#8217;s an example of using the <code>pre-integration-test</code> and <code>post-integration-test</code> Maven build phases to trigger the execution and termination of Jetty:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;stopKey&gt;</span>foo<span class="tag">&lt;/stopKey&gt;</span>
<span class="tag">&lt;stopPort&gt;</span>9999<span class="tag">&lt;/stopPort&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;executions&gt;</span>
<span class="tag">&lt;execution&gt;</span>
<span class="tag">&lt;id&gt;</span>start-jetty<span class="tag">&lt;/id&gt;</span>
<span class="tag">&lt;phase&gt;</span>pre-integration-test<span class="tag">&lt;/phase&gt;</span>
<span class="tag">&lt;goals&gt;</span>
<span class="tag">&lt;goal&gt;</span>start<span class="tag">&lt;/goal&gt;</span>
<span class="tag">&lt;/goals&gt;</span>
<span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;execution&gt;</span>
<span class="tag">&lt;id&gt;</span>stop-jetty<span class="tag">&lt;/id&gt;</span>
<span class="tag">&lt;phase&gt;</span>post-integration-test<span class="tag">&lt;/phase&gt;</span>
<span class="tag">&lt;goals&gt;</span>
<span class="tag">&lt;goal&gt;</span>stop<span class="tag">&lt;/goal&gt;</span>
<span class="tag">&lt;/goals&gt;</span>
<span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;/executions&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This goal will generate output from jetty into the <code>target/jetty-start.out</code> file.</p>
</div>
<div class="sect4">
<h5 id="pg-configuration-8"><a class="anchor" href="#pg-configuration-8"></a><a class="link" href="#pg-configuration-8">Configuration</a></h5>
<div class="paragraph">
<p>These configuration parameters are available:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">webApp</dt>
<dd>
<p>This is an instance of <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/maven/plugin/MavenWebAppContext.html">org.eclipse.jetty.maven.plugin.MavenWebAppContext</a>, which is an extension to the class <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/webapp/WebAppContext.hml"><code>org.eclipse.jetty.webapp.WebAppContext</code></a>.
You can use any of the setter methods on this object to configure your webapp.
Here are a few of the most useful ones:</p>
<div class="dlist">
<dl>
<dt class="hdlist1">contextPath</dt>
<dd>
<p>The context path for your webapp. By default, this is set to <code>/</code>.
If using a custom value for this parameter, you should include the leading <code>/</code>, example <code>/mycontext</code>.</p>
</dd>
<dt class="hdlist1">descriptor</dt>
<dd>
<p>The path to the <code>web.xml</code> file for your webapp.
The default is <code>src/main/webapp/WEB-INF/web.xml</code>.</p>
</dd>
<dt class="hdlist1">defaultsDescriptor</dt>
<dd>
<p>The path to a <code>webdefault.xml</code> file that will be applied to your webapp before the <code>web.xml</code>.
If you don&#8217;t supply one, Jetty uses a default file baked into the <code>jetty-webapp.jar</code>.</p>
</dd>
<dt class="hdlist1">overrideDescriptor</dt>
<dd>
<p>The path to a <code>web.xml</code> file that Jetty applies after reading your <code>web.xml</code>.
You can use this to replace or add configuration.</p>
</dd>
<dt class="hdlist1">jettyEnvXml</dt>
<dd>
<p>Optional.
Location of a <code>jetty-env.xml</code> file, which allows you to make JNDI bindings that satisfy <code>env-entry</code>, <code>resource-env-ref</code>, and <code>resource-ref</code> linkages in the <code>web.xml</code> that are scoped only to the webapp and not shared with other webapps that you might be deploying at the same time (for example, by using a <code>jettyXml</code> file).</p>
</dd>
<dt class="hdlist1">tempDirectory</dt>
<dd>
<p>The path to a dir that Jetty can use to expand or copy jars and jsp compiles when your webapp is running.
The default is <code>${project.build.outputDirectory}/tmp</code>.</p>
</dd>
<dt class="hdlist1">baseResource</dt>
<dd>
<p>The path from which Jetty serves static resources.
Defaults to <code>src/main/webapp</code>.</p>
</dd>
<dt class="hdlist1">resourceBases</dt>
<dd>
<p>Use instead of <code>baseResource</code> if you have multiple directories from which you want to serve static content.
This is an array of directory names.</p>
</dd>
<dt class="hdlist1">baseAppFirst</dt>
<dd>
<p>Defaults to "true".
Controls whether any overlaid wars are added before or after the original base resource(s) of the webapp.
See the section on <a href="#using-overlaid-wars">overlaid wars</a> for more information.</p>
</dd>
<dt class="hdlist1">containerIncludeJarPattern</dt>
<dd>
<p>Defaults to <code>.<strong>/jetty-servlet-api-[<sup>/]</strong>\.jar$|.<strong>javax.servlet.jsp.jstl-[</sup>/]</strong>\.jar|.<strong>taglibs-standard-impl-.</strong>\.jar</code>.
This is a pattern that is applied to the names of the jars on the container&#8217;s classpath (ie the classpath of the plugin, not that of the webapp) that should be scanned for fragments, tlds, annotations etc.
This is analogous to the context attribute <a href="#container-include-jar-pattern">org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</a> that is documented <a href="#container-include-jar-pattern">here</a>.
You can define extra patterns of jars that will be included in the scan.</p>
</dd>
<dt class="hdlist1">webInfIncludeJarPattern</dt>
<dd>
<p>Defaults to matching <em>all</em> of the dependency jars for the webapp (ie the equivalent of WEB-INF/lib).
You can make this pattern more restrictive to only match certain jars by using this setter.
This is analogous to the context attribute <a href="#web-inf-include-jar-pattern">org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</a> that is documented <a href="#web-inf-include-jar-pattern">here</a>.</p>
</dd>
</dl>
</div>
</dd>
<dt class="hdlist1">contextXml</dt>
<dd>
<p>The path to a context xml file that is applied to your webapp AFTER the <code>webApp</code> element.</p>
</dd>
<dt class="hdlist1">classesDirectory</dt>
<dd>
<p>Location of your compiled classes for the webapp.
You should rarely need to set this parameter.
Instead, you should set <code>build outputDirectory</code> in your <code>pom.xml</code>.</p>
</dd>
<dt class="hdlist1">testClassesDirectory</dt>
<dd>
<p>Location of the compiled test classes for your webapp. By default this is <code>${project.build.testOutputDirectory}</code>.</p>
</dd>
<dt class="hdlist1">useTestScope</dt>
<dd>
<p>If true, the classes from <code>testClassesDirectory</code> and dependencies of scope "test" are placed first on the classpath.
By default this is false.</p>
</dd>
<dt class="hdlist1">stopPort</dt>
<dd>
<p>Optional.
Port to listen on for stop commands.
Useful to use in conjunction with the <a href="#jetty-stop-goal">stop</a> and <a href="#jetty-start-goal">start</a> goals.</p>
</dd>
<dt class="hdlist1">stopKey</dt>
<dd>
<p>Optional.
Used in conjunction with stopPort for stopping jetty.
Useful to use in conjunction with the <a href="#jetty-stop-goal">stop</a> and <a href="#jetty-start-goal">start</a> goals.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>These additional configuration parameters are available when running in <code>FORK</code> or <code>EXTERNAL</code> mode:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">maxChildStartChecks</dt>
<dd>
<p>Default is <code>10</code>.
This is maximum number of times the parent process checks to see if the forked jetty process has started correctly</p>
</dd>
<dt class="hdlist1">maxChildStartCheckMs</dt>
<dd>
<p>Default is <code>200</code>.
This is the time in milliseconds between checks on the startup of the forked jetty process.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect3">
<h4 id="jetty-start-war-goal"><a class="anchor" href="#jetty-start-war-goal"></a><a class="link" href="#jetty-start-war-goal">jetty:start-war</a></h4>
<div class="paragraph">
<p>Similarly to the <code>jetty:start</code> goal, <code>jetty:start-war</code> is designed to be bound to build lifecycle phases in your pom.</p>
</div>
<div class="paragraph">
<p>It will <em>not</em> scan your project for changes and restart your webapp.
It does <em>not</em> pause maven until jetty is stopped.</p>
</div>
<div class="paragraph">
<p>By default, if your pom is for a webapp project, it will deploy the war file for the project to jetty.
However, like the <code>jetty:run-war</code> project, you can nominate any war file to deploy by defining its location in the <code>&lt;webApp&gt;&lt;war&gt;</code> parameter.</p>
</div>
<div class="paragraph">
<p>If the plugin is invoked as part of a multi-module build, any dependencies that are also in the maven reactor are used from their compiled classes.
Prior to jetty-9.4.7 any dependencies needed to be built first.</p>
</div>
<div class="paragraph">
<p>This goal will generate output from jetty into the <code>target/jetty-start-war.out</code> file.</p>
</div>
<div class="sect4">
<h5 id="pg-configuration-9"><a class="anchor" href="#pg-configuration-9"></a><a class="link" href="#pg-configuration-9">Configuration</a></h5>
<div class="paragraph">
<p>These configuration parameters are available:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">webApp</dt>
<dd>
<div class="dlist">
<dl>
<dt class="hdlist1">war</dt>
<dd>
<p>The location of the built WAR file. This defaults to <code>${project.build.directory}/${project.build.finalName}.war</code>.
You can set it to the location of any pre-built war file.</p>
</dd>
<dt class="hdlist1">contextPath</dt>
<dd>
<p>The context path for your webapp. By default, this is set to <code>/</code>.
If using a custom value for this parameter, you should include the leading <code>/</code>, example <code>/mycontext</code>.</p>
</dd>
<dt class="hdlist1">defaultsDescriptor</dt>
<dd>
<p>The path to a <code>webdefault.xml</code> file that will be applied to your webapp before the <code>web.xml</code>.
If you don&#8217;t supply one, Jetty uses a default file baked into the <code>jetty-webapp.jar</code>.</p>
</dd>
<dt class="hdlist1">overrideDescriptor</dt>
<dd>
<p>The path to a <code>web.xml</code> file that Jetty applies after reading your <code>web.xml</code>.
You can use this to replace or add configuration.</p>
</dd>
<dt class="hdlist1">containerIncludeJarPattern</dt>
<dd>
<p>Defaults to <code>.<strong>/jetty-servlet-api-[<sup>/]</strong>\.jar$|.<strong>javax.servlet.jsp.jstl-[</sup>/]</strong>\.jar|.<strong>taglibs-standard-impl-.</strong>\.jar</code>.
This is a pattern that is applied to the names of the jars on the container&#8217;s classpath (ie the classpath of the plugin, not that of the webapp) that should be scanned for fragments, tlds, annotations etc.
This is analogous to the context attribute <a href="#container-include-jar-pattern">org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</a> that is documented <a href="#container-include-jar-pattern">here</a>.
You can define extra patterns of jars that will be included in the scan.</p>
</dd>
<dt class="hdlist1">webInfIncludeJarPattern</dt>
<dd>
<p>Defaults to matching <em>all</em> of the dependency jars for the webapp (ie the equivalent of WEB-INF/lib).
You can make this pattern more restrictive to only match certain jars by using this setter.
This is analogous to the context attribute <a href="#web-inf-include-jar-pattern">org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</a> that is documented <a href="#web-inf-include-jar-pattern">here</a>.</p>
</dd>
<dt class="hdlist1">tempDirectory</dt>
<dd>
<p>The path to a dir that Jetty can use to expand or copy jars and jsp compiles when your webapp is running.
The default is <code>${project.build.outputDirectory}/tmp</code>.</p>
</dd>
<dt class="hdlist1">contextXml</dt>
<dd>
<p>The path to a context xml file that is applied to your webapp AFTER the <code>webApp</code> element.</p>
</dd>
</dl>
</div>
</dd>
<dt class="hdlist1">stopPort</dt>
<dd>
<p>Optional.
Port to listen on for stop commands.
Useful to use in conjunction with the <a href="#jetty-stop-goal">stop</a>.</p>
</dd>
<dt class="hdlist1">stopKey</dt>
<dd>
<p>Optional.
Used in conjunction with stopPort for stopping jetty.
Useful to use in conjunction with the <a href="#jetty-stop-goal">stop</a>.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>These additional configuration parameters are available when running in FORK or EXTERNAL mode:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">maxChildStartChecks</dt>
<dd>
<p>Default is <code>10</code>.
This is maximum number of times the parent process checks to see if the forked jetty process has started correctly</p>
</dd>
<dt class="hdlist1">maxChildStartCheckMs</dt>
<dd>
<p>Default is <code>200</code>.
This is the time in milliseconds between checks on the startup of the forked jetty process.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect3">
<h4 id="jetty-stop-goal"><a class="anchor" href="#jetty-stop-goal"></a><a class="link" href="#jetty-stop-goal">jetty:stop</a></h4>
<div class="paragraph">
<p>The stop goal stops a FORK or EXTERNAL mode running instance of Jetty.
To use it, you need to configure the plugin with a special port number and key.
That same port number and key will also be used by the other goals that start jetty.</p>
</div>
<div class="sect4">
<h5 id="pg-configuration-10"><a class="anchor" href="#pg-configuration-10"></a><a class="link" href="#pg-configuration-10">Configuration</a></h5>
<div class="dlist">
<dl>
<dt class="hdlist1">stopPort</dt>
<dd>
<p>A port number for Jetty to listen on to receive a stop command to cause it to shutdown.</p>
</dd>
<dt class="hdlist1">stopKey</dt>
<dd>
<p>A string value sent to the <code>stopPort</code> to validate the stop command.</p>
</dd>
<dt class="hdlist1">stopWait</dt>
<dd>
<p>The maximum time in seconds that the plugin will wait for confirmation that Jetty has stopped.
If false or not specified, the plugin does not wait for confirmation but exits after issuing the stop command.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Here&#8217;s a configuration example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;stopPort&gt;</span>9966<span class="tag">&lt;/stopPort&gt;</span>
<span class="tag">&lt;stopKey&gt;</span>foo<span class="tag">&lt;/stopKey&gt;</span>
<span class="tag">&lt;stopWait&gt;</span>10<span class="tag">&lt;/stopWait&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then, while Jetty is running (in another window), type:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>mvn jetty:stop</pre>
</div>
</div>
<div class="paragraph">
<p>The <code>stopPort</code> must be free on the machine you are running on.
If this is not the case, you will get an "Address already in use" error message after the "Started ServerConnector &#8230;&#8203;" message.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="jetty-effective-web-xml-goal"><a class="anchor" href="#jetty-effective-web-xml-goal"></a><a class="link" href="#jetty-effective-web-xml-goal">jetty:effective-web-xml</a></h4>
<div class="paragraph">
<p>This goal calculates a synthetic <code>web.xml</code> (the "effective web.xml") according to the rules of the Servlet Specification taking into account all sources of discoverable configuration of web components in your application: descriptors (<code>webdefault.xml</code>, <code>web.xml</code>, <code>web-fragment.xml`s, `web-override.xml</code>) and discovered annotations (<code>@WebServlet</code>, <code>@WebFilter</code>, <code>@WebListener</code>).
No programmatic declarations of servlets, filters and listeners can be taken into account.</p>
</div>
<div class="paragraph">
<p>You can calculate the effective web.xml for any pre-built war file by setting the <code>&lt;webApp&gt;&lt;war&gt;</code> parameter, or you can calculate it for the unassembled webapp by setting all of the usual <code>&lt;webApp&gt;</code> parameters as for <code>jetty:run</code>.</p>
</div>
<div class="paragraph">
<p>Other useful information about your webapp that is produced as part of the analysis is also stored as context parameters in the effective-web.xml.
The effective-web.xml can be used in conjunction with the <a href="#quickstart-webapp">Quickstart</a> feature to quickly start your webapp (note that Quickstart is not appropriate for the mvn jetty goals).</p>
</div>
<div class="paragraph">
<p>The effective web.xml from these combined sources is generated into a file, which by default is <code>target/effective-web.xml</code>, but can be changed by setting the <code>effectiveWebXml</code> configuration parameter.</p>
</div>
<div class="sect4">
<h5 id="pg-configuration-11"><a class="anchor" href="#pg-configuration-11"></a><a class="link" href="#pg-configuration-11">Configuration</a></h5>
<div class="dlist">
<dl>
<dt class="hdlist1">effectiveWebXml</dt>
<dd>
<p>The full path name of a file into which you would like the effective web xml generated.</p>
</dd>
<dt class="hdlist1">webApp</dt>
<dd>
<div class="dlist">
<dl>
<dt class="hdlist1">war</dt>
<dd>
<p>The location of the built WAR file. This defaults to <code>${project.build.directory}/${project.build.finalName}.war</code>.
You can set it to the location of any pre-built war file.
Or you can leave it blank and set up the other <code>webApp</code> parameters as per <a href="#jetty-run-goal">jetty:run</a>, as well as the <code>webAppSourceDirectory</code>, <code>classes</code> and <code>testClasses</code> parameters.</p>
</dd>
<dt class="hdlist1">contextPath</dt>
<dd>
<p>The context path for your webapp. By default, this is set to <code>/</code>.
If using a custom value for this parameter, you should include the leading <code>/</code>, example <code>/mycontext</code>.</p>
</dd>
<dt class="hdlist1">defaultsDescriptor</dt>
<dd>
<p>The path to a <code>webdefault.xml</code> file that will be applied to your webapp before the <code>web.xml</code>.
If you don&#8217;t supply one, Jetty uses a default file baked into the <code>jetty-webapp.jar</code>.</p>
</dd>
<dt class="hdlist1">overrideDescriptor</dt>
<dd>
<p>The path to a <code>web.xml</code> file that Jetty applies after reading your <code>web.xml</code>.
You can use this to replace or add configuration.</p>
</dd>
<dt class="hdlist1">containerIncludeJarPattern</dt>
<dd>
<p>Defaults to <code>.<strong>/jetty-servlet-api-[<sup>/]</strong>\.jar$|.<strong>javax.servlet.jsp.jstl-[</sup>/]</strong>\.jar|.<strong>taglibs-standard-impl-.</strong>\.jar</code>.
This is a pattern that is applied to the names of the jars on the container&#8217;s classpath (ie the classpath of the plugin, not that of the webapp) that should be scanned for fragments, tlds, annotations etc.
This is analogous to the context attribute <a href="#container-include-jar-pattern">org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</a> that is documented <a href="#container-include-jar-pattern">here</a>.
You can define extra patterns of jars that will be included in the scan.</p>
</dd>
<dt class="hdlist1">webInfIncludeJarPattern</dt>
<dd>
<p>Defaults to matching <em>all</em> of the dependency jars for the webapp (ie the equivalent of WEB-INF/lib).
You can make this pattern more restrictive to only match certain jars by using this setter.
This is analogous to the context attribute <a href="#web-inf-include-jar-pattern">org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern</a> that is documented <a href="#web-inf-include-jar-pattern">here</a>.</p>
</dd>
<dt class="hdlist1">tempDirectory</dt>
<dd>
<p>The path to a dir that Jetty can use to expand or copy jars and jsp compiles when your webapp is running.
The default is <code>${project.build.outputDirectory}/tmp</code>.</p>
</dd>
<dt class="hdlist1">contextXml</dt>
<dd>
<p>The path to a context xml file that is applied to your webapp AFTER the <code>webApp</code> element.</p>
</dd>
</dl>
</div>
</dd>
</dl>
</div>
<div class="paragraph">
<p>You can also generate the origin of each element into the effective web.xml file.
The origin is either a descriptor eg web.xml,web-fragment.xml,override-web.xml file, or an annotation eg @WebServlet.
Some examples of elements with origin attribute information are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;listener</span> <span class="attribute-name">origin</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">DefaultsDescriptor(file:///path/to/distro/etc/webdefault.xml):21</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;listener</span> <span class="attribute-name">origin</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">WebDescriptor(file:///path/to/base/webapps/test-spec/WEB-INF/web.xml):22</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;servlet-class</span> <span class="attribute-name">origin</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">FragmentDescriptor(jar:file:///path/to/base/webapps/test-spec/WEB-INF/lib/test-web-fragment.jar!/META-INF/web-fragment.xml):23</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;servlet-class</span> <span class="attribute-name">origin</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@WebServlet(com.acme.test.TestServlet):24</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>To generate origin information, use the following configuration parameters on the <code>webApp</code> element:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">originAttribute</dt>
<dd>
<p>The name of the attribute that will contain the origin.
By default it is <code>origin</code>.</p>
</dd>
<dt class="hdlist1">generateOrigin</dt>
<dd>
<p>False by default. If true, will force the generation of the originAttribute onto each element.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect3">
<h4 id="using-overlaid-wars"><a class="anchor" href="#using-overlaid-wars"></a><a class="link" href="#using-overlaid-wars">Using Overlaid wars</a></h4>
<div class="paragraph">
<p>If your webapp depends on other war files, the <a href="#jetty-run-goal">jetty:run</a> and <a href="#jetty-start-goal">jetty:start</a> goals are able to merge resources from all of them.
It can do so based on the settings of the <a href="http://maven.apache.org/plugins/maven-war-plugin/">maven-war-plugin</a>, or if your project does not use the <a href="http://maven.apache.org/plugins/maven-war-plugin/">maven-war-plugin</a> to handle the overlays, it can fall back to a simple algorithm to determine the ordering of resources.</p>
</div>
<div class="sect4">
<h5 id="pg-with-maven-war-plugin"><a class="anchor" href="#pg-with-maven-war-plugin"></a><a class="link" href="#pg-with-maven-war-plugin">With maven-war-plugin</a></h5>
<div class="paragraph">
<p>The maven-war-plugin has a rich set of capabilities for merging resources.
The <code>jetty:run</code> and <code>jetty:start</code> goals are able to interpret most of them and apply them during execution of your unassembled webapp.
This is probably best seen by looking at a concrete example.</p>
</div>
<div class="paragraph">
<p>Suppose your webapp depends on the following wars:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>com.acme<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>X<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;type&gt;</span>war<span class="tag">&lt;/type&gt;</span>
<span class="tag">&lt;/dependency&gt;</span>
<span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>com.acme<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>Y<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;type&gt;</span>war<span class="tag">&lt;/type&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Containing:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>WebAppX:
/foo.jsp
/bar.jsp
/WEB-INF/web.xml
WebAppY:
/bar.jsp
/baz.jsp
/WEB-INF/web.xml
/WEB-INF/special.xml</pre>
</div>
</div>
<div class="paragraph">
<p>They are configured for the <a href="http://maven.apache.org/plugins/maven-war-plugin/overlays.html">maven-war-plugin</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>maven-war-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;overlays&gt;</span>
<span class="tag">&lt;overlay&gt;</span>
<span class="tag">&lt;groupId&gt;</span>com.acme<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>X<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;excludes&gt;</span>
<span class="tag">&lt;exclude&gt;</span>bar.jsp<span class="tag">&lt;/exclude&gt;</span>
<span class="tag">&lt;/excludes&gt;</span>
<span class="tag">&lt;/overlay&gt;</span>
<span class="tag">&lt;overlay&gt;</span>
<span class="tag">&lt;groupId&gt;</span>com.acme<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>Y<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;excludes&gt;</span>
<span class="tag">&lt;exclude&gt;</span>baz.jsp<span class="tag">&lt;/exclude&gt;</span>
<span class="tag">&lt;/excludes&gt;</span>
<span class="tag">&lt;/overlay&gt;</span>
<span class="tag">&lt;overlay&gt;</span>
<span class="tag">&lt;/overlay&gt;</span>
<span class="tag">&lt;/overlays&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then executing jetty:run would yield the following ordering of resources: <code>com.acme.X.war : com.acme.Y.war: ${project.basedir}/src/main/webapp</code>.
Note that the current project&#8217;s resources are placed last in the ordering due to the empty &lt;overlay/&gt; element in the maven-war-plugin.
You can either use that, or specify the <code>&lt;baseAppFirst&gt;false&lt;/baseAppFirst&gt;</code> parameter to the jetty-maven-plugin.</p>
</div>
<div class="paragraph">
<p>Moreover, due to the <code>exclusions</code> specified above, a request for the resource ` bar.jsp` would only be satisfied from <code>com.acme.Y.war.</code>
Similarly as <code>baz.jsp</code> is excluded, a request for it would result in a 404 error.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-without-maven-war-plugin"><a class="anchor" href="#pg-without-maven-war-plugin"></a><a class="link" href="#pg-without-maven-war-plugin">Without maven-war-plugin</a></h5>
<div class="paragraph">
<p>The algorithm is fairly simple, is based on the ordering of declaration of the dependent wars, and does not support exclusions.
The configuration parameter <code>&lt;baseAppFirst&gt;</code> (see for example <a href="#jetty-run-goal">jetty:run</a> for more information) can be used to control whether your webapp&#8217;s resources are placed first or last on the resource path at runtime.</p>
</div>
<div class="paragraph">
<p>For example, suppose our webapp depends on these two wars:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>com.acme<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>X<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;type&gt;</span>war<span class="tag">&lt;/type&gt;</span>
<span class="tag">&lt;/dependency&gt;</span>
<span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>com.acme<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>Y<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;type&gt;</span>war<span class="tag">&lt;/type&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Suppose the webapps contain:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>WebAppX:
/foo.jsp
/bar.jsp
/WEB-INF/web.xml
WebAppY:
/bar.jsp
/baz.jsp
/WEB-INF/web.xml
/WEB-INF/special.xml</pre>
</div>
</div>
<div class="paragraph">
<p>Then our webapp has available these additional resources:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>/foo.jsp (X)
/bar.jsp (X)
/baz.jsp (Y)
/WEB-INF/web.xml (X)
/WEB-INF/special.xml (Y)</pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="configuring-security-settings"><a class="anchor" href="#configuring-security-settings"></a><a class="link" href="#configuring-security-settings">Configuring Security Settings</a></h4>
<div class="paragraph">
<p>You can configure LoginServices in the plugin.
Here&#8217;s an example of setting up the HashLoginService for a webapp:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;scan&gt;</span>10<span class="tag">&lt;/scan&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/test<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;loginServices&gt;</span>
<span class="tag">&lt;loginService</span> <span class="attribute-name">implementation</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.security.HashLoginService</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;name&gt;</span>Test Realm<span class="tag">&lt;/name&gt;</span>
<span class="tag">&lt;config&gt;</span>${project.basedir}/src/etc/realm.properties<span class="tag">&lt;/config&gt;</span>
<span class="tag">&lt;/loginService&gt;</span>
<span class="tag">&lt;/loginServices&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="using-multiple-webapp-root-directories"><a class="anchor" href="#using-multiple-webapp-root-directories"></a><a class="link" href="#using-multiple-webapp-root-directories">Using Multiple Webapp Root Directories</a></h4>
<div class="paragraph">
<p>If you have external resources that you want to incorporate in the execution of a webapp, but which are not assembled into war files, you can&#8217;t use the overlaid wars method described above, but you can tell Jetty the directories in which these external resources are located.
At runtime, when Jetty receives a request for a resource, it searches all the locations to retrieve the resource.
It&#8217;s a lot like the overlaid war situation, but without the war.</p>
</div>
<div class="paragraph">
<p>Here is a configuration example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/${build.finalName}<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;baseResource</span> <span class="attribute-name">implementation</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.util.resource.ResourceCollection</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;resourcesAsCSV&gt;</span>src/main/webapp,/home/johndoe/path/to/my/other/source,/yet/another/folder<span class="tag">&lt;/resourcesAsCSV&gt;</span>
<span class="tag">&lt;/baseResource&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;/configuration&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="running-more-than-one-webapp"><a class="anchor" href="#running-more-than-one-webapp"></a><a class="link" href="#running-more-than-one-webapp">Running More than One Webapp</a></h4>
<div class="sect4">
<h5 id="pg-with-jettyrun"><a class="anchor" href="#pg-with-jettyrun"></a><a class="link" href="#pg-with-jettyrun">With jetty:run</a></h5>
<div class="paragraph">
<p>You can use either a <code>jetty.xml</code> file to configure extra (pre-compiled) webapps that you want to deploy, or you can use the <code>&lt;contextHandlers&gt;</code> configuration element to do so.
If you want to deploy webapp A, and webapps B and C in the same Jetty instance:</p>
</div>
<div class="paragraph">
<p>Putting the configuration in webapp A&#8217;s <code>pom.xml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;scan&gt;</span>10<span class="tag">&lt;/scan&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/test<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;contextHandlers&gt;</span>
<span class="tag">&lt;contextHandler</span> <span class="attribute-name">implementation</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.maven.plugin.MavenWebAppContext</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;war&gt;</span>${project.basedir}../../B.war<span class="tag">&lt;/war&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/B<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/contextHandler&gt;</span>
<span class="tag">&lt;contextHandler</span> <span class="attribute-name">implementation</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.maven.plugin.MavenWebAppContext</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;war&gt;</span>${project.basedir}../../C.war<span class="tag">&lt;/war&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/C<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/contextHandler&gt;</span>
<span class="tag">&lt;/contextHandlers&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If the <code>ContextHandler</code> you are deploying is a webapp, it is <strong>essential</strong> that you use an <code>org.eclipse.jetty.maven.plugin.MavenWebAppContext</code> instance rather than a standard <code>org.eclipse.jetty.webapp.WebAppContext</code> instance.
Only the former will allow the webapp to function correctly in the maven environment.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Alternatively, add a <code>jetty.xml</code> file to webapp A.
Copy the <code>jetty.xml</code> file from the Jetty distribution, and then add WebAppContexts for the other 2 webapps:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;Ref</span> <span class="attribute-name">refid</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">Contexts</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;Call</span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">addHandler</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;Arg&gt;</span>
<span class="tag">&lt;New</span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.maven.plugin.MavenWebAppContext</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;Set</span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">contextPath</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>/B<span class="tag">&lt;/Set&gt;</span>
<span class="tag">&lt;Set</span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">war</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>../../B.war<span class="tag">&lt;/Set&gt;</span>
<span class="tag">&lt;/New&gt;</span>
<span class="tag">&lt;/Arg&gt;</span>
<span class="tag">&lt;/Call&gt;</span>
<span class="tag">&lt;Call&gt;</span>
<span class="tag">&lt;Arg&gt;</span>
<span class="tag">&lt;New</span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.maven.plugin.MavenWebAppContext</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
<span class="tag">&lt;Set</span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">contextPath</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>/C<span class="tag">&lt;/Set&gt;</span>
<span class="tag">&lt;Set</span> <span class="attribute-name">name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">war</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>../../C.war<span class="tag">&lt;/Set&gt;</span>
<span class="tag">&lt;/New&gt;</span>
<span class="tag">&lt;/Arg&gt;</span>
<span class="tag">&lt;/Call&gt;</span>
<span class="tag">&lt;/Ref&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Then configure the location of this <code>jetty.xml</code> file into webapp A&#8217;s jetty plugin:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;scan&gt;</span>10<span class="tag">&lt;/scan&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/test<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;jettyXml&gt;</span>src/main/etc/jetty.xml<span class="tag">&lt;/jettyXml&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>For either of these solutions, the other webapps must already have been built, and they are not automatically monitored for changes.
You can refer either to the packed WAR file of the pre-built webapps or to their expanded equivalents.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="setting-system-properties"><a class="anchor" href="#setting-system-properties"></a><a class="link" href="#setting-system-properties">Setting System Properties</a></h4>
<div class="paragraph">
<p>You can specify property name/value pairs that Jetty sets as System properties for the execution of the plugin.
This feature is useful to tidy up the command line and save a lot of typing.</p>
</div>
<div class="paragraph">
<p>However, <strong>sometimes it is not possible to use this feature to set System properties</strong> - sometimes the software component using the System property is already initialized by the time that maven runs (in which case you will need to provide the System property on the command line), or by the time that Jetty runs.
In the latter case, you can use the <a href="http://www.mojohaus.org/">maven properties plugin</a> to define the system properties instead. Here&#8217;s an example that configures the logback logging system as the Jetty logger:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.codehaus.mojo<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>properties-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>1.0-alpha-2<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;executions&gt;</span>
<span class="tag">&lt;execution&gt;</span>
<span class="tag">&lt;goals&gt;</span>
<span class="tag">&lt;goal&gt;</span>set-system-properties<span class="tag">&lt;/goal&gt;</span>
<span class="tag">&lt;/goals&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;properties&gt;</span>
<span class="tag">&lt;property&gt;</span>
<span class="tag">&lt;name&gt;</span>logback.configurationFile<span class="tag">&lt;/name&gt;</span>
<span class="tag">&lt;value&gt;</span>${project.baseUri}/resources/logback.xml<span class="tag">&lt;/value&gt;</span>
<span class="tag">&lt;/property&gt;</span>
<span class="tag">&lt;/properties&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;/executions&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If a System property is already set (for example, from the command line or by the JVM itself), then by default these configured properties <strong>DO NOT</strong> override them.
However, they can override system properties set from a file instead, see <a href="#specifying-properties-in-file">specifying system properties in a file</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect4">
<h5 id="specifying-properties-in-pom"><a class="anchor" href="#specifying-properties-in-pom"></a><a class="link" href="#specifying-properties-in-pom">Specifying System Properties in the POM</a></h5>
<div class="paragraph">
<p>Here&#8217;s an example of how to specify System properties in the POM:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;systemProperties&gt;</span>
<span class="tag">&lt;fooprop&gt;</span>222<span class="tag">&lt;/fooprop&gt;</span>
<span class="tag">&lt;/systemProperties&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/test<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="specifying-properties-in-file"><a class="anchor" href="#specifying-properties-in-file"></a><a class="link" href="#specifying-properties-in-file">Specifying System Properties in a File</a></h5>
<div class="paragraph">
<p>You can also specify your System properties in a file.
System properties you specify in this way <strong>do not</strong> override System properties that set on the command line, by the JVM, or directly in the POM via <code>systemProperties</code>.</p>
</div>
<div class="paragraph">
<p>Suppose we have a file called <code>mysys.props</code> which contains the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>fooprop=222</pre>
</div>
</div>
<div class="paragraph">
<p>This can be configured on the plugin like so:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;systemPropertiesFile&gt;</span>${project.basedir}/mysys.props<span class="tag">&lt;/systemPropertiesFile&gt;</span>
<span class="tag">&lt;webApp&gt;</span>
<span class="tag">&lt;contextPath&gt;</span>/test<span class="tag">&lt;/contextPath&gt;</span>
<span class="tag">&lt;/webApp&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>You can instead specify the file by setting the System property <code>jetty.systemPropertiesFile</code> on the command line.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="jetty-jspc-maven-plugin"><a class="anchor" href="#jetty-jspc-maven-plugin"></a><a class="link" href="#jetty-jspc-maven-plugin">Jetty Jspc Maven Plugin</a></h3>
<div class="paragraph">
<p>This plugin will help you pre-compile your jsps and works in conjunction with the Maven war plugin to put them inside an assembled war.</p>
</div>
<div class="sect3">
<h4 id="jspc-config"><a class="anchor" href="#jspc-config"></a><a class="link" href="#jspc-config">Configuration</a></h4>
<div class="paragraph">
<p>Here&#8217;s the basic setup required to put the jspc plugin into your build:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-jspc-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;executions&gt;</span>
<span class="tag">&lt;execution&gt;</span>
<span class="tag">&lt;id&gt;</span>jspc<span class="tag">&lt;/id&gt;</span>
<span class="tag">&lt;goals&gt;</span>
<span class="tag">&lt;goal&gt;</span>jspc<span class="tag">&lt;/goal&gt;</span>
<span class="tag">&lt;/goals&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;/executions&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The configurable parameters are as follows:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">webXmlFragment</dt>
<dd>
<p>Default value: <code>$\{project.basedir}/target/webfrag.xml</code></p>
<div class="paragraph">
<p>File into which to generate the servlet declarations.
Will be merged with an existing <code>web.xml</code>.</p>
</div>
</dd>
<dt class="hdlist1">webAppSourceDirectory</dt>
<dd>
<p>Default value: <code>$\{project.basedir}/src/main/webapp</code></p>
<div class="paragraph">
<p>Root of resources directory where jsps, tags etc are located.</p>
</div>
</dd>
<dt class="hdlist1">webXml</dt>
<dd>
<p>Default value: <code>$\{project.basedir}/src/main/webapp/WEB-INF/web.xml</code></p>
<div class="paragraph">
<p>The web.xml file to use to merge with the generated fragments.</p>
</div>
</dd>
<dt class="hdlist1">includes</dt>
<dd>
<p>Default value: <code><strong>\/<strong>.jsp, </strong>\/</strong>.jspx</code></p>
<div class="paragraph">
<p>The comma separated list of patterns for file extensions to be processed.</p>
</div>
</dd>
<dt class="hdlist1">excludes</dt>
<dd>
<p>Default value: <code><strong>\/.svn\/</strong></code></p>
<div class="paragraph">
<p>The comma separated list of patterns for file extensions to be skipped.</p>
</div>
</dd>
<dt class="hdlist1">classesDirectory</dt>
<dd>
<p>Default value: <code>$\{project.build.outputDirectory}</code></p>
<div class="paragraph">
<p>Location of classes for the webapp.</p>
</div>
</dd>
<dt class="hdlist1">generatedClasses</dt>
<dd>
<p>Default value: <code>$\{project.build.outputDirectory}</code></p>
<div class="paragraph">
<p>Location to put the generated classes for the jsps.</p>
</div>
</dd>
<dt class="hdlist1">insertionMarker</dt>
<dd>
<p>Default value: <em>none</em></p>
<div class="paragraph">
<p>A marker string in the src <code>web.xml</code> file which indicates where to merge in the generated web.xml fragment.
Note that the marker string will NOT be preserved during the insertion.
Can be left blank, in which case the generated fragment is inserted just before the line containing <code>&lt;/web-app&gt;</code>.</p>
</div>
</dd>
<dt class="hdlist1">useProvidedScope</dt>
<dd>
<p>Default value: false</p>
<div class="paragraph">
<p>If true, jars of dependencies marked with &lt;scope&gt;provided&lt;/scope&gt; will be placed on the compilation classpath.</p>
</div>
</dd>
<dt class="hdlist1">mergeFragment</dt>
<dd>
<p>Default value: true</p>
<div class="paragraph">
<p>Whether or not to merge the generated fragment file with the source web.xml.
The merged file will go into the same directory as the webXmlFragment.</p>
</div>
</dd>
<dt class="hdlist1">keepSources</dt>
<dd>
<p>Default value: false</p>
<div class="paragraph">
<p>If true, the generated .java files are not deleted at the end of processing.</p>
</div>
</dd>
<dt class="hdlist1">scanAllDirectories</dt>
<dd>
<p>Default value: true</p>
<div class="paragraph">
<p>Determines if dirs on the classpath should be scanned as well as jars.
If true, this allows scanning for tlds of dependent projects that
are in the reactor as unassembled jars.</p>
</div>
</dd>
<dt class="hdlist1">scanManifest</dt>
<dd>
<p>Default value: true</p>
<div class="paragraph">
<p>Determines if the manifest of JAR files found on the classpath should be scanned.</p>
</div>
</dd>
<dt class="hdlist1">sourceVersion</dt>
<dd>
<p>Introduced in Jetty 9.3.6.
Java version of jsp source files.
Defaults to 1.7.</p>
</dd>
<dt class="hdlist1">targetVersion</dt>
<dd>
<p>Introduced in Jetty 9.3.6.
Java version of class files generated from jsps.
Defaults to 1.7.</p>
</dd>
<dt class="hdlist1">tldJarNamePatterns</dt>
<dd>
<p>Default value: <code>.<strong>taglibs[<sup>/]</strong>\.jar|.<strong>jstl-impl[</sup>/]</strong>\.jar$</code></p>
<div class="paragraph">
<p>Patterns of jars on the 'system' (ie container) path that contain tlds.
Use | to separate each pattern.</p>
</div>
</dd>
<dt class="hdlist1">jspc</dt>
<dd>
<p>Default value: the <code>org.apache.jasper.JspC</code> instance being configured.</p>
<div class="paragraph">
<p>The JspC class actually performs the pre-compilation.
All setters on the JspC class are available.
You can download the javadoc <a href="https://repo1.maven.org/maven2/org/glassfish/web/javax.servlet.jsp/2.3.2/javax.servlet.jsp-2.3.2-javadoc.jar">here</a>.</p>
</div>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Taking all the default settings, here&#8217;s how to configure the war plugin to use the generated <code>web.xml</code> that includes all of the jsp servlet declarations:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>maven-war-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;webXml&gt;</span>${project.basedir}/target/web.xml<span class="tag">&lt;/webXml&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="jspc-production-precompile"><a class="anchor" href="#jspc-production-precompile"></a><a class="link" href="#jspc-production-precompile">Precompiling only for Production Build</a></h4>
<div class="paragraph">
<p>As compiling jsps is usually done during preparation for a production release and not usually done during development, it is more convenient to put the plugin setup inside a &lt;profile&gt; which which can be deliberately invoked during prep for production.</p>
</div>
<div class="paragraph">
<p>For example, the following profile will only be invoked if the flag <code>-Dprod</code> is present on the run line:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;profiles&gt;</span>
<span class="tag">&lt;profile&gt;</span>
<span class="tag">&lt;id&gt;</span>prod<span class="tag">&lt;/id&gt;</span>
<span class="tag">&lt;activation&gt;</span>
<span class="tag">&lt;property&gt;</span><span class="tag">&lt;name&gt;</span>prod<span class="tag">&lt;/name&gt;</span><span class="tag">&lt;/property&gt;</span>
<span class="tag">&lt;/activation&gt;</span>
<span class="tag">&lt;build&gt;</span>
<span class="tag">&lt;plugins&gt;</span>
<span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-jspc-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="comment">&lt;!-- put your configuration in here --&gt;</span>
<span class="tag">&lt;/plugin&gt;</span>
<span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>maven-war-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="comment">&lt;!-- put your configuration in here --&gt;</span>
<span class="tag">&lt;/plugin&gt;</span>
<span class="tag">&lt;/plugins&gt;</span>
<span class="tag">&lt;/build&gt;</span>
<span class="tag">&lt;/profile&gt;</span>
<span class="tag">&lt;/profiles&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The following invocation would cause your code to be compiled, the jsps to be compiled, the &lt;servlet&gt; and &lt;servlet-mapping&gt;s inserted in the <code>web.xml</code> and your webapp assembled into a war:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>$ mvn -Dprod package</pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="jspc-overlay-precompile"><a class="anchor" href="#jspc-overlay-precompile"></a><a class="link" href="#jspc-overlay-precompile">Precompiling Jsps with Overlaid Wars</a></h4>
<div class="paragraph">
<p>Precompiling jsps with an overlaid war requires a bit more configuration.
This is because you need to separate the steps of unpacking the overlaid war and then repacking the final target war so the jetty-jspc-maven-plugin has the opportunity to access the overlaid resources.</p>
</div>
<div class="paragraph">
<p>In the example we&#8217;ll show, we will use an overlaid war.
The overlaid war will provide the <code>web.xml</code> file but the jsps will be in <code>src/main/webapp</code> (i.e. part of the project that uses the overlay).
We will unpack the overlaid war file, compile the jsps and merge their servlet definitions into the extracted <code>web.xml</code>, then pack everything into a war.</p>
</div>
<div class="paragraph">
<p>Here&#8217;s an example configuration of the war plugin that separate those phases into an unpack phase, and then a packing phase:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>maven-war-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;executions&gt;</span>
<span class="tag">&lt;execution&gt;</span>
<span class="tag">&lt;id&gt;</span>unpack<span class="tag">&lt;/id&gt;</span>
<span class="tag">&lt;goals&gt;</span><span class="tag">&lt;goal&gt;</span>exploded<span class="tag">&lt;/goal&gt;</span><span class="tag">&lt;/goals&gt;</span>
<span class="tag">&lt;phase&gt;</span>generate-resources<span class="tag">&lt;/phase&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;webappDirectory&gt;</span>target/foo<span class="tag">&lt;/webappDirectory&gt;</span>
<span class="tag">&lt;overlays&gt;</span>
<span class="tag">&lt;overlay</span> <span class="tag">/&gt;</span>
<span class="tag">&lt;overlay&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty.demos<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>demo-jetty-webapp<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;/overlay&gt;</span>
<span class="tag">&lt;/overlays&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;execution&gt;</span>
<span class="tag">&lt;id&gt;</span>pack<span class="tag">&lt;/id&gt;</span>
<span class="tag">&lt;goals&gt;</span><span class="tag">&lt;goal&gt;</span>war<span class="tag">&lt;/goal&gt;</span><span class="tag">&lt;/goals&gt;</span>
<span class="tag">&lt;phase&gt;</span>package<span class="tag">&lt;/phase&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;warSourceDirectory&gt;</span>target/foo<span class="tag">&lt;/warSourceDirectory&gt;</span>
<span class="tag">&lt;webXml&gt;</span>target/web.xml<span class="tag">&lt;/webXml&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;/executions&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Now you also need to configure the <code>jetty-jspc-maven-plugin</code> so that it can use the web.xml that was extracted by the war unpacking and merge in the generated definitions of the servlets.
This is in <code>target/foo/WEB-INF/web.xml</code>.
Using the default settings, the <code>web.xml</code> merged with the jsp servlet definitions will be put into <code>target/web.xml</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;plugin&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-jspc-maven-plugin<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>{VERSION}<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;executions&gt;</span>
<span class="tag">&lt;execution&gt;</span>
<span class="tag">&lt;id&gt;</span>jspc<span class="tag">&lt;/id&gt;</span>
<span class="tag">&lt;goals&gt;</span>
<span class="tag">&lt;goal&gt;</span>jspc<span class="tag">&lt;/goal&gt;</span>
<span class="tag">&lt;/goals&gt;</span>
<span class="tag">&lt;configuration&gt;</span>
<span class="tag">&lt;webXml&gt;</span>target/foo/WEB-INF/web.xml<span class="tag">&lt;/webXml&gt;</span>
<span class="tag">&lt;includes&gt;</span>**/*.foo<span class="tag">&lt;/includes&gt;</span>
<span class="tag">&lt;excludes&gt;</span>**/*.fff<span class="tag">&lt;/excludes&gt;</span>
<span class="tag">&lt;/configuration&gt;</span>
<span class="tag">&lt;/execution&gt;</span>
<span class="tag">&lt;/executions&gt;</span>
<span class="tag">&lt;/plugin&gt;</span></code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="pg-arch"><a class="anchor" href="#pg-arch"></a><a class="link" href="#pg-arch">Appendix A: Jetty Architecture</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="pg-arch-bean"><a class="anchor" href="#pg-arch-bean"></a><a class="link" href="#pg-arch-bean">Jetty Component Architecture</a></h3>
<div class="paragraph">
<p>Applications that use the Jetty libraries (both client and server) create objects from Jetty classes and compose them together to obtain the desired functionalities.</p>
</div>
<div class="paragraph">
<p>A client application creates a <code>ClientConnector</code> instance, a <code>HttpClientTransport</code> instance and an <code>HttpClient</code> instance and compose them to have a working HTTP client that uses to call third party services.</p>
</div>
<div class="paragraph">
<p>A server application creates a <code>ThreadPool</code> instance, a <code>Server</code> instance, a <code>ServerConnector</code> instance, a <code>Handler</code> instance and compose them together to expose an HTTP service.</p>
</div>
<div class="paragraph">
<p>Internally, the Jetty libraries create even more instances of other components that also are composed together with the main ones created by applications.</p>
</div>
<div class="paragraph">
<p>The end result is that an application based on the Jetty libraries is a <em>tree</em> of components.
In server application the root of the component tree is a <code>Server</code> instance, while in client applications the root of the component tree is an <code>HttpClient</code> instance.</p>
</div>
<div class="paragraph">
<p>Having all the Jetty components in a tree is beneficial in a number of use cases.
It makes possible to register the components in the tree as <a href="#pg-arch-jmx">JMX MBeans</a> so that a JMX console can look at the internal state of the components.
It also makes possible to <a href="#pg-troubleshooting-component-dump">dump the component tree</a> (and therefore each component&#8217;s internal state) to a log file or to the console for <a href="#pg-troubleshooting">troubleshooting purposes</a>.</p>
</div>
<div class="sect3">
<h4 id="pg-arch-bean-lifecycle"><a class="anchor" href="#pg-arch-bean-lifecycle"></a><a class="link" href="#pg-arch-bean-lifecycle">Jetty Component Lifecycle</a></h4>
<div class="paragraph">
<p>Jetty components typically have a life cycle: they can be started and stopped.
The Jetty components that have a life cycle implement the <code>org.eclipse.jetty.util.component.LifeCycle</code> interface.</p>
</div>
<div class="paragraph">
<p>Jetty components that contain other components implement the <code>org.eclipse.jetty.util.component.Container</code> interface and typically extend the <code>org.eclipse.jetty.util.component.ContainerLifeCycle</code> class.
<code>ContainerLifeCycle</code> can contain these type of components, also called <em>bean</em>s:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>managed</em> beans, <code>LifeCycle</code> instances whose life cycle is tied to the life cycle of their container</p>
</li>
<li>
<p><em>unmanaged</em> beans, <code>LifeCycle</code> instances whose life cycle is <em>not</em> tied to the life cycle of their container</p>
</li>
<li>
<p><em>POJO</em> (Plain Old Java Object) beans, instances that do not implement <code>LifeCycle</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>ContainerLifeCycle</code> uses the following logic to determine if a bean should be <em>managed</em>, <em>unmanaged</em> or <em>POJO</em>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the bean implements <code>LifeCycle</code></p>
<div class="ulist">
<ul>
<li>
<p>the bean is not started, add it as <em>managed</em></p>
</li>
<li>
<p>the bean is started, add it as <em>unmanaged</em></p>
</li>
</ul>
</div>
</li>
<li>
<p>the bean does not implement <code>LifeCycle</code>, add it as <em>POJO</em></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>When a <code>ContainerLifeCycle</code> is started, it also starts recursively all its managed beans (if they implement <code>LifeCycle</code>); unmanaged beans are not started during the <code>ContainerLifeCycle</code> start cycle.
Likewise, stopping a <code>ContainerLifeCycle</code> stops recursively and in reverse order all its managed beans; unmanaged beans are not stopped during the <code>ContainerLifeCycle</code> stop cycle.</p>
</div>
<div class="paragraph">
<p>Components can also be started and stopped individually, therefore activating or deactivating the functionalities that they offer.</p>
</div>
<div class="paragraph">
<p>Applications should first compose components in the desired structure, and then start the root component:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">Monitor</span> <span class="directive">extends</span> AbstractLifeCycle
{
}
<span class="type">class</span> <span class="class">Root</span> <span class="directive">extends</span> ContainerLifeCycle
{
<span class="comment">// Monitor is an internal component.</span>
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">Monitor</span> monitor = <span class="keyword">new</span> <span class="predefined-type">Monitor</span>();
<span class="directive">public</span> Root()
{
<span class="comment">// The Monitor life cycle is managed by Root.</span>
addManaged(monitor);
}
}
<span class="type">class</span> <span class="class">Service</span> <span class="directive">extends</span> ContainerLifeCycle
{
<span class="comment">// An instance of the Java scheduler service.</span>
<span class="directive">private</span> <span class="predefined-type">ScheduledExecutorService</span> scheduler;
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> doStart() <span class="directive">throws</span> <span class="exception">Exception</span>
{
<span class="comment">// Java's schedulers cannot be restarted, so they must</span>
<span class="comment">// be created anew every time their container is started.</span>
scheduler = <span class="predefined-type">Executors</span>.newSingleThreadScheduledExecutor();
<span class="comment">// Even if Java scheduler does not implement</span>
<span class="comment">// LifeCycle, make it part of the component tree.</span>
addBean(scheduler);
<span class="comment">// Start all the children beans.</span>
<span class="local-variable">super</span>.doStart();
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> doStop() <span class="directive">throws</span> <span class="exception">Exception</span>
{
<span class="comment">// Perform the opposite operations that were</span>
<span class="comment">// performed in doStart(), in reverse order.</span>
<span class="local-variable">super</span>.doStop();
removeBean(scheduler);
scheduler.shutdown();
}
}
<span class="comment">// Create a Root instance.</span>
Root root = <span class="keyword">new</span> Root();
<span class="comment">// Create a Service instance.</span>
Service service = <span class="keyword">new</span> Service();
<span class="comment">// Link the components.</span>
root.addBean(service);
<span class="comment">// Start the root component to</span>
<span class="comment">// start the whole component tree.</span>
root.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The component tree is the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">Root
├── Monitor (MANAGED)
└── Service (MANAGED)
└── ScheduledExecutorService (POJO)</code></pre>
</div>
</div>
<div class="paragraph">
<p>When the <code>Root</code> instance is created, also the <code>Monitor</code> instance is created and added as bean, so <code>Monitor</code> is the first bean of <code>Root</code>.
<code>Monitor</code> is a <em>managed</em> bean, because it has been explicitly added to <code>Root</code> via <code>ContainerLifeCycle.addManaged(&#8230;&#8203;)</code>.</p>
</div>
<div class="paragraph">
<p>Then, the application creates a <code>Service</code> instance and adds it to <code>Root</code> via <code>ContainerLifeCycle.addBean(&#8230;&#8203;)</code>, so <code>Service</code> is the second bean of <code>Root</code>.
<code>Service</code> is a <em>managed</em> bean too, because it is a <code>LifeCycle</code> and at the time it was added to <code>Root</code> is was not started.</p>
</div>
<div class="paragraph">
<p>The <code>ScheduledExecutorService</code> within <code>Service</code> does not implement <code>LifeCycle</code> so it is added as a <em>POJO</em> to <code>Service</code>.</p>
</div>
<div class="paragraph">
<p>It is possible to stop and re-start any component in a tree, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">Root</span> <span class="directive">extends</span> ContainerLifeCycle
{
}
<span class="type">class</span> <span class="class">Service</span> <span class="directive">extends</span> ContainerLifeCycle
{
<span class="comment">// An instance of the Java scheduler service.</span>
<span class="directive">private</span> <span class="predefined-type">ScheduledExecutorService</span> scheduler;
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> doStart() <span class="directive">throws</span> <span class="exception">Exception</span>
{
<span class="comment">// Java's schedulers cannot be restarted, so they must</span>
<span class="comment">// be created anew every time their container is started.</span>
scheduler = <span class="predefined-type">Executors</span>.newSingleThreadScheduledExecutor();
<span class="comment">// Even if Java scheduler does not implement</span>
<span class="comment">// LifeCycle, make it part of the component tree.</span>
addBean(scheduler);
<span class="comment">// Start all the children beans.</span>
<span class="local-variable">super</span>.doStart();
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> doStop() <span class="directive">throws</span> <span class="exception">Exception</span>
{
<span class="comment">// Perform the opposite operations that were</span>
<span class="comment">// performed in doStart(), in reverse order.</span>
<span class="local-variable">super</span>.doStop();
removeBean(scheduler);
scheduler.shutdown();
}
}
Root root = <span class="keyword">new</span> Root();
Service service = <span class="keyword">new</span> Service();
root.addBean(service);
<span class="comment">// Start the Root component.</span>
root.start();
<span class="comment">// Stop temporarily Service without stopping the Root.</span>
service.stop();
<span class="comment">// Restart Service.</span>
service.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>Service</code> can be stopped independently of <code>Root</code>, and re-started.
Starting and stopping a non-root component does not alter the structure of the component tree, just the state of the subtree starting from the component that has been stopped and re-started.</p>
</div>
<div class="paragraph">
<p><code>Container</code> provides an API to find beans in the component tree:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">Root</span> <span class="directive">extends</span> ContainerLifeCycle
{
}
<span class="type">class</span> <span class="class">Service</span> <span class="directive">extends</span> ContainerLifeCycle
{
<span class="directive">private</span> <span class="predefined-type">ScheduledExecutorService</span> scheduler;
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> doStart() <span class="directive">throws</span> <span class="exception">Exception</span>
{
scheduler = <span class="predefined-type">Executors</span>.newSingleThreadScheduledExecutor();
addBean(scheduler);
<span class="local-variable">super</span>.doStart();
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> doStop() <span class="directive">throws</span> <span class="exception">Exception</span>
{
<span class="local-variable">super</span>.doStop();
removeBean(scheduler);
scheduler.shutdown();
}
}
Root root = <span class="keyword">new</span> Root();
Service service = <span class="keyword">new</span> Service();
root.addBean(service);
<span class="comment">// Start the Root component.</span>
root.start();
<span class="comment">// Find all the direct children of root.</span>
<span class="predefined-type">Collection</span>&lt;<span class="predefined-type">Object</span>&gt; children = root.getBeans();
<span class="comment">// children contains only service</span>
<span class="comment">// Find all descendants of root that are instance of a particular class.</span>
<span class="predefined-type">Collection</span>&lt;<span class="predefined-type">ScheduledExecutorService</span>&gt; schedulers = root.getContainedBeans(<span class="predefined-type">ScheduledExecutorService</span>.class);
<span class="comment">// schedulers contains the service scheduler.</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>You can add your own beans to the component tree at application startup time, and later find them from your application code to access their services.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The component tree should be used for long-lived or medium-lived components such as thread pools, web application contexts, etc.</p>
</div>
<div class="paragraph">
<p>It is not recommended adding to, and removing from, the component tree short-lived objects such as HTTP requests or TCP connections, for performance reasons.</p>
</div>
<div class="paragraph">
<p>If you need component tree features such as automatic <a href="#pg-arch-jmx">export to JMX</a> or <a href="#pg-troubleshooting-component-dump">dump capabilities</a> for short-lived objects, consider having a long-lived container in the component tree instead.
You can make the long-lived container efficient at adding/removing the short-lived components using a data structure that is not part of the component tree, and make the long-lived container handle the JMX and dump features for the short-lived components.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="pg-arch-bean-listener"><a class="anchor" href="#pg-arch-bean-listener"></a><a class="link" href="#pg-arch-bean-listener">Jetty Component Listeners</a></h4>
<div class="paragraph">
<p>A component that extends <code>AbstractLifeCycle</code> inherits the possibility to add/remove event <em>listeners</em> for various events emitted by components.</p>
</div>
<div class="paragraph">
<p>A component that implements <code>java.util.EventListener</code> that is added to a <code>ContainerLifeCycle</code> is also registered as an event listener.</p>
</div>
<div class="paragraph">
<p>The following sections describe in details the various listeners available in the Jetty component architecture.</p>
</div>
<div class="sect4">
<h5 id="pg-arch-bean-listener-lifecycle"><a class="anchor" href="#pg-arch-bean-listener-lifecycle"></a><a class="link" href="#pg-arch-bean-listener-lifecycle">LifeCycle.Listener</a></h5>
<div class="paragraph">
<p>A <code>LifeCycle.Listener</code> emits events for life cycle events such as starting, stopping and failures:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Add an event listener of type LifeCycle.Listener.</span>
server.addEventListener(<span class="keyword">new</span> LifeCycle.Listener()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> lifeCycleStarted(LifeCycle lifeCycle)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">server</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Server {0} has been started</span><span class="delimiter">&quot;</span></span>, lifeCycle);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> lifeCycleFailure(LifeCycle lifeCycle, <span class="predefined-type">Throwable</span> failure)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">server</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Server {0} failed to start</span><span class="delimiter">&quot;</span></span>, lifeCycle, failure);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> lifeCycleStopped(LifeCycle lifeCycle)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">server</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Server {0} has been stopped</span><span class="delimiter">&quot;</span></span>, lifeCycle);
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>For example, a life cycle listener attached to a <code>Server</code> instance could be used to create (for the <em>started</em> event) and delete (for the <em>stopped</em> event) a file containing the process ID of the JVM that runs the <code>Server</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-arch-bean-listener-container"><a class="anchor" href="#pg-arch-bean-listener-container"></a><a class="link" href="#pg-arch-bean-listener-container">Container.Listener</a></h5>
<div class="paragraph">
<p>A component that implements <code>Container</code> is a container for other components and <code>ContainerLifeCycle</code> is the typical implementation.</p>
</div>
<div class="paragraph">
<p>A <code>Container</code> emits events when a component (also called <em>bean</em>) is added to or removed from the container:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Add an event listener of type LifeCycle.Listener.</span>
server.addEventListener(<span class="keyword">new</span> <span class="predefined-type">Container</span>.Listener()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> beanAdded(<span class="predefined-type">Container</span> parent, <span class="predefined-type">Object</span> child)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">server</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Added bean {1} to {0}</span><span class="delimiter">&quot;</span></span>, parent, child);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> beanRemoved(<span class="predefined-type">Container</span> parent, <span class="predefined-type">Object</span> child)
{
<span class="predefined-type">System</span>.getLogger(<span class="string"><span class="delimiter">&quot;</span><span class="content">server</span><span class="delimiter">&quot;</span></span>).log(INFO, <span class="string"><span class="delimiter">&quot;</span><span class="content">Removed bean {1} from {0}</span><span class="delimiter">&quot;</span></span>, parent, child);
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>A <code>Container.Listener</code> added as a bean will also be registered as a listener:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">Parent</span> <span class="directive">extends</span> ContainerLifeCycle
{
}
<span class="type">class</span> <span class="class">Child</span>
{
}
<span class="comment">// The older child takes care of its siblings.</span>
<span class="type">class</span> <span class="class">OlderChild</span> <span class="directive">extends</span> Child <span class="directive">implements</span> <span class="predefined-type">Container</span>.Listener
{
<span class="directive">private</span> <span class="predefined-type">Set</span>&lt;<span class="predefined-type">Object</span>&gt; siblings = <span class="keyword">new</span> <span class="predefined-type">HashSet</span>&lt;&gt;();
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> beanAdded(<span class="predefined-type">Container</span> parent, <span class="predefined-type">Object</span> child)
{
siblings.add(child);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> beanRemoved(<span class="predefined-type">Container</span> parent, <span class="predefined-type">Object</span> child)
{
siblings.remove(child);
}
}
Parent parent = <span class="keyword">new</span> Parent();
Child older = <span class="keyword">new</span> OlderChild();
<span class="comment">// The older child is a child bean _and_ a listener.</span>
parent.addBean(older);
Child younger = <span class="keyword">new</span> Child();
<span class="comment">// Adding a younger child will notify the older child.</span>
parent.addBean(younger);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="pg-arch-bean-listener-inherited"><a class="anchor" href="#pg-arch-bean-listener-inherited"></a><a class="link" href="#pg-arch-bean-listener-inherited">Container.InheritedListener</a></h5>
<div class="paragraph">
<p>A <code>Container.InheritedListener</code> is a listener that will be added to all descendants that are also <code>Container</code>s.</p>
</div>
<div class="paragraph">
<p>Listeners of this type may be added to the component tree root only, but will be notified of every descendant component that is added to or removed from the component tree (not only first level children).</p>
</div>
<div class="paragraph">
<p>The primary use of <code>Container.InheritedListener</code> within the Jetty Libraries is <code>MBeanContainer</code> from the <a href="#pg-arch-jmx">Jetty JMX support</a>.</p>
</div>
<div class="paragraph">
<p><code>MBeanContainer</code> listens for every component added to the tree, converts it to an MBean and registers it to the MBeanServer; for every component removed from the tree, it unregisters the corresponding MBean from the MBeanServer.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-arch-io"><a class="anchor" href="#pg-arch-io"></a><a class="link" href="#pg-arch-io">Jetty I/O Architecture</a></h3>
<div class="paragraph">
<p>Jetty libraries (both client and server) use Java NIO to handle I/O, so that at its core Jetty I/O is completely non-blocking.</p>
</div>
<div class="sect3">
<h4 id="pg-arch-io-selector-manager"><a class="anchor" href="#pg-arch-io-selector-manager"></a><a class="link" href="#pg-arch-io-selector-manager">Jetty I/O: <code>SelectorManager</code></a></h4>
<div class="paragraph">
<p>The core class of Jetty I/O is <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/SelectorManager.html"><code>SelectorManager</code></a>.</p>
</div>
<div class="paragraph">
<p><code>SelectorManager</code> manages internally a configurable number of <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/ManagedSelector.html"><code>ManagedSelector</code></a>s.
Each <code>ManagedSelector</code> wraps an instance of <code>java.nio.channels.Selector</code> that in turn manages a number of <code>java.nio.channels.SocketChannel</code> instances.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
TODO: add image
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>SocketChannel</code> instances can be created by network clients when connecting to a server and by a network server when accepting connections from network clients.
In both cases the <code>SocketChannel</code> instance is passed to <code>SelectorManager</code> (which passes it to <code>ManagedSelector</code> and eventually to <code>java.nio.channels.Selector</code>) to be registered for use within Jetty.</p>
</div>
<div class="paragraph">
<p>It is possible for an application to create the <code>SocketChannel</code> instances outside Jetty, even perform some initial network traffic also outside Jetty (for example for authentication purposes), and then pass the <code>SocketChannel</code> instance to <code>SelectorManager</code> for use within Jetty.</p>
</div>
<div class="paragraph">
<p>This example shows how a client can connect to a server:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">void</span> connect(SelectorManager selectorManager, <span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; context) <span class="directive">throws</span> <span class="exception">IOException</span>
{
<span class="predefined-type">String</span> host = <span class="string"><span class="delimiter">&quot;</span><span class="content">host</span><span class="delimiter">&quot;</span></span>;
<span class="type">int</span> port = <span class="integer">8080</span>;
<span class="comment">// Create an unconnected SocketChannel.</span>
<span class="predefined-type">SocketChannel</span> socketChannel = <span class="predefined-type">SocketChannel</span>.open();
socketChannel.configureBlocking(<span class="predefined-constant">false</span>);
<span class="comment">// Connect and register to Jetty.</span>
<span class="keyword">if</span> (socketChannel.connect(<span class="keyword">new</span> <span class="predefined-type">InetSocketAddress</span>(host, port)))
selectorManager.accept(socketChannel, context);
<span class="keyword">else</span>
selectorManager.connect(socketChannel, context);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This example shows how a server accepts a client connection:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">void</span> accept(<span class="predefined-type">ServerSocketChannel</span> acceptor, SelectorManager selectorManager) <span class="directive">throws</span> <span class="exception">IOException</span>
{
<span class="comment">// Wait until a client connects.</span>
<span class="predefined-type">SocketChannel</span> socketChannel = acceptor.accept();
socketChannel.configureBlocking(<span class="predefined-constant">false</span>);
<span class="comment">// Accept and register to Jetty.</span>
<span class="predefined-type">Object</span> attachment = <span class="predefined-constant">null</span>;
selectorManager.accept(socketChannel, attachment);
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-arch-io-endpoint-connection"><a class="anchor" href="#pg-arch-io-endpoint-connection"></a><a class="link" href="#pg-arch-io-endpoint-connection">Jetty I/O: <code>EndPoint</code> and <code>Connection</code></a></h4>
<div class="paragraph">
<p><code>SocketChannel</code>s that are passed to <code>SelectorManager</code> are wrapped into two related components: an <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/EndPoint.html"><code>EndPoint</code></a> and a <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/Connection.html"><code>Connection</code></a>.</p>
</div>
<div class="paragraph">
<p><code>EndPoint</code> is the Jetty abstraction for a <code>SocketChannel</code>: you can read bytes from an <code>EndPoint</code> via <code>EndPoint.fill(ByteBuffer)</code>, you can write bytes to an <code>EndPoint</code> via <code>EndPoint.flush(ByteBuffer&#8230;&#8203;)</code> and <code>EndPoint.write(Callback, ByteBuffer&#8230;&#8203;)</code>, you can close an <code>EndPoint</code> via <code>EndPoint.close()</code>, etc.</p>
</div>
<div class="paragraph">
<p><code>Connection</code> is the Jetty abstraction that is responsible to read bytes from the <code>EndPoint</code> and to deserialize the read bytes into objects.
For example, an HTTP/1.1 server-side <code>Connection</code> implementation is responsible to deserialize HTTP/1.1 request bytes into an HTTP request object.
Conversely, an HTTP/1.1 client-side <code>Connection</code> implementation is responsible to deserialize HTTP/1.1 response bytes into an HTTP response object.</p>
</div>
<div class="paragraph">
<p><code>Connection</code> is the abstraction that implements the reading side of a specific protocol such as HTTP/1.1, or HTTP/2, or WebSocket: it is able to read incoming communication in that protocol.</p>
</div>
<div class="paragraph">
<p>The writing side for a specific protocol <em>may</em> be implemented in the <code>Connection</code> but may also be implemented in other components, although eventually the bytes to be written will be written through the <code>EndPoint</code>.</p>
</div>
<div class="paragraph">
<p>While there is primarily just one implementation of <code>EndPoint</code>,<a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/SocketChannelEndPoint.html"><code>SocketChannelEndPoint</code></a> (used both on the client-side and on the server-side), there are many implementations of <code>Connection</code>, typically two for each protocol (one for the client-side and one for the server-side).</p>
</div>
<div class="paragraph">
<p>The <code>EndPoint</code> and <code>Connection</code> pairs can be chained, for example in case of encrypted communication using the TLS protocol.
There is an <code>EndPoint</code> and <code>Connection</code> TLS pair where the <code>EndPoint</code> reads the encrypted bytes from the network and the <code>Connection</code> decrypts them; next in the chain there is an <code>EndPoint</code> and <code>Connection</code> pair where the <code>EndPoint</code> "reads" decrypted bytes (provided by the previous <code>Connection</code>) and the <code>Connection</code> deserializes them into specific protocol objects (for example HTTP/2 frame objects).</p>
</div>
<div class="paragraph">
<p>Certain protocols, such as WebSocket, start the communication with the server using one protocol (e.g. HTTP/1.1), but then change the communication to use another protocol (e.g. WebSocket).
<code>EndPoint</code> supports changing the <code>Connection</code> object on-the-fly via <code>EndPoint.upgrade(Connection)</code>.
This allows to use the HTTP/1.1 <code>Connection</code> during the initial communication and later to replace it with a WebSocket <code>Connection</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
TODO: add a section on <code>UpgradeFrom</code> and <code>UpgradeTo</code>?
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>SelectorManager</code> is an abstract class because while it knows how to create concrete <code>EndPoint</code> instances, it does not know how to create protocol specific <code>Connection</code> instances.</p>
</div>
<div class="paragraph">
<p>Creating <code>Connection</code> instances is performed on the server-side by <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/ConnectionFactory.html"><code>ConnectionFactory</code></a>s and on the client-side by <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/io/ClientConnectionFactory.html"><code>ClientConnectionFactory</code></a>s</p>
</div>
<div class="paragraph">
<p>On the server-side, the component that aggregates a <code>SelectorManager</code> with a set of <code>ConnectionFactory</code>s is <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/ServerConnector.html"><code>ServerConnector</code></a>s, see <a href="#pg-server-io-arch">Server Libraries I/O Architecture</a>.</p>
</div>
<div class="paragraph">
<p>On the client-side, the components that aggregates a <code>SelectorManager</code> with a set of <code>ClientConnectionFactory</code>s are <a href="https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/client/HttpClientTransport.html"><code>HttpClientTransport</code></a> subclasses, see <a href="#pg-client-io-arch">Client Libraries I/O Architecture</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-arch-io-endpoint"><a class="anchor" href="#pg-arch-io-endpoint"></a><a class="link" href="#pg-arch-io-endpoint">Jetty I/O: <code>EndPoint</code></a></h4>
<div class="paragraph">
<p>The Jetty I/O library use Java NIO to handle I/O, so that I/O is non-blocking.</p>
</div>
<div class="paragraph">
<p>At the Java NIO level, in order to be notified when a <code>SocketChannel</code> has data to be read, the <code>SelectionKey.OP_READ</code> flag must be set.</p>
</div>
<div class="paragraph">
<p>In the Jetty I/O library, you can call <code>EndPoint.fillInterested(Callback)</code> to declare interest in the "read" (or "fill") event, and the <code>Callback</code> parameter is the object that is notified when such an event occurs.</p>
</div>
<div class="paragraph">
<p>At the Java NIO level, a <code>SocketChannel</code> is always writable, unless it becomes TCP congested.
In order to be notified when a <code>SocketChannel</code> uncongests and it is therefore writable again, the <code>SelectionKey.OP_WRITE</code> flag must be set.</p>
</div>
<div class="paragraph">
<p>In the Jetty I/O library, you can call <code>EndPoint.write(Callback, ByteBuffer&#8230;&#8203;)</code> to write the <code>ByteBuffer</code>s and the <code>Callback</code> parameter is the object that is notified when the whole write is finished (i.e. <em>all</em> <code>ByteBuffer</code>s have been fully written, even if they are delayed by TCP congestion/uncongestion).</p>
</div>
<div class="paragraph">
<p>The <code>EndPoint</code> APIs abstract out the Java NIO details by providing non-blocking APIs based on <code>Callback</code> objects for I/O operations.
The <code>EndPoint</code> APIs are typically called by <code>Connection</code> implementations, see <a href="#pg-arch-io-connection">this section</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="pg-arch-io-connection"><a class="anchor" href="#pg-arch-io-connection"></a><a class="link" href="#pg-arch-io-connection">Jetty I/O: <code>Connection</code></a></h4>
<div class="paragraph">
<p><code>Connection</code> is the abstraction that deserializes incoming bytes into objects, for example an HTTP request object or a WebSocket frame object, that can be used by more abstract layers.</p>
</div>
<div class="paragraph">
<p><code>Connection</code> instances have two lifecycle methods:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>Connection.onOpen()</code>, invoked when the <code>Connection</code> is associated with the <code>EndPoint</code></p>
</li>
<li>
<p><code>Connection.onClose(Throwable)</code>, invoked when the <code>Connection</code> is disassociated from the <code>EndPoint</code>, where the <code>Throwable</code> parameter indicates whether the disassociation was normal (when the parameter is <code>null</code>) or was due to an error (when the parameter is not <code>null</code>)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>When a <code>Connection</code> is first created, it is not registered for any Java NIO event.
It is therefore typical to implement <code>onOpen()</code> to call <code>EndPoint.fillInterested(Callback)</code> so that the <code>Connection</code> declares interest for read events and it is invoked (via the <code>Callback</code>) when the read event happens.</p>
</div>
<div class="paragraph">
<p>Abstract class <code>AbstractConnection</code> partially implements <code>Connection</code> and provides simpler APIs.
The example below shows a typical implementation that extends <code>AbstractConnection</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Extend AbstractConnection to inherit basic implementation.</span>
<span class="type">class</span> <span class="class">MyConnection</span> <span class="directive">extends</span> AbstractConnection
{
<span class="directive">public</span> MyConnection(EndPoint endPoint, <span class="predefined-type">Executor</span> executor)
{
<span class="local-variable">super</span>(endPoint, executor);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onOpen()
{
<span class="local-variable">super</span>.onOpen();
<span class="comment">// Declare interest for fill events.</span>
fillInterested();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onFillable()
{
<span class="comment">// Called when a fill event happens.</span>
}
}</code></pre>
</div>
</div>
<div class="sect4">
<h5 id="pg-arch-io-connection-listener"><a class="anchor" href="#pg-arch-io-connection-listener"></a><a class="link" href="#pg-arch-io-connection-listener">Jetty I/O: <code>Connection.Listener</code></a></h5>
<div class="paragraph">
<p>TODO</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-arch-io-echo"><a class="anchor" href="#pg-arch-io-echo"></a><a class="link" href="#pg-arch-io-echo">Jetty I/O: Network Echo</a></h4>
<div class="paragraph">
<p>With the concepts above it is now possible to write a simple, fully non-blocking, <code>Connection</code> implementation that simply echoes the bytes that it reads back to the other peer.</p>
</div>
<div class="paragraph">
<p>A naive, but wrong, implementation may be the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">WrongEchoConnection</span> <span class="directive">extends</span> AbstractConnection <span class="directive">implements</span> <span class="predefined-type">Callback</span>
{
<span class="directive">public</span> WrongEchoConnection(EndPoint endPoint, <span class="predefined-type">Executor</span> executor)
{
<span class="local-variable">super</span>(endPoint, executor);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onOpen()
{
<span class="local-variable">super</span>.onOpen();
<span class="comment">// Declare interest for fill events.</span>
fillInterested();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onFillable()
{
<span class="keyword">try</span>
{
<span class="predefined-type">ByteBuffer</span> buffer = BufferUtil.allocate(<span class="integer">1024</span>);
<span class="type">int</span> filled = getEndPoint().fill(buffer);
<span class="keyword">if</span> (filled &gt; <span class="integer">0</span>)
{
<span class="comment">// Filled some bytes, echo them back.</span>
getEndPoint().write(<span class="local-variable">this</span>, buffer);
}
<span class="keyword">else</span> <span class="keyword">if</span> (filled == <span class="integer">0</span>)
{
<span class="comment">// No more bytes to fill, declare</span>
<span class="comment">// again interest for fill events.</span>
fillInterested();
}
<span class="keyword">else</span>
{
<span class="comment">// The other peer closed the</span>
<span class="comment">// connection, close it back.</span>
getEndPoint().close();
}
}
<span class="keyword">catch</span> (<span class="exception">Exception</span> x)
{
getEndPoint().close(x);
}
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> succeeded()
{
<span class="comment">// The write is complete, fill again.</span>
onFillable();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> failed(<span class="predefined-type">Throwable</span> x)
{
getEndPoint().close(x);
}
}</code></pre>
</div>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
The implementation above is wrong and leads to <code>StackOverflowError</code>.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The problem with this implementation is that if the writes always complete synchronously (i.e. without being delayed by TCP congestion), you end up with this sequence of calls:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>Connection.onFillable()
EndPoint.write()
Connection.succeeded()
Connection.onFillable()
EndPoint.write()
Connection.succeeded()
...</pre>
</div>
</div>
<div class="paragraph">
<p>which leads to <code>StackOverflowError</code>.</p>
</div>
<div class="paragraph">
<p>This is a typical side effect of asynchronous programming using non-blocking APIs, and happens in the Jetty I/O library as well.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The callback is invoked synchronously for efficiency reasons.
Submitting the invocation of the callback to an <code>Executor</code> to be invoked in a different thread would cause a context switch and make simple writes extremely inefficient.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This side effect of asynchronous programming leading to <code>StackOverflowError</code> is so common that the Jetty libraries have a generic solution for it: a specialized <code>Callback</code> implementation named <code>org.eclipse.jetty.util.IteratingCallback</code> that turns recursion into iteration, therefore avoiding the <code>StackOverflowError</code>.</p>
</div>
<div class="paragraph">
<p><code>IteratingCallback</code> is a <code>Callback</code> implementation that should be passed to non-blocking APIs such as <code>EndPoint.write(Callback, ByteBuffer&#8230;&#8203;)</code> when they are performed in a loop.</p>
</div>
<div class="paragraph">
<p><code>IteratingCallback</code> works by starting the loop with <code>IteratingCallback.iterate()</code>.
In turn, this calls <code>IteratingCallback.process()</code>, an abstract method that must be implemented with the code that should be executed for each loop.</p>
</div>
<div class="paragraph">
<p>Method <code>process()</code> must return:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>Action.SCHEDULED</code>, to indicate whether the loop has performed a non-blocking, possibly asynchronous, operation</p>
</li>
<li>
<p><code>Action.IDLE</code>, to indicate that the loop should temporarily be suspended to be resumed later</p>
</li>
<li>
<p><code>Action.SUCCEEDED</code> to indicate that the loop exited successfully</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Any exception thrown within <code>process()</code> exits the loops with a failure.</p>
</div>
<div class="paragraph">
<p>Now that you know how <code>IteratingCallback</code> works, a correct implementation for the echo <code>Connection</code> is the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">class</span> <span class="class">EchoConnection</span> <span class="directive">extends</span> AbstractConnection
{
<span class="directive">private</span> <span class="directive">final</span> IteratingCallback callback = <span class="keyword">new</span> EchoIteratingCallback();
<span class="directive">public</span> EchoConnection(EndPoint endp, <span class="predefined-type">Executor</span> executor)
{
<span class="local-variable">super</span>(endp, executor);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onOpen()
{
<span class="local-variable">super</span>.onOpen();
<span class="comment">// Declare interest for fill events.</span>
fillInterested();
}
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> onFillable()
{
<span class="comment">// Start the iteration loop that reads and echoes back.</span>
callback.iterate();
}
<span class="type">class</span> <span class="class">EchoIteratingCallback</span> <span class="directive">extends</span> IteratingCallback
{
<span class="directive">private</span> <span class="predefined-type">ByteBuffer</span> buffer;
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="predefined-type">Action</span> process() <span class="directive">throws</span> <span class="predefined-type">Throwable</span>
{
<span class="comment">// Obtain a buffer if we don't already have one.</span>
<span class="keyword">if</span> (buffer == <span class="predefined-constant">null</span>)
buffer = BufferUtil.allocate(<span class="integer">1024</span>);
<span class="type">int</span> filled = getEndPoint().fill(buffer);
<span class="keyword">if</span> (filled &gt; <span class="integer">0</span>)
{
<span class="comment">// We have filled some bytes, echo them back.</span>
getEndPoint().write(<span class="local-variable">this</span>, buffer);
<span class="comment">// Signal that the iteration should resume</span>
<span class="comment">// when the write() operation is completed.</span>
<span class="keyword">return</span> <span class="predefined-type">Action</span>.SCHEDULED;
}
<span class="keyword">else</span> <span class="keyword">if</span> (filled == <span class="integer">0</span>)
{
<span class="comment">// We don't need the buffer anymore, so</span>
<span class="comment">// don't keep it around while we are idle.</span>
buffer = <span class="predefined-constant">null</span>;
<span class="comment">// No more bytes to read, declare</span>
<span class="comment">// again interest for fill events.</span>
fillInterested();
<span class="comment">// Signal that the iteration is now IDLE.</span>
<span class="keyword">return</span> <span class="predefined-type">Action</span>.IDLE;
}
<span class="keyword">else</span>
{
<span class="comment">// The other peer closed the connection,</span>
<span class="comment">// the iteration completed successfully.</span>
<span class="keyword">return</span> <span class="predefined-type">Action</span>.SUCCEEDED;
}
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> onCompleteSuccess()
{
<span class="comment">// The iteration completed successfully.</span>
getEndPoint().close();
}
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> onCompleteFailure(<span class="predefined-type">Throwable</span> cause)
{
<span class="comment">// The iteration completed with a failure.</span>
getEndPoint().close(cause);
}
<span class="annotation">@Override</span>
<span class="directive">public</span> InvocationType getInvocationType()
{
<span class="keyword">return</span> InvocationType.NON_BLOCKING;
}
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>When <code>onFillable()</code> is called, for example the first time that bytes are available from the network, the iteration is started.
Starting the iteration calls <code>process()</code>, where a buffer is allocated and filled with bytes read from the network via <code>EndPoint.fill(ByteBuffer)</code>; the buffer is subsequently written back via <code>EndPoint.write(Callback, ByteBuffer&#8230;&#8203;)</code>&#8201;&#8212;&#8201;note that the callback passed to <code>EndPoint.write()</code> is <code>this</code>, i.e. the <code>IteratingCallback</code> itself; finally <code>Action.SCHEDULED</code> is returned, returning from the <code>process()</code> method.</p>
</div>
<div class="paragraph">
<p>At this point, the call to <code>EndPoint.write(Callback, ByteBuffer&#8230;&#8203;)</code> may have completed synchronously; <code>IteratingCallback</code> would know that and call <code>process()</code> again; within <code>process()</code>, the buffer has already been allocated so it will be reused, saving further allocations; the buffer will be filled and possibly written again; <code>Action.SCHEDULED</code> is returned again, returning again from the <code>process()</code> method.</p>
</div>
<div class="paragraph">
<p>At this point, the call to <code>EndPoint.write(Callback, ByteBuffer&#8230;&#8203;)</code> may have not completed synchronously, so <code>IteratingCallback</code> will not call <code>process()</code> again; the processing thread is free to return to the Jetty I/O system where it may be put back into the thread pool.
If this was the only active network connection, the system would now be idle, with no threads blocked, waiting that the <code>write()</code> completes. This thread-less wait is one of the most important features that make non-blocking asynchronous servers more scalable: they use less resources.</p>
</div>
<div class="paragraph">
<p>Eventually, the Jetty I/O system will notify that the <code>write()</code> completed; this notifies the <code>IteratingCallback</code> that can now resume the loop and call <code>process()</code> again.</p>
</div>
<div class="paragraph">
<p>When <code>process()</code> is called, it is possible that zero bytes are read from the network; in this case, you want to deallocate the buffer since the other peer may never send more bytes for the <code>Connection</code> to read, or it may send them after a long pause&#8201;&#8212;&#8201;in both cases we do not want to retain the memory allocated by the buffer; next, you want to call <code>fillInterested()</code> to declare again interest for read events, and return <code>Action.IDLE</code> since there is nothing to write back and therefore the loop may be suspended.
When more bytes are again available to be read from the network, <code>onFillable()</code> will be called again and that will start the iteration again.</p>
</div>
<div class="paragraph">
<p>Another possibility is that during <code>process()</code> the read returns <code>-1</code> indicating that the other peer has closed the connection; this means that there will not be more bytes to read and the loop can be exited, so you return <code>Action.SUCCEEDED</code>; <code>IteratingCallback</code> will then call <code>onCompleteSuccess()</code> where you can close the <code>EndPoint</code>.</p>
</div>
<div class="paragraph">
<p>The last case is that during <code>process()</code> an exception is thrown, for example by <code>EndPoint.fill(ByteBuffer)</code> or, in more advanced implementations, by code that parses the bytes that have been read and finds them unacceptable; any exception thrown within <code>process()</code> will be caught by <code>IteratingCallback</code> that will exit the loop with a failure and call <code>onCompleteFailure(Throwable)</code> with the exception that has been thrown, where you can close the <code>EndPoint</code>, passing the exception that is the reason for closing prematurely the <code>EndPoint</code>.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Asynchronous programming is hard.</p>
</div>
<div class="paragraph">
<p>Rely on the Jetty classes to implement <code>Connection</code> to avoid mistakes that will be difficult to diagnose and reproduce.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-arch-listener"><a class="anchor" href="#pg-arch-listener"></a><a class="link" href="#pg-arch-listener">Jetty Listeners</a></h3>
<div class="paragraph">
<p>The Jetty architecture is based on <a href="#pg-arch-bean">components</a>, typically organized in a component tree.
These components have an internal state that varies with the component life cycle (that is, whether the component is started or stopped), as well as with the component use at runtime.
The typical example is a thread pool, whose internal state&#8201;&#8212;&#8201;such as the number of pooled threads or the job queue size&#8201;&#8212;&#8201;changes as the thread pool is used by the running client or server.</p>
</div>
<div class="paragraph">
<p>In many cases, the component state change produces an event that is broadcast to listeners.
Applications can register listeners to these components to be notified of the events they produce.</p>
</div>
<div class="paragraph">
<p>This section lists the listeners available in the Jetty components, but the events and listener APIs are discussed in the component specific sections.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#pg-arch-bean-listener">Jetty Component Listeners</a></p>
</li>
<li>
<p><a href="#pg-arch-io-connection-listener">Jetty I/O: <code>Connection.Listener</code></a></p>
</li>
<li>
<p><a href="#pg-server-http-channel-events">HttpChannel Events</a></p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="pg-arch-jmx"><a class="anchor" href="#pg-arch-jmx"></a><a class="link" href="#pg-arch-jmx">Jetty JMX Support</a></h3>
<div class="paragraph">
<p>The Java Management Extensions (JMX) APIs are standard API for managing and monitoring resources such as applications, devices, services, and the Java Virtual Machine itself.</p>
</div>
<div class="paragraph">
<p>The JMX API includes remote access, so a remote management console such as <a href="https://openjdk.java.net/projects/jmc/">Java Mission Control</a> can interact with a running application for these purposes.</p>
</div>
<div class="paragraph">
<p>Jetty architecture is based on <a href="#pg-arch-bean">components</a> organized in a tree. Every time a component is added to or removed from the component tree, an event is emitted, and <a href="#pg-arch-bean-listener-container">Container.Listener</a> implementations can listen to those events and perform additional actions.</p>
</div>
<div class="paragraph">
<p><code>org.eclipse.jetty.jmx.MBeanContainer</code> listens to those events and registers/unregisters the Jetty components as MBeans into the platform MBeanServer.</p>
</div>
<div class="paragraph">
<p>The Jetty components are annotated with <a href="#pg-arch-jmx-annotation">Jetty JMX annotations</a> so that they can provide specific JMX metadata such as attributes and operations that should be exposed via JMX.</p>
</div>
<div class="paragraph">
<p>Therefore, when a component is added to the component tree, <code>MBeanContainer</code> is notified, it creates the MBean from the component POJO and registers it to the <code>MBeanServer</code>.
Similarly, when a component is removed from the tree, <code>MBeanContainer</code> is notified, and unregisters the MBean from the <code>MBeanServer</code>.</p>
</div>
<div class="paragraph">
<p>The Maven coordinates for the Jetty JMX support are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;dependency&gt;</span>
<span class="tag">&lt;groupId&gt;</span>org.eclipse.jetty<span class="tag">&lt;/groupId&gt;</span>
<span class="tag">&lt;artifactId&gt;</span>jetty-jmx<span class="tag">&lt;/artifactId&gt;</span>
<span class="tag">&lt;version&gt;</span>10.0.6<span class="tag">&lt;/version&gt;</span>
<span class="tag">&lt;/dependency&gt;</span></code></pre>
</div>
</div>
<div class="sect3">
<h4 id="pg-enabling-jmx-support"><a class="anchor" href="#pg-enabling-jmx-support"></a><a class="link" href="#pg-enabling-jmx-support">Enabling JMX Support</a></h4>
<div class="paragraph">
<p>Enabling JMX support is always recommended because it provides valuable information about the system, both for monitoring purposes and for troubleshooting purposes in case of problems.</p>
</div>
<div class="paragraph">
<p>To enable JMX support on the server:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Create an MBeanContainer with the platform MBeanServer.</span>
MBeanContainer mbeanContainer = <span class="keyword">new</span> MBeanContainer(<span class="predefined-type">ManagementFactory</span>.getPlatformMBeanServer());
<span class="comment">// Add MBeanContainer to the root component.</span>
server.addBean(mbeanContainer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Similarly on the client:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">HttpClient httpClient = <span class="keyword">new</span> HttpClient();
<span class="comment">// Create an MBeanContainer with the platform MBeanServer.</span>
MBeanContainer mbeanContainer = <span class="keyword">new</span> MBeanContainer(<span class="predefined-type">ManagementFactory</span>.getPlatformMBeanServer());
<span class="comment">// Add MBeanContainer to the root component.</span>
httpClient.addBean(mbeanContainer);</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The MBeans exported to the platform MBeanServer can only be accessed locally (from the same machine), not from remote machines.</p>
</div>
<div class="paragraph">
<p>This means that this configuration is enough for development, where you have easy access (with graphical user interface) to the machine where Jetty runs, but it is typically not enough when the machine where Jetty runs is remote, or only accessible via SSH or otherwise without graphical user interface support.
In these cases, you have to enable <a href="#pg-arch-jmx-remote">JMX Remote Access</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="pg-arch-jmx-remote"><a class="anchor" href="#pg-arch-jmx-remote"></a><a class="link" href="#pg-arch-jmx-remote">Enabling JMX Remote Access</a></h4>
<div class="paragraph">
<p>There are two ways of enabling remote connectivity so that JMC can connect to the remote JVM to visualize MBeans.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Use the <code>com.sun.management.jmxremote</code> system property on the command line.
Unfortunately, this solution does not work well with firewalls and is not flexible.</p>
</li>
<li>
<p>Use Jetty&#8217;s <code>ConnectorServer</code> class.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>org.eclipse.jetty.jmx.ConnectorServer</code> will use by default RMI to allow connection from remote clients, and it is a wrapper around the standard JDK class <code>JMXConnectorServer</code>, which is the class that provides remote access to JMX clients.</p>
</div>
<div class="paragraph">
<p>Connecting to the remote JVM is a two step process:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>First, the client will connect to the RMI <em>registry</em> to download the RMI stub for the <code>JMXConnectorServer</code>; this RMI stub contains the IP address and port to connect to the RMI server, i.e. the remote <code>JMXConnectorServer</code>.</p>
</li>
<li>
<p>Second, the client uses the RMI stub to connect to the RMI <em>server</em> (i.e. the remote <code>JMXConnectorServer</code>) typically on an address and port that may be different from the RMI registry address and port.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The host and port configuration for the RMI registry and the RMI server is specified by a <code>JMXServiceURL</code>.
The string format of an RMI <code>JMXServiceURL</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">service:jmx:rmi://&lt;rmi_server_host&gt;:&lt;rmi_server_port&gt;/jndi/rmi://&lt;rmi_registry_host&gt;:&lt;rmi_registry_port&gt;/jmxrmi</code></pre>
</div>
</div>
<div class="paragraph">
<p>Default values are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">rmi_server_host = localhost
rmi_server_port = 1099
rmi_registry_host = localhost
rmi_registry_port = 1099</code></pre>
</div>
</div>
<div class="paragraph">
<p>With the default configuration, only clients that are local to the server machine can connect to the RMI registry and RMI server - this is done for security reasons.
With this configuration it would still be possible to access the MBeans from remote using a <a href="#pg-arch-jmx-remote-ssh-tunnel">SSH tunnel</a>.</p>
</div>
<div class="paragraph">
<p>By specifying an appropriate <code>JMXServiceURL</code>, you can fine tune the network interfaces the RMI registry and the RMI server bind to, and the ports that the RMI registry and the RMI server listen to.
The RMI server and RMI registry hosts and ports can be the same (as in the default configuration) because RMI is able to multiplex traffic arriving to a port to multiple RMI objects.</p>
</div>
<div class="paragraph">
<p>If you need to allow JMX remote access through a firewall, you must open both the RMI registry and the RMI server ports.</p>
</div>
<div class="paragraph">
<p><code>JMXServiceURL</code> common examples:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">service:jmx:rmi:///jndi/rmi:///jmxrmi
rmi_server_host = local host address
rmi_server_port = randomly chosen
rmi_registry_host = local host address
rmi_registry_port = 1099
service:jmx:rmi://0.0.0.0:1099/jndi/rmi://0.0.0.0:1099/jmxrmi
rmi_server_host = any address
rmi_server_port = 1099
rmi_registry_host = any address
rmi_registry_port = 1099
service:jmx:rmi://localhost:1100/jndi/rmi://localhost:1099/jmxrmi
rmi_server_host = loopback address
rmi_server_port = 1100
rmi_registry_host = loopback address
rmi_registry_port = 1099</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>When <code>ConnectorServer</code> is started, its RMI stub is exported to the RMI registry.
The RMI stub contains the IP address and port to connect to the RMI object, but the IP address is typically the machine host name, not the host specified in the <code>JMXServiceURL</code>.</p>
</div>
<div class="paragraph">
<p>To control the IP address stored in the RMI stub you need to set the system property <code>java.rmi.server.hostname</code> with the desired value.
This is especially important when binding the RMI server host to the loopback address for security reasons. See also <a href="#pg-arch-jmx-remote-ssh-tunnel">JMX Remote Access via SSH Tunnel.</a></p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To allow JMX remote access, create and configure a <code>ConnectorServer</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Setup Jetty JMX.</span>
MBeanContainer mbeanContainer = <span class="keyword">new</span> MBeanContainer(<span class="predefined-type">ManagementFactory</span>.getPlatformMBeanServer());
server.addBean(mbeanContainer);
<span class="comment">// Setup ConnectorServer.</span>
<span class="comment">// Bind the RMI server to the wildcard address and port 1999.</span>
<span class="comment">// Bind the RMI registry to the wildcard address and port 1099.</span>
<span class="predefined-type">JMXServiceURL</span> jmxURL = <span class="keyword">new</span> <span class="predefined-type">JMXServiceURL</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">rmi</span><span class="delimiter">&quot;</span></span>, <span class="predefined-constant">null</span>, <span class="integer">1999</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/jndi/rmi:///jmxrmi</span><span class="delimiter">&quot;</span></span>);
ConnectorServer jmxServer = <span class="keyword">new</span> ConnectorServer(jmxURL, <span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.jmx:name=rmiconnectorserver</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Add ConnectorServer as a bean, so it is started</span>
<span class="comment">// with the Server and also exported as MBean.</span>
server.addBean(jmxServer);
server.start();</code></pre>
</div>
</div>
<div class="sect4">
<h5 id="pg-arch-jmx-remote-authorization"><a class="anchor" href="#pg-arch-jmx-remote-authorization"></a><a class="link" href="#pg-arch-jmx-remote-authorization">JMX Remote Access Authorization</a></h5>
<div class="paragraph">
<p>The standard <code>JMXConnectorServer</code> provides several options to authorize access, for example via JAAS or via configuration files.
For a complete guide to controlling authentication and authorization in JMX, see <a href="https://docs.oracle.com/en/java/javase/11/management/">the official JMX documentation</a>.</p>
</div>
<div class="paragraph">
<p>In the sections below we detail one way to setup JMX authentication and authorization, using configuration files for users, passwords and roles:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Setup Jetty JMX.</span>
MBeanContainer mbeanContainer = <span class="keyword">new</span> MBeanContainer(<span class="predefined-type">ManagementFactory</span>.getPlatformMBeanServer());
server.addBean(mbeanContainer);
<span class="comment">// Setup ConnectorServer.</span>
<span class="predefined-type">JMXServiceURL</span> jmxURL = <span class="keyword">new</span> <span class="predefined-type">JMXServiceURL</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">rmi</span><span class="delimiter">&quot;</span></span>, <span class="predefined-constant">null</span>, <span class="integer">1099</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/jndi/rmi:///jmxrmi</span><span class="delimiter">&quot;</span></span>);
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; env = <span class="keyword">new</span> <span class="predefined-type">HashMap</span>&lt;&gt;();
env.put(<span class="string"><span class="delimiter">&quot;</span><span class="content">com.sun.management.jmxremote.access.file</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/users.access</span><span class="delimiter">&quot;</span></span>);
env.put(<span class="string"><span class="delimiter">&quot;</span><span class="content">com.sun.management.jmxremote.password.file</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/users.password</span><span class="delimiter">&quot;</span></span>);
ConnectorServer jmxServer = <span class="keyword">new</span> ConnectorServer(jmxURL, env, <span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.jmx:name=rmiconnectorserver</span><span class="delimiter">&quot;</span></span>);
server.addBean(jmxServer);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>users.access</code> file format is defined in the <code>$JAVA_HOME/conf/management/jmxremote.access</code> file.
A simplified version is the following:</p>
</div>
<div class="listingblock">
<div class="title">users.access</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">user1 readonly
user2 readwrite</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>users.password</code> file format is defined in the <code>$JAVA_HOME/conf/management/jmxremote.password.template</code> file.
A simplified version is the following:</p>
</div>
<div class="listingblock">
<div class="title">users.password</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">user1 password1
user2 password2</code></pre>
</div>
</div>
<div class="admonitionblock caution">
<table>
<tr>
<td class="icon">
<i class="fa icon-caution" title="Caution"></i>
</td>
<td class="content">
The <code>users.access</code> and <code>users.password</code> files are not standard <code>*.properties</code> files&#8201;&#8212;&#8201;the user must be separated from the role or password by a space character.
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="pg-securing-jmx-remote-access-with-tls"><a class="anchor" href="#pg-securing-jmx-remote-access-with-tls"></a><a class="link" href="#pg-securing-jmx-remote-access-with-tls">Securing JMX Remote Access with TLS</a></h5>
<div class="paragraph">
<p>The JMX communication via RMI happens by default in clear-text.</p>
</div>
<div class="paragraph">
<p>It is possible to configure the <code>ConnectorServer</code> with a <code>SslContextFactory</code> so that the JMX communication via RMI is encrypted:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Server server = <span class="keyword">new</span> Server();
<span class="comment">// Setup Jetty JMX.</span>
MBeanContainer mbeanContainer = <span class="keyword">new</span> MBeanContainer(<span class="predefined-type">ManagementFactory</span>.getPlatformMBeanServer());
server.addBean(mbeanContainer);
<span class="comment">// Setup SslContextFactory.</span>
SslContextFactory.Server sslContextFactory = <span class="keyword">new</span> SslContextFactory.Server();
sslContextFactory.setKeyStorePath(<span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/keystore</span><span class="delimiter">&quot;</span></span>);
sslContextFactory.setKeyStorePassword(<span class="string"><span class="delimiter">&quot;</span><span class="content">secret</span><span class="delimiter">&quot;</span></span>);
<span class="comment">// Setup ConnectorServer with SslContextFactory.</span>
<span class="predefined-type">JMXServiceURL</span> jmxURL = <span class="keyword">new</span> <span class="predefined-type">JMXServiceURL</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">rmi</span><span class="delimiter">&quot;</span></span>, <span class="predefined-constant">null</span>, <span class="integer">1099</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/jndi/rmi:///jmxrmi</span><span class="delimiter">&quot;</span></span>);
ConnectorServer jmxServer = <span class="keyword">new</span> ConnectorServer(jmxURL, <span class="predefined-constant">null</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">org.eclipse.jetty.jmx:name=rmiconnectorserver</span><span class="delimiter">&quot;</span></span>, sslContextFactory);
server.addBean(jmxServer);
server.start();</code></pre>
</div>
</div>
<div class="paragraph">
<p>It is possible to use the same <code>SslContextFactory.Server</code> used to configure the Jetty <code>ServerConnector</code> that supports TLS also for the JMX communication via RMI.</p>
</div>
<div class="paragraph">
<p>The keystore must contain a valid certificate signed by a Certification Authority.</p>
</div>
<div class="paragraph">
<p>The RMI mechanic is the usual one: the RMI client (typically a monitoring console) will connect first to the RMI registry (using TLS), download the RMI server stub that contains the address and port of the RMI server to connect to, then connect to the RMI server (using TLS).</p>
</div>
<div class="paragraph">
<p>This also mean that if the RMI registry and the RMI server are on different hosts, the RMI client must have available the cryptographic material to validate both hosts.</p>
</div>
<div class="paragraph">
<p>Having certificates signed by a Certification Authority simplifies by a lot the configuration needed to get the JMX communication over TLS working properly.</p>
</div>
<div class="paragraph">
<p>If that is not the case (for example the certificate is self-signed), then you need to specify the required system properties that allow RMI (especially when acting as an RMI client) to retrieve the cryptographic material necessary to establish the TLS connection.</p>
</div>
<div class="paragraph">
<p>For example, trying to connect using the JDK standard <code>JMXConnector</code> with both the RMI server and the RMI registry via TLS to <code>domain.com</code> with a self-signed certificate:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// System properties necessary for an RMI client to trust a self-signed certificate.</span>
<span class="predefined-type">System</span>.setProperty(<span class="string"><span class="delimiter">&quot;</span><span class="content">javax.net.ssl.trustStore</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">/path/to/trustStore</span><span class="delimiter">&quot;</span></span>);
<span class="predefined-type">System</span>.setProperty(<span class="string"><span class="delimiter">&quot;</span><span class="content">javax.net.ssl.trustStorePassword</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">secret</span><span class="delimiter">&quot;</span></span>);
<span class="predefined-type">JMXServiceURL</span> jmxURL = <span class="keyword">new</span> <span class="predefined-type">JMXServiceURL</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">service:jmx:rmi:///jndi/rmi://domain.com:1100/jmxrmi</span><span class="delimiter">&quot;</span></span>);
<span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; clientEnv = <span class="keyword">new</span> <span class="predefined-type">HashMap</span>&lt;&gt;();
<span class="comment">// Required to connect to the RMI registry via TLS.</span>
clientEnv.put(ConnectorServer.RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE, <span class="keyword">new</span> <span class="predefined-type">SslRMIClientSocketFactory</span>());
<span class="keyword">try</span> (<span class="predefined-type">JMXConnector</span> client = <span class="predefined-type">JMXConnectorFactory</span>.connect(jmxURL, clientEnv))
{
<span class="predefined-type">Set</span>&lt;<span class="predefined-type">ObjectName</span>&gt; names = client.getMBeanServerConnection().queryNames(<span class="predefined-constant">null</span>, <span class="predefined-constant">null</span>);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Similarly, to launch JMC:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">$ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore -Djavax.net.ssl.trustStorePassword=secret</code></pre>
</div>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
These system properties are required when launching the <code>ConnectorServer</code> too, on the server, because it acts as an RMI client with respect to the RMI registry.
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="pg-arch-jmx-remote-ssh-tunnel"><a class="anchor" href="#pg-arch-jmx-remote-ssh-tunnel"></a><a class="link" href="#pg-arch-jmx-remote-ssh-tunnel">JMX Remote Access with Port Forwarding via SSH Tunnel</a></h5>
<div class="paragraph">
<p>You can access JMX MBeans on a remote machine when the RMI ports are not open, for example because of firewall policies, but you have SSH access to the machine using local port forwarding via an SSH tunnel.</p>
</div>
<div class="paragraph">
<p>In this case you want to configure the <code>ConnectorServer</code> with a <code>JMXServiceURL</code> that binds the RMI server and the RMI registry to the loopback interface only: <code>service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi</code>.</p>
</div>
<div class="paragraph">
<p>Then you setup the local port forwarding with the SSH tunnel:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">$ ssh -L 1099:localhost:1099 &lt;user&gt;@&lt;machine_host&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now you can use JConsole or JMC to connect to <code>localhost:1099</code> on your local computer.
The traffic will be forwarded to <code>machine_host</code> and when there, SSH will forward the traffic to <code>localhost:1099</code>, which is exactly where the <code>ConnectorServer</code> listens.</p>
</div>
<div class="paragraph">
<p>When you configure <code>ConnectorServer</code> in this way, you must set the system property <code>-Djava.rmi.server.hostname=localhost</code>, on the server.
This is required because when the RMI server is exported, its address and port are stored in the RMI stub. You want the address in the RMI stub to be <code>localhost</code> so that when the RMI stub is downloaded to the remote client, the RMI communication will go through the SSH tunnel.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="pg-arch-jmx-annotation"><a class="anchor" href="#pg-arch-jmx-annotation"></a><a class="link" href="#pg-arch-jmx-annotation">Jetty JMX Annotations</a></h4>
<div class="paragraph">
<p>The Jetty JMX support, and in particular <code>MBeanContainer</code>, is notified every time a bean is added to the component tree.</p>
</div>
<div class="paragraph">
<p>The bean is scanned for Jetty JMX annotations to obtain JMX metadata: the JMX attributes and JMX operations.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// Annotate the class with @ManagedObject and provide a description.</span>
<span class="annotation">@ManagedObject</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">Services that provide useful features</span><span class="delimiter">&quot;</span></span>)
<span class="type">class</span> <span class="class">Services</span>
{
<span class="directive">private</span> <span class="directive">final</span> <span class="predefined-type">Map</span>&lt;<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>&gt; services = <span class="keyword">new</span> <span class="predefined-type">ConcurrentHashMap</span>&lt;&gt;();
<span class="directive">private</span> <span class="type">boolean</span> enabled = <span class="predefined-constant">true</span>;
<span class="comment">// A read-only attribute with description.</span>
<span class="annotation">@ManagedAttribute</span>(value = <span class="string"><span class="delimiter">&quot;</span><span class="content">The number of services</span><span class="delimiter">&quot;</span></span>, readonly = <span class="predefined-constant">true</span>)
<span class="directive">public</span> <span class="type">int</span> getServiceCount()
{
<span class="keyword">return</span> services.size();
}
<span class="comment">// A read-write attribute with description.</span>
<span class="comment">// Only the getter is annotated.</span>
<span class="annotation">@ManagedAttribute</span>(value = <span class="string"><span class="delimiter">&quot;</span><span class="content">Whether the services are enabled</span><span class="delimiter">&quot;</span></span>)
<span class="directive">public</span> <span class="type">boolean</span> isEnabled()
{
<span class="keyword">return</span> enabled;
}
<span class="comment">// There is no need to annotate the setter.</span>
<span class="directive">public</span> <span class="type">void</span> setEnabled(<span class="type">boolean</span> enabled)
{
<span class="local-variable">this</span>.enabled = enabled;
}
<span class="comment">// An operation with description and impact.</span>
<span class="comment">// The @Name annotation is used to annotate parameters</span>
<span class="comment">// for example to display meaningful parameter names.</span>
<span class="annotation">@ManagedOperation</span>(value = <span class="string"><span class="delimiter">&quot;</span><span class="content">Retrieves the service with the given name</span><span class="delimiter">&quot;</span></span>, impact = <span class="string"><span class="delimiter">&quot;</span><span class="content">INFO</span><span class="delimiter">&quot;</span></span>)
<span class="directive">public</span> <span class="predefined-type">Object</span> getService(<span class="annotation">@Name</span>(value = <span class="string"><span class="delimiter">&quot;</span><span class="content">serviceName</span><span class="delimiter">&quot;</span></span>) <span class="predefined-type">String</span> n)
{
<span class="keyword">return</span> services.get(n);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The JMX metadata and the bean are wrapped by an instance of <code>org.eclipse.jetty.jmx.ObjectMBean</code> that exposes the JMX metadata and, upon request from JMX consoles, invokes methods on the bean to get/set attribute values and perform operations.</p>
</div>
<div class="paragraph">
<p>You can provide a custom subclass of <code>ObjectMBean</code> to further customize how the bean is exposed to JMX.</p>
</div>
<div class="paragraph">
<p>The custom <code>ObjectMBean</code> subclass must respect the following naming convention: <code>&lt;package&gt;.jmx.&lt;class&gt;MBean</code>.
For example, class <code>com.acme.Foo</code> may have a custom <code>ObjectMBean</code> subclass named <code>com.acme.<strong>jmx</strong>.Foo<strong>MBean</strong></code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">//package com.acme;</span>
<span class="annotation">@ManagedObject</span>
<span class="type">class</span> <span class="class">Service</span>
{
}
<span class="comment">//package com.acme.jmx;</span>
<span class="type">class</span> <span class="class">ServiceMBean</span> <span class="directive">extends</span> ObjectMBean
{
ServiceMBean(<span class="predefined-type">Object</span> service)
{
<span class="local-variable">super</span>(service);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The custom <code>ObjectMBean</code> subclass is also scanned for Jetty JMX annotations and overrides the JMX metadata obtained by scanning the bean class.
This allows to annotate only the custom <code>ObjectMBean</code> subclass and keep the bean class free of the Jetty JMX annotations.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">//package com.acme;</span>
<span class="comment">// No Jetty JMX annotations.</span>
<span class="type">class</span> <span class="class">CountService</span>
{
<span class="directive">private</span> <span class="type">int</span> count;
<span class="directive">public</span> <span class="type">int</span> getCount()
{
<span class="keyword">return</span> count;
}
<span class="directive">public</span> <span class="type">void</span> addCount(<span class="type">int</span> value)
{
count += value;
}
}
<span class="comment">//package com.acme.jmx;</span>
<span class="annotation">@ManagedObject</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">the count service</span><span class="delimiter">&quot;</span></span>)
<span class="type">class</span> <span class="class">CountServiceMBean</span> <span class="directive">extends</span> ObjectMBean
{
<span class="directive">public</span> CountServiceMBean(<span class="predefined-type">Object</span> service)
{
<span class="local-variable">super</span>(service);
}
<span class="directive">private</span> CountService getCountService()
{
<span class="keyword">return</span> (CountService)<span class="local-variable">super</span>.getManagedObject();
}
<span class="annotation">@ManagedAttribute</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">the current service count</span><span class="delimiter">&quot;</span></span>)
<span class="directive">public</span> <span class="type">int</span> getCount()
{
<span class="keyword">return</span> getCountService().getCount();
}
<span class="annotation">@ManagedOperation</span>(value = <span class="string"><span class="delimiter">&quot;</span><span class="content">adds the given value to the service count</span><span class="delimiter">&quot;</span></span>, impact = <span class="string"><span class="delimiter">&quot;</span><span class="content">ACTION</span><span class="delimiter">&quot;</span></span>)
<span class="directive">public</span> <span class="type">void</span> addCount(<span class="annotation">@Name</span>(<span class="string"><span class="delimiter">&quot;</span><span class="content">count delta</span><span class="delimiter">&quot;</span></span>) <span class="type">int</span> value)
{
getCountService().addCount(value);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The scan for Jetty JMX annotations is performed on the bean class and all the interfaces implemented by the bean class, then on the super-class and all the interfaces implemented by the super-class and so on until <code>java.lang.Object</code> is reached.
For each type&#8201;&#8212;&#8201;class or interface, the corresponding <code>*.jmx.*MBean</code> is looked up and scanned as well with the same algorithm.
For each type, the scan looks for the class-level annotation <code>@ManagedObject</code>.
If it is found, the scan looks for method-level <code>@ManagedAttribute</code> and <code>@ManagedOperation</code> annotations; otherwise it skips the current type and moves to the next type to scan.</p>
</div>
<div class="sect4">
<h5 id="pg-managedobject"><a class="anchor" href="#pg-managedobject"></a><a class="link" href="#pg-managedobject">@ManagedObject</a></h5>
<div class="paragraph">
<p>The <code>@ManagedObject</code> annotation is used on a class at the top level to indicate that it should be exposed as an MBean.
It has only one attribute to it which is used as the description of the MBean.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-managedattribute"><a class="anchor" href="#pg-managedattribute"></a><a class="link" href="#pg-managedattribute">@ManagedAttribute</a></h5>
<div class="paragraph">
<p>The <code>@ManagedAttribute</code> annotation is used to indicate that a given method is exposed as a JMX attribute.
This annotation is placed always on the getter method of a given attribute.
Unless the <code>readonly</code> attribute is set to <code>true</code> in the annotation, a corresponding setter is looked up following normal naming conventions.
For example if this annotation is on a method called <code>String getFoo()</code> then a method called <code>void setFoo(String)</code> would be looked up, and if found wired as the setter for the JMX attribute.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-managedoperation"><a class="anchor" href="#pg-managedoperation"></a><a class="link" href="#pg-managedoperation">@ManagedOperation</a></h5>
<div class="paragraph">
<p>The <code>@ManagedOperation</code> annotation is used to indicate that a given method is exposed as a JMX operation.
A JMX operation has an <em>impact</em> that can be <code>INFO</code> if the operation returns a value without modifying the object, <code>ACTION</code> if the operation does not return a value but modifies the object, and "ACTION_INFO" if the operation both returns a value and modifies the object.
If the <em>impact</em> is not specified, it has the default value of <code>UNKNOWN</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="pg-name"><a class="anchor" href="#pg-name"></a><a class="link" href="#pg-name">@Name</a></h5>
<div class="paragraph">
<p>The <code>@Name</code> annotation is used to assign a name and description to parameters in method signatures so that when rendered by JMX consoles it is clearer what the parameter meaning is.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="pg-troubleshooting"><a class="anchor" href="#pg-troubleshooting"></a><a class="link" href="#pg-troubleshooting">Appendix B: Troubleshooting Jetty</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>TODO: introduction</p>
</div>
<div class="sect2">
<h3 id="pg-troubleshooting-logging"><a class="anchor" href="#pg-troubleshooting-logging"></a><a class="link" href="#pg-troubleshooting-logging">Logging</a></h3>
<div class="paragraph">
<p>The Jetty libraries (both client and server) use <a href="http://slf4j.org/">SLF4J</a> as logging APIs.
You can therefore plug in any SLF4J logging implementation, and configure the logging category <code>org.eclipse.jetty</code> at the desired level.</p>
</div>
<div class="paragraph">
<p>When you have problems with Jetty, the first thing that you want to do is to enable DEBUG logging.
This is helpful because by reading the DEBUG logs you get a better understanding of what is going on in the system (and that alone may give you the answers you need to fix the problem), and because Jetty developers will probably need the DEBUG logs to help you.</p>
</div>
<div class="sect3">
<h4 id="pg-jetty-slf4j-binding"><a class="anchor" href="#pg-jetty-slf4j-binding"></a><a class="link" href="#pg-jetty-slf4j-binding">Jetty SLF4J Binding</a></h4>
<div class="paragraph">
<p>The Jetty artifact <code>jetty-slf4j-impl</code> is a SLF4J binding, that is the Jetty implementation of the SLF4J APIs, and provides a number of easy-to-use features to configure logging.</p>
</div>
<div class="paragraph">
<p>The Jetty SLF4J binding only provides an appender that writes to <code>System.err</code>.
For more advanced configurations (for example, logging to a file), use <a href="http://logback.qos.ch">LogBack</a>, or <a href="https://logging.apache.org/log4j/2.x/">Log4J2</a>, or your preferred SLF4J binding.</p>
</div>
<div class="admonitionblock caution">
<table>
<tr>
<td class="icon">
<i class="fa icon-caution" title="Caution"></i>
</td>
<td class="content">
Only one binding can be present in the class-path or module-path. If you use the LogBack SLF4J binding or the Log4J2 SLF4J binding, remember to remove the Jetty SLF4J binding.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The Jetty SLF4J binding reads a file in the class-path (or module-path) called <code>jetty-logging.properties</code> that can be configured with the logging levels for various logger categories:</p>
</div>
<div class="listingblock">
<div class="title">jetty-logging.properties</div>
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen"># By default, log at INFO level all Jetty classes.
org.eclipse.jetty.LEVEL=INFO
# However, the Jetty client classes are logged at DEBUG level.
org.eclipse.jetty.client.LEVEL=DEBUG</code></pre>
</div>
</div>
<div class="paragraph">
<p>Similarly to how you configure the <code>jetty-logging.properties</code> file, you can set the system property <code>org.eclipse.jetty[.&lt;package_names&gt;].LEVEL=DEBUG</code> to quickly change the logging level to DEBUG without editing any file.
The system property can be set on the command line, or in your IDE when you run your tests or your Jetty-based application and will override the <code>jetty-logging.properties</code> file configuration.
For example to enable DEBUG logging for all the Jetty classes (<em>very</em> verbose):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">java -Dorg.eclipse.jetty.LEVEL=DEBUG --class-path ...</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you want to enable DEBUG logging but only for the HTTP/2 classes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">java -Dorg.eclipse.jetty.http2.LEVEL=DEBUG --class-path ...</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="pg-troubleshooting-thread-dump"><a class="anchor" href="#pg-troubleshooting-thread-dump"></a><a class="link" href="#pg-troubleshooting-thread-dump">JVM Thread Dump</a></h3>
<div class="paragraph">
<p>TODO</p>
</div>
</div>
<div class="sect2">
<h3 id="pg-troubleshooting-component-dump"><a class="anchor" href="#pg-troubleshooting-component-dump"></a><a class="link" href="#pg-troubleshooting-component-dump">Jetty Component Tree Dump</a></h3>
<div class="paragraph">
<p>Jetty components are organized in a <a href="#pg-arch-bean">component tree</a>.</p>
</div>
<div class="paragraph">
<p>At the root of the component tree there is typically a <code>ContainerLifeCycle</code> instance&#8201;&#8212;&#8201;typically a <code>Server</code> instance on the server and an <code>HttpClient</code> instance on the client.</p>
</div>
<div class="paragraph">
<p><code>ContainerLifeCycle</code> has built-in <em>dump</em> APIs that can be invoked either directly or <a href="#pg-arch-jmx">via JMX</a>.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
You can get more details from a Jetty&#8217;s <code>QueuedThreadPool</code> dump by enabling detailed dumps via <code>queuedThreadPool.setDetailedDump(true)</code>.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="pg-troubleshooting-debugging"><a class="anchor" href="#pg-troubleshooting-debugging"></a><a class="link" href="#pg-troubleshooting-debugging">Debugging</a></h3>
<div class="paragraph">
<p>Sometimes, in order to figure out a problem, enabling <a href="#pg-troubleshooting-logging">DEBUG logging</a> is not enough and you really need to debug the code with a debugger.</p>
</div>
<div class="paragraph">
<p>Debugging an embedded Jetty application is most easily done from your preferred IDE, so refer to your IDE instruction for how to debug Java applications.</p>
</div>
<div class="paragraph">
<p>Remote debugging can be enabled in a Jetty application via command line options:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="screen">java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000 --class-path ...</code></pre>
</div>
</div>
<div class="paragraph">
<p>The example above enables remote debugging so that debuggers (for example, your preferred IDE) can connect to port <code>8000</code> on the host running the Jetty application to receive debugging events.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
More technically, remote debugging exchanges JVM Tools Interface (JVMTI) events and commands via the Java Debug Wire Protocol (JDWP).
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="pg-migration"><a class="anchor" href="#pg-migration"></a><a class="link" href="#pg-migration">Appendix C: Migration Guides</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="pg-migration-94-to-10"><a class="anchor" href="#pg-migration-94-to-10"></a><a class="link" href="#pg-migration-94-to-10">Migrating from Jetty 9.4.x to Jetty 10.0.x</a></h3>
<div class="sect3">
<h4 id="pg-migration-94-to-10-java-version"><a class="anchor" href="#pg-migration-94-to-10-java-version"></a><a class="link" href="#pg-migration-94-to-10-java-version">Required Java Version Changes</a></h4>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Jetty 9.4.x</th>
<th class="tableblock halign-left valign-top">Jetty 10.0.x</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Java 8</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Java 11</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="pg-migration-94-to-10-websocket"><a class="anchor" href="#pg-migration-94-to-10-websocket"></a><a class="link" href="#pg-migration-94-to-10-websocket">WebSocket Migration Guide</a></h4>
<div class="paragraph">
<p>Migrating from Jetty 9.4.x to Jetty 10.0.x requires changes in the coordinates of the Maven artifact dependencies for WebSocket. Some of these classes have also changed name and package. This is not a comprehensive list of changes but should cover the most common changes encountered during migration.</p>
</div>
<div class="sect4">
<h5 id="pg-migration-94-to-10-websocket-maven-artifact-changes"><a class="anchor" href="#pg-migration-94-to-10-websocket-maven-artifact-changes"></a><a class="link" href="#pg-migration-94-to-10-websocket-maven-artifact-changes">Maven Artifacts Changes</a></h5>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Jetty 9.4.x</th>
<th class="tableblock halign-left valign-top">Jetty 10.0.x</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-api</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-jetty-api</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-server</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-jetty-server</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-client</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-jetty-client</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>javax-websocket-server-impl</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-javax-server</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>javax-websocket-client-impl</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket:<strong>websocket-javax-client</strong></code></p>
</div></div></td>
</tr>
</tbody>
</table>
</div>
<div class="sect4">
<h5 id="pg-migration-94-to-10-websocket-class-name-changes"><a class="anchor" href="#pg-migration-94-to-10-websocket-class-name-changes"></a><a class="link" href="#pg-migration-94-to-10-websocket-class-name-changes">Class Names Changes</a></h5>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Jetty 9.4.x</th>
<th class="tableblock halign-left valign-top">Jetty 10.0.x</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>server.NativeWebSocketServletContainerInitializer</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>server.config.JettyWebSocketServletContainerInitializer</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>jsr356.server.deploy.WebSocketServerContainerInitializer</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>javax.server.config.JavaxWebSocketServletContainerInitializer</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>servlet.WebSocketCreator</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>server.JettyWebSocketCreator</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>servlet.ServletUpgradeRequest</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>server.JettyServerUpgradeRequest</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>servlet.ServletUpgradeResponse</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>server.JettyServerUpgradeResponse</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>servlet.WebSocketServlet</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>server.JettyWebSocketServlet</strong></code></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>servlet.WebSocketServletFactory</strong></code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><code>org.eclipse.jetty.websocket.<strong>server.JettyWebSocketServletFactory</strong></code></p>
</div></div></td>
</tr>
</tbody>
</table>
</div>
<div class="sect4">
<h5 id="pg-migration-94-to-10-websocket-example-code"><a class="anchor" href="#pg-migration-94-to-10-websocket-example-code"></a><a class="link" href="#pg-migration-94-to-10-websocket-example-code">Example Code</a></h5>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Jetty 9.4.x</th>
<th class="tableblock halign-left valign-top">Jetty 10.0.x</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ExampleWebSocketServlet</span> <span class="directive">extends</span> WebSocketServlet
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> configure(WebSocketServletFactory factory)
{
factory.setCreator(<span class="keyword">new</span> WebSocketCreator()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Object</span> createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
<span class="keyword">return</span> <span class="keyword">new</span> ExampleEndpoint();
}
});
}
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ExampleWebSocketServlet</span> <span class="directive">extends</span> JettyWebSocketServlet
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> configure(JettyWebSocketServletFactory factory)
{
factory.setCreator(<span class="keyword">new</span> JettyWebSocketCreator()
{
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Object</span> createWebSocket(JettyServerUpgradeRequest req, JettyServerUpgradeResponse resp)
{
<span class="keyword">return</span> <span class="keyword">new</span> ExampleEndpoint();
}
});
}
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 10.0.6<br>
Last updated 2021-05-12 14:52:38 -0500
</div>
</div>
<link rel="stylesheet" href="./coderay-asciidoctor.css">
</body>
</html>