Merge branch 'jetty-10.0.x' into jetty-11.0.x
This commit is contained in:
commit
7e03bb250e
|
@ -0,0 +1,525 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||||
|
//
|
||||||
|
// This program and the accompanying materials are made available under
|
||||||
|
// the terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
// https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// This Source Code may also be made available under the following
|
||||||
|
// Secondary Licenses when the conditions for such availability set
|
||||||
|
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||||
|
// the Apache License v2.0 which is available at
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SelectableChannel;
|
||||||
|
import java.nio.channels.SelectionKey;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.api.ContentResponse;
|
||||||
|
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
|
||||||
|
import org.eclipse.jetty.client.util.FormRequestContent;
|
||||||
|
import org.eclipse.jetty.client.util.StringRequestContent;
|
||||||
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
|
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||||
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
|
import org.eclipse.jetty.io.ClientConnector;
|
||||||
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
|
import org.eclipse.jetty.io.ManagedSelector;
|
||||||
|
import org.eclipse.jetty.io.NetworkTrafficListener;
|
||||||
|
import org.eclipse.jetty.io.NetworkTrafficSocketChannelEndPoint;
|
||||||
|
import org.eclipse.jetty.io.SelectorManager;
|
||||||
|
import org.eclipse.jetty.server.Handler;
|
||||||
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
|
import org.eclipse.jetty.server.NetworkTrafficServerConnector;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
import org.eclipse.jetty.util.Fields;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class NetworkTrafficListenerTest
|
||||||
|
{
|
||||||
|
private static final String END_OF_CONTENT = "~";
|
||||||
|
|
||||||
|
private Server server;
|
||||||
|
private NetworkTrafficServerConnector connector;
|
||||||
|
private NetworkTrafficHttpClient client;
|
||||||
|
|
||||||
|
private void start(Handler handler) throws Exception
|
||||||
|
{
|
||||||
|
startServer(handler);
|
||||||
|
startClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startServer(Handler handler) throws Exception
|
||||||
|
{
|
||||||
|
server = new Server();
|
||||||
|
connector = new NetworkTrafficServerConnector(server);
|
||||||
|
connector.getConnectionFactory(HttpConfiguration.ConnectionFactory.class).getHttpConfiguration().setSendDateHeader(false);
|
||||||
|
connector.getConnectionFactory(HttpConfiguration.ConnectionFactory.class).getHttpConfiguration().setSendServerVersion(false);
|
||||||
|
server.addConnector(connector);
|
||||||
|
server.setHandler(handler);
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startClient() throws Exception
|
||||||
|
{
|
||||||
|
client = new NetworkTrafficHttpClient(new AtomicReference<>());
|
||||||
|
client.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void dispose() throws Exception
|
||||||
|
{
|
||||||
|
if (client != null)
|
||||||
|
client.stop();
|
||||||
|
if (server != null)
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenedClosedAreInvoked() throws Exception
|
||||||
|
{
|
||||||
|
startServer(null);
|
||||||
|
|
||||||
|
CountDownLatch openedLatch = new CountDownLatch(1);
|
||||||
|
CountDownLatch closedLatch = new CountDownLatch(1);
|
||||||
|
connector.setNetworkTrafficListener(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
public volatile Socket socket;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void opened(Socket socket)
|
||||||
|
{
|
||||||
|
this.socket = socket;
|
||||||
|
openedLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closed(Socket socket)
|
||||||
|
{
|
||||||
|
if (this.socket == socket)
|
||||||
|
closedLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int port = connector.getLocalPort();
|
||||||
|
|
||||||
|
// Connect to the server
|
||||||
|
try (Socket ignored = new Socket("localhost", port))
|
||||||
|
{
|
||||||
|
assertTrue(openedLatch.await(10, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
assertTrue(closedLatch.await(10, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrafficWithNoResponseContentOnNonPersistentConnection() throws Exception
|
||||||
|
{
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse)
|
||||||
|
{
|
||||||
|
request.setHandled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> serverIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> serverOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverOutgoingLatch = new CountDownLatch(1);
|
||||||
|
connector.setNetworkTrafficListener(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverIncoming.set(serverIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverOutgoing.set(serverOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> clientIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> clientOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientOutgoingLatch = new CountDownLatch(1);
|
||||||
|
client.listener.set(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientOutgoing.set(clientOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientIncoming.set(clientIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||||
|
.header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString())
|
||||||
|
.send();
|
||||||
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
|
|
||||||
|
assertTrue(clientOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(clientIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertEquals(clientOutgoing.get(), serverIncoming.get());
|
||||||
|
assertEquals(serverOutgoing.get(), clientIncoming.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrafficWithResponseContentOnPersistentConnection() throws Exception
|
||||||
|
{
|
||||||
|
String responseContent = "response_content" + END_OF_CONTENT;
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException
|
||||||
|
{
|
||||||
|
request.setHandled(true);
|
||||||
|
ServletOutputStream output = servletResponse.getOutputStream();
|
||||||
|
output.write(responseContent.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> serverIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> serverOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverOutgoingLatch = new CountDownLatch(1);
|
||||||
|
connector.setNetworkTrafficListener(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverIncoming.set(serverIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverOutgoing.set(serverOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> clientIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> clientOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientOutgoingLatch = new CountDownLatch(1);
|
||||||
|
client.listener.set(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientOutgoing.set(clientOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientIncoming.set(clientIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort()).send();
|
||||||
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
|
assertEquals(responseContent, response.getContentAsString());
|
||||||
|
|
||||||
|
assertTrue(clientOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(clientIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertEquals(clientOutgoing.get(), serverIncoming.get());
|
||||||
|
assertEquals(serverOutgoing.get(), clientIncoming.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrafficWithResponseContentChunkedOnPersistentConnection() throws Exception
|
||||||
|
{
|
||||||
|
String responseContent = "response_content";
|
||||||
|
String responseChunk1 = responseContent.substring(0, responseContent.length() / 2);
|
||||||
|
String responseChunk2 = responseContent.substring(responseContent.length() / 2);
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException
|
||||||
|
{
|
||||||
|
request.setHandled(true);
|
||||||
|
ServletOutputStream output = servletResponse.getOutputStream();
|
||||||
|
output.write(responseChunk1.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
output.write(responseChunk2.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> serverIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> serverOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverOutgoingLatch = new CountDownLatch(1);
|
||||||
|
connector.setNetworkTrafficListener(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverIncoming.set(serverIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverOutgoing.set(serverOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
if (serverOutgoing.get().endsWith("\r\n0\r\n\r\n"))
|
||||||
|
serverOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> clientIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> clientOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientOutgoingLatch = new CountDownLatch(1);
|
||||||
|
client.listener.set(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientOutgoing.set(clientOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientIncoming.set(clientIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
if (clientIncoming.get().endsWith("\r\n0\r\n\r\n"))
|
||||||
|
clientIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort()).send();
|
||||||
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
|
|
||||||
|
assertTrue(clientOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(clientIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertEquals(clientOutgoing.get(), serverIncoming.get());
|
||||||
|
assertEquals(serverOutgoing.get(), clientIncoming.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrafficWithRequestContentWithResponseRedirectOnPersistentConnection() throws Exception
|
||||||
|
{
|
||||||
|
String location = "/redirect";
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException
|
||||||
|
{
|
||||||
|
request.setHandled(true);
|
||||||
|
servletResponse.sendRedirect(location);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> serverIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> serverOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverOutgoingLatch = new CountDownLatch(1);
|
||||||
|
connector.setNetworkTrafficListener(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverIncoming.set(serverIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverOutgoing.set(serverOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> clientIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> clientOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientOutgoingLatch = new CountDownLatch(1);
|
||||||
|
client.listener.set(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientOutgoing.set(clientOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientIncoming.set(clientIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.setFollowRedirects(false);
|
||||||
|
Fields fields = new Fields();
|
||||||
|
fields.put("a", "1");
|
||||||
|
fields.put("b", "2");
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||||
|
.body(new FormRequestContent(fields))
|
||||||
|
.send();
|
||||||
|
assertEquals(HttpStatus.FOUND_302, response.getStatus());
|
||||||
|
|
||||||
|
assertTrue(clientOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(clientIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertEquals(clientOutgoing.get(), serverIncoming.get());
|
||||||
|
assertEquals(serverOutgoing.get(), clientIncoming.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrafficWithBigRequestContentOnPersistentConnection() throws Exception
|
||||||
|
{
|
||||||
|
start(new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String uri, Request request, HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException
|
||||||
|
{
|
||||||
|
// Read and discard the request body to make the test more
|
||||||
|
// reliable, otherwise there is a race between request body
|
||||||
|
// upload and response download
|
||||||
|
InputStream input = servletRequest.getInputStream();
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int read = input.read(buffer);
|
||||||
|
if (read < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
request.setHandled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> serverIncoming = new AtomicReference<>("");
|
||||||
|
AtomicReference<String> serverOutgoing = new AtomicReference<>("");
|
||||||
|
CountDownLatch serverOutgoingLatch = new CountDownLatch(1);
|
||||||
|
connector.setNetworkTrafficListener(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverIncoming.set(serverIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
serverOutgoing.set(serverOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
serverOutgoingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicReference<String> clientIncoming = new AtomicReference<>("");
|
||||||
|
CountDownLatch clientIncomingLatch = new CountDownLatch(1);
|
||||||
|
AtomicReference<String> clientOutgoing = new AtomicReference<>("");
|
||||||
|
client.listener.set(new NetworkTrafficListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientOutgoing.set(clientOutgoing.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
clientIncoming.set(clientIncoming.get() + BufferUtil.toString(bytes, StandardCharsets.UTF_8));
|
||||||
|
clientIncomingLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate a large request content.
|
||||||
|
String requestContent = "0123456789ABCDEF";
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
requestContent += requestContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||||
|
.body(new StringRequestContent(requestContent))
|
||||||
|
.send();
|
||||||
|
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||||
|
|
||||||
|
assertTrue(serverOutgoingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertTrue(clientIncomingLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
assertEquals(clientOutgoing.get(), serverIncoming.get());
|
||||||
|
assertTrue(clientOutgoing.get().length() > requestContent.length());
|
||||||
|
assertEquals(serverOutgoing.get(), clientIncoming.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NetworkTrafficHttpClient extends HttpClient
|
||||||
|
{
|
||||||
|
private final AtomicReference<NetworkTrafficListener> listener;
|
||||||
|
|
||||||
|
private NetworkTrafficHttpClient(AtomicReference<NetworkTrafficListener> listener)
|
||||||
|
{
|
||||||
|
super(new HttpClientTransportOverHTTP(new ClientConnector()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected SelectorManager newSelectorManager()
|
||||||
|
{
|
||||||
|
return new ClientSelectorManager(getExecutor(), getScheduler(), getSelectors())
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey)
|
||||||
|
{
|
||||||
|
return new NetworkTrafficSocketChannelEndPoint(channel, selector, selectionKey, getScheduler(), getIdleTimeout().toMillis(), listener.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@
|
||||||
<asciidoctorj.epub.version>1.5.0-alpha.8.1</asciidoctorj.epub.version>
|
<asciidoctorj.epub.version>1.5.0-alpha.8.1</asciidoctorj.epub.version>
|
||||||
<asciidoctorj.version>1.5.8.1</asciidoctorj.version>
|
<asciidoctorj.version>1.5.8.1</asciidoctorj.version>
|
||||||
<jruby.version>1.7.27</jruby.version>
|
<jruby.version>1.7.27</jruby.version>
|
||||||
<web.resources.version>1.1</web.resources.version>
|
<web.resources.version>1.2</web.resources.version>
|
||||||
<web.resources.directory>${project.build.directory}/web-resources</web.resources.directory>
|
<web.resources.directory>${project.build.directory}/web-resources</web.resources.directory>
|
||||||
<!-- old properties -->
|
<!-- old properties -->
|
||||||
<html.directory>${project.build.directory}/current</html.directory>
|
<html.directory>${project.build.directory}/current</html.directory>
|
||||||
|
|
|
@ -23,8 +23,11 @@
|
||||||
:revdate: {TIMESTAMP}
|
:revdate: {TIMESTAMP}
|
||||||
:toc: left
|
:toc: left
|
||||||
:toc-title: Contribution Guide
|
:toc-title: Contribution Guide
|
||||||
:toc-image: ../../common/images/jetty-logo.svg
|
:toc-style:
|
||||||
:toc-image-url: /jetty/index.html
|
|
||||||
|
:header-style: eclipse-thin
|
||||||
|
:breadcrumb-style: eclipse-thin
|
||||||
|
:footer-style: default
|
||||||
:breadcrumb: Home:../index.html | Contribution Guide:./index.html
|
:breadcrumb: Home:../index.html | Contribution Guide:./index.html
|
||||||
|
|
||||||
// docinfo lets you pull in shared content and/or influence via render type
|
// docinfo lets you pull in shared content and/or influence via render type
|
||||||
|
@ -43,12 +46,6 @@ endif::[]
|
||||||
// options for special blocks, code snippets, screen, etc
|
// options for special blocks, code snippets, screen, etc
|
||||||
:sub-order: attributes+
|
:sub-order: attributes+
|
||||||
|
|
||||||
// suppress document footer generation
|
|
||||||
//:nofooter:
|
|
||||||
|
|
||||||
// suppress Eclipse footer
|
|
||||||
:no-eclipse-footer:
|
|
||||||
|
|
||||||
// uncomment to allow include::https:// style content inclusion
|
// uncomment to allow include::https:// style content inclusion
|
||||||
//:allow-uri-read: true
|
//:allow-uri-read: true
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ If `true`, welcome files are redirected rather that forwarded.
|
||||||
welcomeServlets::
|
welcomeServlets::
|
||||||
If `true`, attempt to dispatch to welcome files that are servlets, but only after no matching static
|
If `true`, attempt to dispatch to welcome files that are servlets, but only after no matching static
|
||||||
resources could be found. If `false`, then a welcome file must exist on disk. If `exact`, then exact
|
resources could be found. If `false`, then a welcome file must exist on disk. If `exact`, then exact
|
||||||
servlet matches are supported without an existing file. Default is `true`. This must be `false` if you want directory listings,
|
servlet matches are supported without an existing file. Default is `false`. This must be `false` if you want directory listings,
|
||||||
but have index.jsp in your welcome file list.
|
but have index.jsp in your welcome file list.
|
||||||
precompressed::
|
precompressed::
|
||||||
If set to a comma separated list of encoding types (that may be listed in a requests Accept-Encoding header) to file extension mappings to look for and serve.
|
If set to a comma separated list of encoding types (that may be listed in a requests Accept-Encoding header) to file extension mappings to look for and serve.
|
||||||
|
|
|
@ -23,8 +23,11 @@
|
||||||
:revdate: {TIMESTAMP}
|
:revdate: {TIMESTAMP}
|
||||||
:toc: left
|
:toc: left
|
||||||
:toc-title: Distribution Guide
|
:toc-title: Distribution Guide
|
||||||
:toc-image: ../../common/images/jetty-logo.svg
|
:toc-style:
|
||||||
:toc-image-url: /jetty/index.html
|
|
||||||
|
:header-style: eclipse-thin
|
||||||
|
:breadcrumb-style: eclipse-thin
|
||||||
|
:footer-style: default
|
||||||
:breadcrumb: Home:../index.html | Distribution Guide:./index.html
|
:breadcrumb: Home:../index.html | Distribution Guide:./index.html
|
||||||
|
|
||||||
// docinfo lets you pull in shared content and/or influence via render type
|
// docinfo lets you pull in shared content and/or influence via render type
|
||||||
|
@ -43,12 +46,6 @@ endif::[]
|
||||||
// options for special blocks, code snippets, screen, etc
|
// options for special blocks, code snippets, screen, etc
|
||||||
:sub-order: attributes+
|
:sub-order: attributes+
|
||||||
|
|
||||||
// suppress document footer generation
|
|
||||||
//:nofooter:
|
|
||||||
|
|
||||||
// suppress Eclipse footer
|
|
||||||
:no-eclipse-footer:
|
|
||||||
|
|
||||||
// uncomment to allow include::https:// style content inclusion
|
// uncomment to allow include::https:// style content inclusion
|
||||||
//:allow-uri-read: true
|
//:allow-uri-read: true
|
||||||
|
|
||||||
|
|
|
@ -34,74 +34,105 @@ This configuration is essentially the multiple logger configuration with added c
|
||||||
|
|
||||||
The technique used by this configuration is to provide an link:{JDURL}org/eclipse/jetty/deploy/AppLifeCycle.Binding.html[AppLifeCycle.Binding] against the link:{JDURL}/org/eclipse/jetty/deploy/AppLifeCycle.html[`"deploying"`node] that modifies the
|
The technique used by this configuration is to provide an link:{JDURL}org/eclipse/jetty/deploy/AppLifeCycle.Binding.html[AppLifeCycle.Binding] against the link:{JDURL}/org/eclipse/jetty/deploy/AppLifeCycle.html[`"deploying"`node] that modifies the
|
||||||
link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#getSystemClasspathPattern()[WebAppContext.getSystemClasspathPattern().add(String)] for the common logging classes.
|
link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#getSystemClasspathPattern()[WebAppContext.getSystemClasspathPattern().add(String)] for the common logging classes.
|
||||||
See https://github.com/jetty-project/jetty-webapp-logging/blob/master/src/main/java/org/eclipse/jetty/webapp/logging/CentralizedWebAppLoggingBinding.java[org.eclipse.jetty.logging.CentralizedWebAppLoggingBinding] for actual implementation.
|
See https://github.com/jetty-project/jetty-webapp-logging/blob/master/jetty-webapp-logging/src/main/java/org/eclipse/jetty/webapp/logging/CentralizedWebAppLoggingBinding.java[org.eclipse.jetty.logging.CentralizedWebAppLoggingBinding] for actual implementation.
|
||||||
|
|
||||||
A convenient replacement `logging` module has been created to bootstrap your `${jetty.base}` directory for capturing all Jetty server logging from multiple logging frameworks into a single logging output file managed by Logback.
|
A convenient replacement `logging` module has been created to bootstrap your `${jetty.base}` directory for capturing all Jetty server logging from multiple logging frameworks into a single logging output file managed by Logback.
|
||||||
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source,screen,subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
[mybase]$ mkdir modules
|
[mybase]$ curl -O https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.4.27/jetty-webapp-logging-9.4.27-config.jar
|
||||||
[mybase]$ cd modules
|
|
||||||
|
|
||||||
[modules]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logging.mod
|
|
||||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||||
Dload Upload Total Spent Left Speed
|
Dload Upload Total Spent Left Speed
|
||||||
100 1416 100 1416 0 0 4241 0 --:--:-- --:--:-- --:--:-- 4252
|
100 3402 100 3402 0 0 15823 0 --:--:-- --:--:-- --:--:-- 15750
|
||||||
|
|
||||||
[master]$ curl -O https://raw.githubusercontent.com/jetty-project/logging-modules/master/centralized/webapp-logging.mod
|
[mybase]$ jar -xf jetty-webapp-logging-9.4.27-config.jar
|
||||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
|
||||||
Dload Upload Total Spent Left Speed
|
|
||||||
100 660 100 660 0 0 2032 0 --:--:-- --:--:-- --:--:-- 2037
|
|
||||||
[modules]$ cd ..
|
|
||||||
|
|
||||||
[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging,webapp-logging
|
[mybase]$ java -jar /opt/jetty-hom/start.jar --create-startd --add-to-start=centralized-webapp-logging
|
||||||
INFO: logging initialised in ${jetty.base}/start.ini (appended)
|
|
||||||
MKDIR: ${jetty.base}/logs
|
|
||||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
|
||||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.6.6/log4j-over-slf4j-1.6.6.jar to lib/logging/log4j-over-slf4j-1.6.6.jar
|
|
||||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/jul-to-slf4j/1.6.6/jul-to-slf4j-1.6.6.jar to lib/logging/jul-to-slf4j-1.6.6.jar
|
|
||||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar to lib/logging/jcl-over-slf4j-1.6.6.jar
|
|
||||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar
|
|
||||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar
|
|
||||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logback.xml to resources/logback.xml
|
|
||||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.properties to resources/jetty-logging.properties
|
|
||||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.xml to etc/jetty-logging.xml
|
|
||||||
INFO: resources initialised transitively
|
|
||||||
INFO: resources enabled in ${jetty.base}/start.ini
|
|
||||||
INFO: webapp-logging initialised in ${jetty.base}/start.ini (appended)
|
|
||||||
DOWNLOAD: https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.0.0/jetty-webapp-logging-9.0.0.jar to lib/webapp-logging/jetty-webapp-logging-9.0.0.jar
|
|
||||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/jetty-webapp-logging/master/src/main/config/etc/jetty-webapp-logging.xml to etc/jetty-webapp-logging.xml
|
|
||||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/jetty-webapp-logging/master/src/main/config/etc/jetty-mdc-handler.xml to etc/jetty-mdc-handler.xml
|
|
||||||
INFO: deploy initialised transitively
|
|
||||||
INFO: deploy enabled in ${jetty.base}/start.ini
|
|
||||||
INFO: logging initialised transitively
|
|
||||||
INFO: resources initialised transitively
|
|
||||||
INFO: resources enabled in ${jetty.base}/start.ini
|
|
||||||
|
|
||||||
[mybase]$ java -jar /opt/jetty-dist/start.jar
|
ALERT: There are enabled module(s) with licenses.
|
||||||
|
The following 2 module(s):
|
||||||
|
+ contains software not provided by the Eclipse Foundation!
|
||||||
|
+ contains software not covered by the Eclipse Public License!
|
||||||
|
+ has not been audited for compliance with its license
|
||||||
|
|
||||||
|
Module: logback-impl
|
||||||
|
+ Logback: the reliable, generic, fast and flexible logging framework.
|
||||||
|
+ Copyright (C) 1999-2012, QOS.ch. All rights reserved.
|
||||||
|
+ This program and the accompanying materials are dual-licensed under
|
||||||
|
+ either:
|
||||||
|
+ the terms of the Eclipse Public License v1.0
|
||||||
|
+ as published by the Eclipse Foundation:
|
||||||
|
+ http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
+ or (per the licensee's choosing) under
|
||||||
|
+ the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
+ as published by the Free Software Foundation:
|
||||||
|
+ http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
|
||||||
|
|
||||||
|
Module: slf4j-api
|
||||||
|
+ SLF4J is distributed under the MIT License.
|
||||||
|
+ Copyright (c) 2004-2013 QOS.ch
|
||||||
|
+ All rights reserved.
|
||||||
|
+ Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
+ a copy of this software and associated documentation files (the
|
||||||
|
+ "Software"), to deal in the Software without restriction, including
|
||||||
|
+ without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
+ distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
+ permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
+ the following conditions:
|
||||||
|
+ The above copyright notice and this permission notice shall be
|
||||||
|
+ included in all copies or substantial portions of the Software.
|
||||||
|
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Proceed (y/N)? y
|
||||||
|
INFO : slf4j-api transitively enabled
|
||||||
|
INFO : log4j-over-slf4j transitively enabled
|
||||||
|
INFO : jcl-slf4j transitively enabled
|
||||||
|
INFO : logback-impl transitively enabled
|
||||||
|
INFO : jul-slf4j transitively enabled
|
||||||
|
INFO : slf4j-logback transitively enabled
|
||||||
|
INFO : centralized-webapp-logging initialized in ${jetty.base}/start.d/centralized-webapp-logging.ini
|
||||||
|
INFO : logging-logback transitively enabled
|
||||||
|
INFO : resources transitively enabled
|
||||||
|
MKDIR : ${jetty.base}/lib/slf4j
|
||||||
|
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.25.jar
|
||||||
|
MKDIR : ${jetty.base}/lib/logging
|
||||||
|
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.7.25/log4j-over-slf4j-1.7.25.jar to ${jetty.base}/lib/logging/log4j-over-slf4j-1.7.25.jar
|
||||||
|
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.25/jcl-over-slf4j-1.7.25.jar to ${jetty.base}/lib/slf4j/jcl-over-slf4j-1.7.25.jar
|
||||||
|
MKDIR : ${jetty.base}/lib/logback
|
||||||
|
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar to ${jetty.base}/lib/logback/logback-core-1.2.3.jar
|
||||||
|
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar to ${jetty.base}/lib/slf4j/jul-to-slf4j-1.7.25.jar
|
||||||
|
COPY : ${jetty.home}/modules/jul-slf4j/etc/java-util-logging.properties to ${jetty.base}/etc/java-util-logging.properties
|
||||||
|
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar to ${jetty.base}/lib/logback/logback-classic-1.2.3.jar
|
||||||
|
MKDIR : ${jetty.base}/logs
|
||||||
|
DOWNLD: https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.4.27/jetty-webapp-logging-9.4.27.jar to ${jetty.base}/lib/logging/jetty-webapp-logging-9.4.27.jar
|
||||||
|
INFO : Base directory was modified
|
||||||
|
|
||||||
|
$
|
||||||
....
|
....
|
||||||
|
|
||||||
The replacement `logging.mod` performs a number of tasks.
|
This replacement `centralized-webapp-logging.mod` performs a number of tasks.
|
||||||
|
|
||||||
. `mybase` is a `${jetty.base}` directory.
|
. `mybase` is a `${jetty.base}` directory.
|
||||||
. The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/` and becomes the `${jetty.home}` directory for this demonstration.
|
. The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/` and becomes the `${jetty.home}` directory for this demonstration.
|
||||||
. The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by mybase only.
|
. The `curl` command downloads the replacement config overlay for the `${jetty.base}/modules/` directory to use.
|
||||||
. The `start.jar --add-to-start=logging,webapp-logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration.
|
. The `start.jar --add-to-start=centralized-webapp-logging` command performs a number of steps to make the centralized-webapp-logging module available to the `${jetty.base}` configuration.
|
||||||
.. Several entries are added to the `${jetty.base}/start.ini` configuration.
|
.. A new `${jetty.base}/start.d/centralized-webapp-logging.ini` configuration was created.
|
||||||
* `--module=logging` is added to enable the logging module.
|
.. Required `${jetty.base}` directories are created: `${jetty.base}/logs` and `${jetty.base}/resources`.
|
||||||
* `--module=webapp-logging` is added to enable the webapp-logging module.
|
.. Required logging libraries are downloaded (if not present already) to the `${jetty.base}/lib/logging/` directory:
|
||||||
.. Required `${jetty.base}` directories are created: `${jetty.base}/logs` and `${jetty.base}/resources`.
|
|
||||||
.. Required logging libraries are downloaded (if not present already) to the `${jetty.base}/lib/logging/` directory:
|
|
||||||
* `slf4j-api.jar` - API jar for Slf4j (used by most of the rest of the jars)
|
* `slf4j-api.jar` - API jar for Slf4j (used by most of the rest of the jars)
|
||||||
* `log4j-over-slf4j.jar` - Slf4j jar that captures all log4j emitted logging events
|
* `log4j-over-slf4j.jar` - Slf4j jar that captures all log4j emitted logging events
|
||||||
* `jul-to-slf4j.jar` - Slf4j jar that captures all java.util.logging events
|
* `jul-to-slf4j.jar` - Slf4j jar that captures all java.util.logging events
|
||||||
* `jcl-over-slf4j.jar` - Slf4j jar that captures all commons-logging events
|
* `jcl-over-slf4j.jar` - Slf4j jar that captures all commons-logging events
|
||||||
* `logback-classic.jar` - the Slf4j adapter jar that routes all of the captured logging events to logback itself.
|
* `logback-classic.jar` - the Slf4j adapter jar that routes all of the captured logging events to logback itself.
|
||||||
* `logback-core.jar` - the logback implementation jar, that handles all of the filtering and output of the logging events.
|
* `logback-core.jar` - the logback implementation jar, that handles all of the filtering and output of the logging events.
|
||||||
.. Required webapp-logging library is downloaded (if not present already) to the `${jetty.base}/lib/webapp-logging/` directory:
|
.. Required webapp-logging library is downloaded (if not present already) to the `${jetty.base}/lib/webapp-logging/` directory:
|
||||||
* `jetty-webapp-logging.jar` - the Jetty side deployment manger app-lifecycle bindings for modifying the `WebAppClassloaders` of deployed webapps.
|
* `jetty-webapp-logging.jar` - the Jetty side deployment manger app-lifecycle bindings for modifying the `WebAppClassloaders` of deployed webapps.
|
||||||
.. Required configuration files are downloaded (if not present already) to the `${jetty.base}/resources/` directory: `jetty-logging.properties`, and `logback.xml`.
|
|
||||||
.. Required initialization commands are downloaded (if not present already) to the `${jetty.base}/etc/` directory: `jetty-logging.xml`, `jetty-webapp-logging.xml`, and `jetty-mdc-handler.xml`.
|
|
||||||
|
|
||||||
At this point the Jetty `mybase` is configured so that the jetty server itself will log using slf4j, and all other logging events from other Jetty Server components (such as database drivers, security layers, jsp, mail, and other 3rd party server components) are routed to logback for filtering and output.
|
At this point the Jetty `mybase` is configured so that the jetty server itself will log using slf4j, and all other logging events from other Jetty Server components (such as database drivers, security layers, jsp, mail, and other 3rd party server components) are routed to logback for filtering and output.
|
||||||
|
|
||||||
|
@ -109,4 +140,5 @@ All webapps deployed via the `DeploymentManager` have their `WebAppClassLoader`
|
||||||
|
|
||||||
The server classpath can be verified by using the `start.jar --list-config` command.
|
The server classpath can be verified by using the `start.jar --list-config` command.
|
||||||
|
|
||||||
In essence, Jetty is now configured to emit its own logging events to slf4j, and various slf4j bridge jars are acting on behalf of log4j, `java.util.logging`, and `commons-logging`, routing all of the logging events to logback (a slf4j adapter) for routing (to console, file, etc...).
|
In essence, Jetty is now configured to emit its own logging events to slf4j, and various slf4j bridge jars are acting on behalf of `log4j`, `java.util.logging`, and `commons-logging`, routing all of the logging events to `logback`
|
||||||
|
(a slf4j implementation) for routing (to console, file, etc...).
|
||||||
|
|
|
@ -23,8 +23,12 @@
|
||||||
:revdate: {TIMESTAMP}
|
:revdate: {TIMESTAMP}
|
||||||
:toc: left
|
:toc: left
|
||||||
:toc-title: Embedded Guide
|
:toc-title: Embedded Guide
|
||||||
:toc-image: ../../common/images/jetty-logo.svg
|
:toc-style:
|
||||||
:toc-image-url: /jetty/index.html
|
|
||||||
|
:header-style: eclipse-thin
|
||||||
|
:breadcrumb-style: eclipse-thin
|
||||||
|
:footer-style: default
|
||||||
|
|
||||||
:breadcrumb: Home:../index.html | Embedded Guide:./index.html
|
:breadcrumb: Home:../index.html | Embedded Guide:./index.html
|
||||||
|
|
||||||
// docinfo lets you pull in shared content and/or influence via render type
|
// docinfo lets you pull in shared content and/or influence via render type
|
||||||
|
@ -43,12 +47,6 @@ endif::[]
|
||||||
// options for special blocks, code snippets, screen, etc
|
// options for special blocks, code snippets, screen, etc
|
||||||
:sub-order: attributes+
|
:sub-order: attributes+
|
||||||
|
|
||||||
// suppress document footer generation
|
|
||||||
//:nofooter:
|
|
||||||
|
|
||||||
// suppress Eclipse footer
|
|
||||||
:no-eclipse-footer:
|
|
||||||
|
|
||||||
// uncomment to allow include::https:// style content inclusion
|
// uncomment to allow include::https:// style content inclusion
|
||||||
//:allow-uri-read: true
|
//:allow-uri-read: true
|
||||||
|
|
||||||
|
|
|
@ -23,15 +23,14 @@
|
||||||
:revdate: {TIMESTAMP}
|
:revdate: {TIMESTAMP}
|
||||||
:toc: left
|
:toc: left
|
||||||
:toc-title: Quickstart Guide
|
:toc-title: Quickstart Guide
|
||||||
:toc-image: ../../common/images/jetty-logo.svg
|
:toc-style:
|
||||||
:toc-image-url: /jetty/index.html
|
|
||||||
|
:header-style: eclipse-thin
|
||||||
|
:breadcrumb-style: eclipse-thin
|
||||||
|
:footer-style: default
|
||||||
|
|
||||||
:breadcrumb: Home:../index.html | Quickstart Guide:./index.html
|
:breadcrumb: Home:../index.html | Quickstart Guide:./index.html
|
||||||
|
|
||||||
|
|
||||||
// docinfo lets you pull in shared content and/or influence via render type
|
|
||||||
//:docinfodir: {DOCINFODIR}/documentation
|
|
||||||
//:docinfo1:
|
|
||||||
|
|
||||||
// html specific directives
|
// html specific directives
|
||||||
ifdef::backend-html5[]
|
ifdef::backend-html5[]
|
||||||
:safe-mode-unsafe:
|
:safe-mode-unsafe:
|
||||||
|
@ -44,10 +43,6 @@ endif::[]
|
||||||
// options for special blocks, code snippets, screen, etc
|
// options for special blocks, code snippets, screen, etc
|
||||||
:sub-order: attributes+
|
:sub-order: attributes+
|
||||||
|
|
||||||
// suppress document footer generation
|
|
||||||
//:nofooter:
|
|
||||||
:no-eclipse-footer:
|
|
||||||
|
|
||||||
// uncomment to allow include::https:// style content inclusion
|
// uncomment to allow include::https:// style content inclusion
|
||||||
//:allow-uri-read: true
|
//:allow-uri-read: true
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Mapping of mime type to inferred or assumed charset
|
# Mapping of mime type to inferred or assumed charset
|
||||||
# inferred charsets are used for encoding/decoding and explicitly set in associated metadata
|
# inferred charsets are used for encoding/decoding and explicitly set in Content-Type
|
||||||
# assumed charsets are used for encoding/decoding, but are not set in associated metadata
|
# assumed charsets are used for encoding/decoding, but are not set in Content-Type
|
||||||
# In this file, assumed charsets are indicated with a leading '-'
|
# In this file, assumed charsets are indicated with a leading '-'
|
||||||
|
|
||||||
text/html=utf-8
|
text/html=utf-8
|
||||||
|
|
|
@ -301,7 +301,7 @@ public class ClientConnector extends ContainerLifeCycle
|
||||||
|
|
||||||
protected class ClientSelectorManager extends SelectorManager
|
protected class ClientSelectorManager extends SelectorManager
|
||||||
{
|
{
|
||||||
protected ClientSelectorManager(Executor executor, Scheduler scheduler, int selectors)
|
public ClientSelectorManager(Executor executor, Scheduler scheduler, int selectors)
|
||||||
{
|
{
|
||||||
super(executor, scheduler, selectors);
|
super(executor, scheduler, selectors);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.nio.ByteBuffer;
|
||||||
/**
|
/**
|
||||||
* <p>A listener for raw network traffic within Jetty.</p>
|
* <p>A listener for raw network traffic within Jetty.</p>
|
||||||
* <p>{@link NetworkTrafficListener}s can be installed in a
|
* <p>{@link NetworkTrafficListener}s can be installed in a
|
||||||
* <code>org.eclipse.jetty.server.nio.NetworkTrafficSelectChannelConnector</code>,
|
* {@code org.eclipse.jetty.server.NetworkTrafficServerConnector},
|
||||||
* and are notified of the following network traffic events:</p>
|
* and are notified of the following network traffic events:</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Connection opened, when the server has accepted the connection from a remote client</li>
|
* <li>Connection opened, when the server has accepted the connection from a remote client</li>
|
||||||
|
@ -45,7 +45,9 @@ public interface NetworkTrafficListener
|
||||||
*
|
*
|
||||||
* @param socket the socket associated with the remote client
|
* @param socket the socket associated with the remote client
|
||||||
*/
|
*/
|
||||||
public void opened(Socket socket);
|
default void opened(Socket socket)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Callback method invoked when bytes sent by a remote client arrived on the server.</p>
|
* <p>Callback method invoked when bytes sent by a remote client arrived on the server.</p>
|
||||||
|
@ -53,7 +55,9 @@ public interface NetworkTrafficListener
|
||||||
* @param socket the socket associated with the remote client
|
* @param socket the socket associated with the remote client
|
||||||
* @param bytes the read-only buffer containing the incoming bytes
|
* @param bytes the read-only buffer containing the incoming bytes
|
||||||
*/
|
*/
|
||||||
public void incoming(Socket socket, ByteBuffer bytes);
|
default void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Callback method invoked when bytes are sent to a remote client from the server.</p>
|
* <p>Callback method invoked when bytes are sent to a remote client from the server.</p>
|
||||||
|
@ -62,7 +66,9 @@ public interface NetworkTrafficListener
|
||||||
* @param socket the socket associated with the remote client
|
* @param socket the socket associated with the remote client
|
||||||
* @param bytes the read-only buffer containing the outgoing bytes
|
* @param bytes the read-only buffer containing the outgoing bytes
|
||||||
*/
|
*/
|
||||||
public void outgoing(Socket socket, ByteBuffer bytes);
|
default void outgoing(Socket socket, ByteBuffer bytes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Callback method invoked when a connection to a remote client has been closed.</p>
|
* <p>Callback method invoked when a connection to a remote client has been closed.</p>
|
||||||
|
@ -74,31 +80,7 @@ public interface NetworkTrafficListener
|
||||||
*
|
*
|
||||||
* @param socket the (closed) socket associated with the remote client
|
* @param socket the (closed) socket associated with the remote client
|
||||||
*/
|
*/
|
||||||
public void closed(Socket socket);
|
default void closed(Socket socket)
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>A commodity class that implements {@link NetworkTrafficListener} with empty methods.</p>
|
|
||||||
*/
|
|
||||||
public static class Adapter implements NetworkTrafficListener
|
|
||||||
{
|
{
|
||||||
@Override
|
|
||||||
public void opened(Socket socket)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void incoming(Socket socket, ByteBuffer bytes)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void outgoing(Socket socket, ByteBuffer bytes)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void closed(Socket socket)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,27 +19,28 @@
|
||||||
package org.eclipse.jetty.io;
|
package org.eclipse.jetty.io;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SelectableChannel;
|
||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class NetworkTrafficSelectChannelEndPoint extends SocketChannelEndPoint
|
/**
|
||||||
|
* <p>A specialized version of {@link SocketChannelEndPoint} that supports {@link NetworkTrafficListener}s.</p>
|
||||||
|
*/
|
||||||
|
public class NetworkTrafficSocketChannelEndPoint extends SocketChannelEndPoint
|
||||||
{
|
{
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(NetworkTrafficSelectChannelEndPoint.class);
|
private static final Logger LOG = LoggerFactory.getLogger(NetworkTrafficSocketChannelEndPoint.class);
|
||||||
|
|
||||||
private final List<NetworkTrafficListener> listeners;
|
private final NetworkTrafficListener listener;
|
||||||
|
|
||||||
public NetworkTrafficSelectChannelEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key, Scheduler scheduler, long idleTimeout, List<NetworkTrafficListener> listeners) throws IOException
|
public NetworkTrafficSocketChannelEndPoint(SelectableChannel channel, ManagedSelector selectSet, SelectionKey key, Scheduler scheduler, long idleTimeout, NetworkTrafficListener listener)
|
||||||
{
|
{
|
||||||
super(channel, selectSet, key, scheduler);
|
super(channel, selectSet, key, scheduler);
|
||||||
setIdleTimeout(idleTimeout);
|
setIdleTimeout(idleTimeout);
|
||||||
this.listeners = listeners;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -60,7 +61,7 @@ public class NetworkTrafficSelectChannelEndPoint extends SocketChannelEndPoint
|
||||||
{
|
{
|
||||||
int position = b.position();
|
int position = b.position();
|
||||||
ByteBuffer view = b.slice();
|
ByteBuffer view = b.slice();
|
||||||
flushed &= super.flush(b);
|
flushed = super.flush(b);
|
||||||
int l = b.position() - position;
|
int l = b.position() - position;
|
||||||
view.limit(view.position() + l);
|
view.limit(view.position() + l);
|
||||||
notifyOutgoing(view);
|
notifyOutgoing(view);
|
||||||
|
@ -75,76 +76,63 @@ public class NetworkTrafficSelectChannelEndPoint extends SocketChannelEndPoint
|
||||||
public void onOpen()
|
public void onOpen()
|
||||||
{
|
{
|
||||||
super.onOpen();
|
super.onOpen();
|
||||||
if (listeners != null && !listeners.isEmpty())
|
if (listener != null)
|
||||||
{
|
{
|
||||||
for (NetworkTrafficListener listener : listeners)
|
try
|
||||||
{
|
{
|
||||||
try
|
listener.opened(getSocket());
|
||||||
{
|
}
|
||||||
listener.opened(getSocket());
|
catch (Throwable x)
|
||||||
}
|
{
|
||||||
catch (Exception x)
|
LOG.info("Exception while invoking listener " + listener, x);
|
||||||
{
|
|
||||||
LOG.warn("listener.opened failure", x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose(Throwable cause)
|
public void onClose(Throwable failure)
|
||||||
{
|
{
|
||||||
super.onClose(cause);
|
super.onClose(failure);
|
||||||
if (listeners != null && !listeners.isEmpty())
|
if (listener != null)
|
||||||
{
|
{
|
||||||
for (NetworkTrafficListener listener : listeners)
|
try
|
||||||
{
|
{
|
||||||
try
|
listener.closed(getSocket());
|
||||||
{
|
}
|
||||||
listener.closed(getSocket());
|
catch (Throwable x)
|
||||||
}
|
{
|
||||||
catch (Exception x)
|
LOG.info("Exception while invoking listener " + listener, x);
|
||||||
{
|
|
||||||
LOG.warn("listener.closed failure", x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyIncoming(ByteBuffer buffer, int read)
|
public void notifyIncoming(ByteBuffer buffer, int read)
|
||||||
{
|
{
|
||||||
if (listeners != null && !listeners.isEmpty() && read > 0)
|
if (listener != null && read > 0)
|
||||||
{
|
{
|
||||||
for (NetworkTrafficListener listener : listeners)
|
try
|
||||||
{
|
{
|
||||||
try
|
ByteBuffer view = buffer.asReadOnlyBuffer();
|
||||||
{
|
listener.incoming(getSocket(), view);
|
||||||
ByteBuffer view = buffer.asReadOnlyBuffer();
|
}
|
||||||
listener.incoming(getSocket(), view);
|
catch (Throwable x)
|
||||||
}
|
{
|
||||||
catch (Exception x)
|
LOG.info("Exception while invoking listener " + listener, x);
|
||||||
{
|
|
||||||
LOG.warn("listener.incoming() failure", x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyOutgoing(ByteBuffer view)
|
public void notifyOutgoing(ByteBuffer view)
|
||||||
{
|
{
|
||||||
if (listeners != null && !listeners.isEmpty() && view.hasRemaining())
|
if (listener != null && view.hasRemaining())
|
||||||
{
|
{
|
||||||
Socket socket = getSocket();
|
try
|
||||||
for (NetworkTrafficListener listener : listeners)
|
|
||||||
{
|
{
|
||||||
try
|
listener.outgoing(getSocket(), view);
|
||||||
{
|
}
|
||||||
listener.outgoing(socket, view);
|
catch (Throwable x)
|
||||||
}
|
{
|
||||||
catch (Exception x)
|
LOG.info("Exception while invoking listener " + listener, x);
|
||||||
{
|
|
||||||
LOG.warn("listener.outgoing() failure", x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,29 +18,26 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.ChannelEndPoint;
|
import org.eclipse.jetty.io.ChannelEndPoint;
|
||||||
import org.eclipse.jetty.io.ManagedSelector;
|
import org.eclipse.jetty.io.ManagedSelector;
|
||||||
import org.eclipse.jetty.io.NetworkTrafficListener;
|
import org.eclipse.jetty.io.NetworkTrafficListener;
|
||||||
import org.eclipse.jetty.io.NetworkTrafficSelectChannelEndPoint;
|
import org.eclipse.jetty.io.NetworkTrafficSocketChannelEndPoint;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A specialized version of {@link ServerConnector} that supports {@link NetworkTrafficListener}s.</p>
|
* <p>A specialized version of {@link ServerConnector} that supports {@link NetworkTrafficListener}s.</p>
|
||||||
* <p>{@link NetworkTrafficListener}s can be added and removed dynamically before and after this connector has
|
* <p>A {@link NetworkTrafficListener} can be set and unset dynamically before and after this connector has
|
||||||
* been started without causing {@link java.util.ConcurrentModificationException}s.</p>
|
* been started.</p>
|
||||||
*/
|
*/
|
||||||
public class NetworkTrafficServerConnector extends ServerConnector
|
public class NetworkTrafficServerConnector extends ServerConnector
|
||||||
{
|
{
|
||||||
private final List<NetworkTrafficListener> listeners = new CopyOnWriteArrayList<>();
|
private volatile NetworkTrafficListener listener;
|
||||||
|
|
||||||
public NetworkTrafficServerConnector(Server server)
|
public NetworkTrafficServerConnector(Server server)
|
||||||
{
|
{
|
||||||
|
@ -68,25 +65,24 @@ public class NetworkTrafficServerConnector extends ServerConnector
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param listener the listener to add
|
* @param listener the listener to set, or null to unset
|
||||||
*/
|
*/
|
||||||
public void addNetworkTrafficListener(NetworkTrafficListener listener)
|
public void setNetworkTrafficListener(NetworkTrafficListener listener)
|
||||||
{
|
{
|
||||||
listeners.add(listener);
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param listener the listener to remove
|
* @return the listener
|
||||||
*/
|
*/
|
||||||
public void removeNetworkTrafficListener(NetworkTrafficListener listener)
|
public NetworkTrafficListener getNetworkTrafficListener()
|
||||||
{
|
{
|
||||||
listeners.remove(listener);
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
|
protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key)
|
||||||
{
|
{
|
||||||
NetworkTrafficSelectChannelEndPoint endPoint = new NetworkTrafficSelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout(), listeners);
|
return new NetworkTrafficSocketChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout(), getNetworkTrafficListener());
|
||||||
return endPoint;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ public class Response implements HttpServletResponse
|
||||||
NOT_SET, INFERRED, SET_LOCALE, SET_CONTENT_TYPE, SET_CHARACTER_ENCODING
|
NOT_SET, INFERRED, SET_LOCALE, SET_CONTENT_TYPE, SET_CHARACTER_ENCODING
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final EnumSet<EncodingFrom> __localeOverride = EnumSet.of(EncodingFrom.NOT_SET, EncodingFrom.INFERRED);
|
private static final EnumSet<EncodingFrom> __localeOverride = EnumSet.of(EncodingFrom.NOT_SET, EncodingFrom.INFERRED, EncodingFrom.SET_LOCALE);
|
||||||
private static final EnumSet<EncodingFrom> __explicitCharset = EnumSet.of(EncodingFrom.SET_LOCALE, EncodingFrom.SET_CHARACTER_ENCODING);
|
private static final EnumSet<EncodingFrom> __explicitCharset = EnumSet.of(EncodingFrom.SET_LOCALE, EncodingFrom.SET_CHARACTER_ENCODING);
|
||||||
|
|
||||||
public Response(HttpChannel channel, HttpOutput out)
|
public Response(HttpChannel channel, HttpOutput out)
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
|
||||||
//
|
|
||||||
// This program and the accompanying materials are made available under
|
|
||||||
// the terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
// https://www.eclipse.org/legal/epl-2.0
|
|
||||||
//
|
|
||||||
// This Source Code may also be made available under the following
|
|
||||||
// Secondary Licenses when the conditions for such availability set
|
|
||||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
|
||||||
// the Apache License v2.0 which is available at
|
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
|
||||||
// ========================================================================
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Jetty Server : Core Server Connector
|
|
||||||
*/
|
|
||||||
package org.eclipse.jetty.server.nio;
|
|
||||||
|
|
|
@ -279,7 +279,8 @@ public class SessionHandler extends ScopedHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call the session lifecycle listeners
|
* Call the session lifecycle listeners in
|
||||||
|
* the reverse order they were added.
|
||||||
*
|
*
|
||||||
* @param session the session on which to call the lifecycle listeners
|
* @param session the session on which to call the lifecycle listeners
|
||||||
*/
|
*/
|
||||||
|
@ -310,7 +311,8 @@ public class SessionHandler extends ScopedHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call the session lifecycle listeners
|
* Call the session lifecycle listeners in the order
|
||||||
|
* they were added.
|
||||||
*
|
*
|
||||||
* @param session the session on which to call the lifecycle listeners
|
* @param session the session on which to call the lifecycle listeners
|
||||||
*/
|
*/
|
||||||
|
@ -322,9 +324,9 @@ public class SessionHandler extends ScopedHandler
|
||||||
if (_sessionListeners != null)
|
if (_sessionListeners != null)
|
||||||
{
|
{
|
||||||
HttpSessionEvent event = new HttpSessionEvent(session);
|
HttpSessionEvent event = new HttpSessionEvent(session);
|
||||||
for (int i = _sessionListeners.size() - 1; i >= 0; i--)
|
for (HttpSessionListener l : _sessionListeners)
|
||||||
{
|
{
|
||||||
_sessionListeners.get(i).sessionCreated(event);
|
l.sessionCreated(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.ServletOutputStream;
|
import jakarta.servlet.ServletOutputStream;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.NetworkTrafficListener;
|
import org.eclipse.jetty.io.NetworkTrafficListener;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
@ -78,7 +79,7 @@ public class NetworkTrafficListenerTest
|
||||||
|
|
||||||
final CountDownLatch openedLatch = new CountDownLatch(1);
|
final CountDownLatch openedLatch = new CountDownLatch(1);
|
||||||
final CountDownLatch closedLatch = new CountDownLatch(1);
|
final CountDownLatch closedLatch = new CountDownLatch(1);
|
||||||
connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
connector.setNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
||||||
{
|
{
|
||||||
public volatile Socket socket;
|
public volatile Socket socket;
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ public class NetworkTrafficListenerTest
|
||||||
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
||||||
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
||||||
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
||||||
connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
connector.setNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void incoming(Socket socket, ByteBuffer bytes)
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
@ -188,7 +189,7 @@ public class NetworkTrafficListenerTest
|
||||||
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
||||||
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
||||||
final CountDownLatch outgoingLatch = new CountDownLatch(2);
|
final CountDownLatch outgoingLatch = new CountDownLatch(2);
|
||||||
connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
connector.setNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void incoming(Socket socket, ByteBuffer bytes)
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
@ -258,7 +259,7 @@ public class NetworkTrafficListenerTest
|
||||||
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
||||||
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
||||||
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
||||||
connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
connector.setNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void incoming(Socket socket, ByteBuffer bytes)
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
@ -328,7 +329,7 @@ public class NetworkTrafficListenerTest
|
||||||
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
final CountDownLatch incomingLatch = new CountDownLatch(1);
|
||||||
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
||||||
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
||||||
connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
connector.setNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void incoming(Socket socket, ByteBuffer bytes)
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
@ -404,7 +405,7 @@ public class NetworkTrafficListenerTest
|
||||||
final AtomicReference<String> incomingData = new AtomicReference<>("");
|
final AtomicReference<String> incomingData = new AtomicReference<>("");
|
||||||
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
final AtomicReference<String> outgoingData = new AtomicReference<>("");
|
||||||
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
final CountDownLatch outgoingLatch = new CountDownLatch(1);
|
||||||
connector.addNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
connector.setNetworkTrafficListener(new NetworkTrafficListener.Adapter()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void incoming(Socket socket, ByteBuffer bytes)
|
public void incoming(Socket socket, ByteBuffer bytes)
|
||||||
|
|
|
@ -54,6 +54,7 @@ import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpURI;
|
import org.eclipse.jetty.http.HttpURI;
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http.MetaData;
|
import org.eclipse.jetty.http.MetaData;
|
||||||
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
import org.eclipse.jetty.io.AbstractEndPoint;
|
import org.eclipse.jetty.io.AbstractEndPoint;
|
||||||
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
import org.eclipse.jetty.io.ByteArrayEndPoint;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
@ -474,6 +475,67 @@ public class ResponseTest
|
||||||
response.getWriter();
|
response.getWriter();
|
||||||
assertThat("iso-8859-1", Matchers.equalTo(response.getCharacterEncoding()));
|
assertThat("iso-8859-1", Matchers.equalTo(response.getCharacterEncoding()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocaleAndContentTypeEncoding() throws Exception
|
||||||
|
{
|
||||||
|
_server.stop();
|
||||||
|
MimeTypes.getInferredEncodings().put("text/html", "iso-8859-1");
|
||||||
|
ContextHandler handler = new ContextHandler();
|
||||||
|
handler.addLocaleEncoding("ja", "euc-jp");
|
||||||
|
handler.addLocaleEncoding("zh_CN", "gb18030");
|
||||||
|
_server.setHandler(handler);
|
||||||
|
handler.setHandler(new DumpHandler());
|
||||||
|
_server.start();
|
||||||
|
|
||||||
|
Response response = getResponse();
|
||||||
|
response.getHttpChannel().getRequest().setContext(handler.getServletContext());
|
||||||
|
|
||||||
|
response.setContentType("text/html");
|
||||||
|
assertEquals("iso-8859-1", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setLocale should change character encoding based on
|
||||||
|
// locale-encoding-mapping-list
|
||||||
|
response.setLocale(Locale.JAPAN);
|
||||||
|
assertEquals("euc-jp", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setLocale should change character encoding based on
|
||||||
|
// locale-encoding-mapping-list
|
||||||
|
response.setLocale(Locale.CHINA);
|
||||||
|
assertEquals("gb18030", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setContentType here doesn't define character encoding
|
||||||
|
response.setContentType("text/html");
|
||||||
|
assertEquals("gb18030", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setCharacterEncoding should still be able to change encoding
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
assertEquals("utf-8", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setLocale should not override explicit character encoding request
|
||||||
|
response.setLocale(Locale.JAPAN);
|
||||||
|
assertEquals("utf-8", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setContentType should still be able to change encoding
|
||||||
|
response.setContentType("text/html;charset=gb18030");
|
||||||
|
assertEquals("gb18030", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setCharacterEncoding should still be able to change encoding
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
assertEquals("utf-8", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// getWriter should freeze the character encoding
|
||||||
|
PrintWriter pw = response.getWriter();
|
||||||
|
assertEquals("utf-8", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setCharacterEncoding should no longer be able to change the encoding
|
||||||
|
response.setCharacterEncoding("iso-8859-1");
|
||||||
|
assertEquals("utf-8", response.getCharacterEncoding());
|
||||||
|
|
||||||
|
// setLocale should not override explicit character encoding request
|
||||||
|
response.setLocale(Locale.JAPAN);
|
||||||
|
assertEquals("utf-8", response.getCharacterEncoding());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testContentTypeCharacterEncoding() throws Exception
|
public void testContentTypeCharacterEncoding() throws Exception
|
||||||
|
|
|
@ -23,8 +23,15 @@ import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import jakarta.servlet.SessionTrackingMode;
|
import jakarta.servlet.SessionTrackingMode;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import jakarta.servlet.http.HttpSessionEvent;
|
||||||
|
import jakarta.servlet.http.HttpSessionListener;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
public class SessionHandlerTest
|
public class SessionHandlerTest
|
||||||
|
@ -35,7 +42,64 @@ public class SessionHandlerTest
|
||||||
SessionHandler sessionHandler = new SessionHandler();
|
SessionHandler sessionHandler = new SessionHandler();
|
||||||
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)));
|
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)));
|
||||||
sessionHandler.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.SSL));
|
sessionHandler.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.SSL));
|
||||||
assertThrows(IllegalArgumentException.class,() ->
|
assertThrows(IllegalArgumentException.class, () -> sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.SSL, SessionTrackingMode.URL))));
|
||||||
sessionHandler.setSessionTrackingModes(new HashSet<>(Arrays.asList(SessionTrackingMode.SSL, SessionTrackingMode.URL))));
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSessionListenerOrdering()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
final StringBuffer result = new StringBuffer();
|
||||||
|
|
||||||
|
class Listener1 implements HttpSessionListener
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionCreated(HttpSessionEvent se)
|
||||||
|
{
|
||||||
|
result.append("Listener1 create;");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionDestroyed(HttpSessionEvent se)
|
||||||
|
{
|
||||||
|
result.append("Listener1 destroy;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Listener2 implements HttpSessionListener
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionCreated(HttpSessionEvent se)
|
||||||
|
{
|
||||||
|
result.append("Listener2 create;");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionDestroyed(HttpSessionEvent se)
|
||||||
|
{
|
||||||
|
result.append("Listener2 destroy;");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Server server = new Server();
|
||||||
|
SessionHandler sessionHandler = new SessionHandler();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sessionHandler.addEventListener(new Listener1());
|
||||||
|
sessionHandler.addEventListener(new Listener2());
|
||||||
|
sessionHandler.setServer(server);
|
||||||
|
sessionHandler.start();
|
||||||
|
Session session = new Session(sessionHandler, new SessionData("aa", "_", "0.0", 0, 0, 0, 0));
|
||||||
|
sessionHandler.callSessionCreatedListeners(session);
|
||||||
|
sessionHandler.callSessionDestroyedListeners(session);
|
||||||
|
assertEquals("Listener1 create;Listener2 create;Listener2 destroy;Listener1 destroy;", result.toString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
sessionHandler.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ import org.slf4j.LoggerFactory;
|
||||||
* resources could be found. If false, then a welcome
|
* resources could be found. If false, then a welcome
|
||||||
* file must exist on disk. If "exact", then exact
|
* file must exist on disk. If "exact", then exact
|
||||||
* servlet matches are supported without an existing file.
|
* servlet matches are supported without an existing file.
|
||||||
* Default is true.
|
* Default is false.
|
||||||
*
|
*
|
||||||
* This must be false if you want directory listings,
|
* This must be false if you want directory listings,
|
||||||
* but have index.jsp in your welcome file list.
|
* but have index.jsp in your welcome file list.
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class CertificateUtils
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!store.exists())
|
if (!store.exists())
|
||||||
throw new IllegalStateException("no valid keystore");
|
throw new IllegalStateException(store.getName() + " is not a valid keystore");
|
||||||
|
|
||||||
try (InputStream inStream = store.getInputStream())
|
try (InputStream inStream = store.getInputStream())
|
||||||
{
|
{
|
||||||
|
|
|
@ -217,7 +217,7 @@ public class SslContextFactoryTest
|
||||||
cf.setTrustStorePath("/foo");
|
cf.setTrustStorePath("/foo");
|
||||||
cf.start();
|
cf.start();
|
||||||
});
|
});
|
||||||
assertThat(x.getMessage(), containsString("no valid keystore"));
|
assertThat(x.getMessage(), equalTo("/foo is not a valid keystore"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
* resources could be found. If false, then a welcome
|
* resources could be found. If false, then a welcome
|
||||||
* file must exist on disk. If "exact", then exact
|
* file must exist on disk. If "exact", then exact
|
||||||
* servlet matches are supported without an existing file.
|
* servlet matches are supported without an existing file.
|
||||||
* Default is true.
|
* Default is false.
|
||||||
*
|
*
|
||||||
* This must be false if you want directory listings,
|
* This must be false if you want directory listings,
|
||||||
* but have index.jsp in your welcome file list.
|
* but have index.jsp in your welcome file list.
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
# Jetty Logging using jetty-slf4j-impl
|
# Jetty Logging using jetty-slf4j-impl
|
||||||
|
org.eclipse.jetty.logging.appender.MESSAGE_ESCAPE=false
|
||||||
#org.eclipse.jetty.LEVEL=DEBUG
|
#org.eclipse.jetty.LEVEL=DEBUG
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.openwebbeans</groupId>
|
<groupId>org.apache.openwebbeans</groupId>
|
||||||
<artifactId>openwebbeans-jetty9</artifactId>
|
<artifactId>openwebbeans-jetty9</artifactId>
|
||||||
<version>2.0.11</version>
|
<version>2.0.15</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||||
|
|
||||||
<Configure id="webAppCtx" class="org.eclipse.jetty.webapp.WebAppContext">
|
<Configure id="webAppCtx" class="org.eclipse.jetty.webapp.WebAppContext">
|
||||||
|
<!-- Enable OWB ServletContainerInitializer
|
||||||
|
See: https://issues.apache.org/jira/browse/OWB-1296 -->
|
||||||
|
<Call name="setInitParameter">
|
||||||
|
<Arg>openwebbeans.web.sci.active</Arg>
|
||||||
|
<Arg>true</Arg>
|
||||||
|
</Call>
|
||||||
|
|
||||||
<New id="BeanManager" class="org.eclipse.jetty.plus.jndi.Resource">
|
<New id="BeanManager" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||||
<Arg>
|
<Arg>
|
||||||
<Ref refid="webAppCtx"/>
|
<Ref refid="webAppCtx" />
|
||||||
</Arg>
|
</Arg>
|
||||||
<Arg>BeanManager</Arg>
|
<Arg>BeanManager</Arg>
|
||||||
<Arg>
|
<Arg>
|
||||||
|
|
Loading…
Reference in New Issue