Merge branch `jetty-9.4.x` into `jetty-10.0.x`
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com> # Conflicts: # aggregates/jetty-all-compact3/pom.xml # jetty-alpn/jetty-alpn-openjdk8-client/pom.xml # jetty-alpn/jetty-alpn-openjdk8-client/src/main/java/org/eclipse/jetty/alpn/java/client/OpenJDK8ClientALPNProcessor.java # jetty-alpn/jetty-alpn-openjdk8-server/pom.xml # jetty-alpn/jetty-alpn-openjdk8-server/src/main/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8ServerALPNProcessor.java # jetty-annotations/src/main/config/etc/jetty-annotations.xml # jetty-cdi/src/main/config/etc/cdi2/jetty-cdi2.xml # jetty-cdi/src/main/config/etc/cdi2/jetty-web-cdi2.xml # jetty-continuation/pom.xml # jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java # jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationFilter.java # jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java # jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java # jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java # jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java # jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java # jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java # jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java # jetty-http/src/test/java/org/eclipse/jetty/http/HttpTesterTest.java # jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java # jetty-http2/http2-alpn-tests/pom.xml # jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java # jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java # jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java # jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java # jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java # jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java # jetty-jmh/src/main/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java # jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/ForwardBenchmark.java # jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java # jetty-overlay-deployer/pom.xml # jetty-overlay-deployer/src/main/config/etc/jetty-overlay.xml # jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java # jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/TemplateContext.java # jetty-overlay-deployer/src/test/java/org/eclipse/jetty/overlays/OverlayServer.java # jetty-overlay-deployer/src/test/java/org/eclipse/jetty/overlays/OverlayedAppProviderTest.java # jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=blue/WEB-INF/overlay.xml # jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=green/WEB-INF/overlay.xml # jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=red/WEB-INF/overlay.xml # jetty-overlay-deployer/src/test/resources/home/overlays/instances/root=root/WEB-INF/overlay.xml # jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml # jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/template.xml # jetty-overlay-deployer/src/test/resources/home/overlays/templates/root/WEB-INF/overlay.xml # jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java # jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java # jetty-server/src/main/config/etc/jetty-customrequestlog.xml # jetty-server/src/main/config/etc/jetty-ipaccess.xml # jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java # jetty-server/src/main/java/org/eclipse/jetty/server/ConnectorStatistics.java # jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormDataCompliance.java # jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java # jetty-server/src/main/java/org/eclipse/jetty/server/PushBuilder.java # jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java # jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java # jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java # jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java # jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java # jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterLayeredTest.java # jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java # jetty-unixsocket/src/main/config/etc/jetty-unixsocket-forwarded.xml # jetty-unixsocket/src/main/config/etc/jetty-unixsocket-http2c.xml # jetty-unixsocket/src/main/java/org/eclipse/jetty/unixsocket/client/HttpClientTransportOverUnixSockets.java # jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java # jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentHashSet.java # jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java # jetty-util/src/main/java/org/eclipse/jetty/util/ModuleLocation.java # jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java # jetty-util/src/main/java/org/eclipse/jetty/util/ReadLineInputStream.java # jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java # jetty-util/src/test/java/org/eclipse/jetty/util/B64CodeTest.java # jetty-util/src/test/java/org/eclipse/jetty/util/CollectionAssert.java # jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java # jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java # jetty-util/src/test/java/org/eclipse/jetty/util/ReadLineInputStreamTest.java # jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java # jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/AbstractJsrRemote.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/DecoderFactory.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/EncoderFactory.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JettyClientContainerProvider.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrBasicRemote.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrUpgradeListener.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactory.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerWrapper.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointMetadata.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointScanner.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/IJsrMethod.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/IJsrParamId.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrEvents.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdBinary.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdDecoder.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnClose.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnError.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnOpen.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdPong.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdText.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnCloseCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnErrorCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryStreamCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessagePongCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextStreamCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnOpenCallable.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/Param.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/client/AnnotatedClientEndpointMetadata.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/client/JsrClientEndpointImpl.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/client/SimpleEndpointMetadata.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/PrimitiveDecoderMetadataSet.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/DefaultTextStreamEncoder.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/PrimitiveEncoderMetadataSet.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/AbstractJsrEventDriver.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/JsrAnnotatedEventDriver.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/JsrEndpointEventDriver.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/JsrEndpointImpl.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryPartialMessage.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryPartialOnMessage.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryWholeMessage.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialMessage.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialOnMessage.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadata.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/DecoderMetadata.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/DecoderMetadataSet.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/EncoderMetadata.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/EncoderMetadataSet.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/EndpointMetadata.java # jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/utils/Primitives.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/AnnotatedEchoTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/AnnotatedEndpointClient.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/AnnotatedEndpointConfigurator.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/CookiesTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderFactoryTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderManySmallTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderFactoryTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoClient.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/LargeMessageTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactoryTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/MessageQueue.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/MessageReceivingTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdDecoderTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/decoders/PrimitiveDecoderMetadataSetTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/demo/ExampleClient.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/ClientAnnotatedEndpointScanner_GoodSignaturesTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/ClientAnnotatedEndpointScanner_InvalidSignaturesTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/OnCloseTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/TrackingSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicBinaryMessageByteBufferSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicErrorSessionSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicErrorSessionThrowableSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicErrorThrowableSessionSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicErrorThrowableSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicInputStreamSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicOpenCloseSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicPongMessageSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/BasicTextMessageStringSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidCloseIntSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorErrorSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorIntSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenCloseReasonSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenIntSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenSessionIntSocket.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/metadata/DecoderMetadataSetTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/metadata/EncoderMetadataSetTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/misbehaving/MisbehavingClassTest.java # jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/utils/TypeTree.java # jetty-websocket/javax-websocket-server-impl/pom.xml # jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointMetadata.java # jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrPathParamId.java # jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrServerEndpointImpl.java # jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrServerExtendsEndpointImpl.java # jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java # jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerEndpointMetadata.java # jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/SimpleServerEndpointMetadata.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DelayedStartClientOnServerTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoCase.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoClientSocket.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ExtensionStackProcessingTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/IdleTimeoutTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/LargeAnnotatedTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/LargeClientContainerServlet.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/LargeContainerTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/LargeNestedClientContainerTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/LargeOnOpenSessionConfiguredTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/LargeServerContainerAsClientContainerServlet.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnMessageReturnTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/PingPongTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_GoodSignaturesTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_InvalidSignaturesTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionAltConfig.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionInfoEndpoint.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionInfoSocket.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TrackingSocket.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorExceptionSocket.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTimeEncoder.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/TimeDecoder.java # jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/ConcurrentConnectTest.java # jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/WebSocketNegotiationTest.java # jetty-websocket/websocket-api/pom.xml # jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/RemoteEndpoint.java # jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPolicy.java # jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java # jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java # jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/QuoteUtilTest.java # jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/QuoteUtil_QuoteTest.java # jetty-websocket/websocket-client/pom.xml # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeResponse.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/DefaultHttpClientProvider.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/HttpClientProvider.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketUpgradeRequest.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/masks/FixedMasker.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/masks/RandomMasker.java # jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/package-info.java # jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ConnectionManagerTest.java # jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/CookieTest.java # jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/JettyTrackingSocket.java # jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/MaxMessageSocket.java # jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java # jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientBadUriTest.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/CloseInfo.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Generator.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/UpgradeResponseAdapter.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketFrame.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpoint.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriverFactory.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriverImpl.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyAnnotatedEventDriver.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyAnnotatedImpl.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyAnnotatedMetadata.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyAnnotatedScanner.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerEventDriver.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerImpl.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/AbstractMethodAnnotationScanner.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/EventMethod.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/EventMethods.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/InvalidSignatureException.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/OptionalSessionCallableMethod.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/CloseFrame.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/ContinuationFrame.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/ControlFrame.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/DataFrame.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/PongFrame.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/ConnectionState.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FrameFlusher.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FramePipes.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/ReadState.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/http/HttpResponseHeaderParser.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/payload/DeMaskProcessor.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/payload/PayloadProcessor.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageAppender.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/SimpleBinaryMessage.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/DelegatedContainerScope.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java # jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilder.java # jetty-websocket/websocket-common/src/test/java/examples/AdapterConnectCloseSocket.java # jetty-websocket/websocket-common/src/test/java/examples/AnnotatedFramesSocket.java # jetty-websocket/websocket-common/src/test/java/examples/AnnotatedStreamingSocket.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/AcceptHashTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/CloseInfoTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ClosePayloadParserTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ParserTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/PingPayloadParserTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/RFC6455ExamplesGeneratorTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/RFC6455ExamplesParserTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/SaneFrameOrderingAssertion.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/TextPayloadParserTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/UpgradeResponseAdapterTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpointTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_1.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_2.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase2.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase3.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase4.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase7_3.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventCapture.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventDriverFactoryTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventDriverTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/JettyAnnotatedScannerTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/DummyOutgoingFrames.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/ByteAccumulatorTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/FrameFlusherTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketSession.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/http/HttpResponseHeaderParserTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/http/HttpResponseParseCapture.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/payload/DeMaskProcessorTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageDebug.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageOutputStreamTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageWriterTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/TrackingInputStreamSocket.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/TrackingSocket.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClientRequest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadConnection.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/ByteBufferAssert.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Fuzzer.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/HttpResponse.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IncomingFramesCapture.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/MoreMatchers.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingFramesCapture.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitGenerator.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitParser.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Hex.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/MaskedByteBuffer.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/ReflectUtilsTest.java # jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java # jetty-websocket/websocket-server/pom.xml # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/MappedWebSocketCreator.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/NativeWebSocketConfiguration.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/NativeWebSocketServletContainerInitializer.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandler.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeHandlerWrapper.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpec.java # jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpec.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/AnnotatedMaxMessageSizeTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ChromeTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsLegacyTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FirefoxTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdleTimeoutTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/InfoContextAltAttributeListener.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/InfoContextAttributeListener.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/InfoContextListener.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/InfoServlet.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/InfoSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/PerMessageDeflateExtensionTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SubProtocolTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WSServer.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketProtocolTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServerFactoryTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServerSessionTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilterTest.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/ABSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AbstractABCase.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase1.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase2.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase3.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase4.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase5.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6_BadUTF.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6_GoodUTF.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase9.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/examples/BasicEchoSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/examples/echo/BigEchoSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/examples/echo/EchoBroadcastPingSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/examples/echo/EchoFragmentSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/examples/echo/ExampleEchoServer.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/examples/echo/LogSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/EchoServlet.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/EchoSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/RFCSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SafariD00.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SessionSocket.java # jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/misbehaving/MisbehavingClassTest.java # jetty-websocket/websocket-server/src/test/resources/wsuf-config-via-listener.xml # jetty-websocket/websocket-server/src/test/resources/wsuf-config-via-servlet-init.xml # tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationsTest.java
This commit is contained in:
commit
daba115e32
|
@ -125,7 +125,7 @@ public class ResourceHttpContent implements HttpContent
|
|||
@Override
|
||||
public ByteBuffer getDirectBuffer()
|
||||
{
|
||||
if (_resource.length() <= 0 || _maxBuffer > 0 && _maxBuffer < _resource.length())
|
||||
if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer)
|
||||
return null;
|
||||
try
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ public class ResourceHttpContent implements HttpContent
|
|||
@Override
|
||||
public ByteBuffer getIndirectBuffer()
|
||||
{
|
||||
if (_resource.length() <= 0 || _maxBuffer > 0 && _maxBuffer < _resource.length())
|
||||
if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer)
|
||||
return null;
|
||||
try
|
||||
{
|
||||
|
|
|
@ -329,13 +329,14 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
{
|
||||
try
|
||||
{
|
||||
return BufferUtil.toBuffer(resource, true);
|
||||
return BufferUtil.toBuffer(resource, false);
|
||||
}
|
||||
catch (IOException | IllegalArgumentException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ByteBuffer getMappedBuffer(Resource resource)
|
||||
|
@ -349,7 +350,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
}
|
||||
catch (IOException | IllegalArgumentException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -362,7 +364,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
}
|
||||
catch (IOException | IllegalArgumentException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -380,7 +383,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
{
|
||||
private final String _key;
|
||||
private final Resource _resource;
|
||||
private final int _contentLengthValue;
|
||||
private final long _contentLengthValue;
|
||||
private final HttpField _contentType;
|
||||
private final String _characterEncoding;
|
||||
private final MimeTypes.Type _mimeType;
|
||||
|
@ -409,7 +412,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
_lastModified = _lastModifiedValue == -1 ? null
|
||||
: new PreEncodedHttpField(HttpHeader.LAST_MODIFIED, DateGenerator.formatDate(_lastModifiedValue));
|
||||
|
||||
_contentLengthValue = exists ? (int)resource.length() : 0;
|
||||
_contentLengthValue = exists ? resource.length() : 0;
|
||||
_contentLength = new PreEncodedHttpField(HttpHeader.CONTENT_LENGTH, Long.toString(_contentLengthValue));
|
||||
|
||||
if (_cachedFiles.incrementAndGet() > _maxCachedFiles)
|
||||
|
@ -546,25 +549,34 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
@Override
|
||||
public ByteBuffer getIndirectBuffer()
|
||||
{
|
||||
if (_resource.length() > _maxCachedFileSize)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteBuffer buffer = _indirectBuffer.get();
|
||||
if (buffer == null)
|
||||
{
|
||||
ByteBuffer buffer2 = CachedContentFactory.this.getIndirectBuffer(_resource);
|
||||
|
||||
if (buffer2 == null)
|
||||
LOG.warn("Could not load " + this);
|
||||
else if (_indirectBuffer.compareAndSet(null, buffer2))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Could not load indirect buffer from " + this);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_indirectBuffer.compareAndSet(null, buffer2))
|
||||
{
|
||||
buffer = buffer2;
|
||||
if (_cachedSize.addAndGet(BufferUtil.length(buffer)) > _maxCacheSize)
|
||||
shrinkCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = _indirectBuffer.get();
|
||||
}
|
||||
}
|
||||
if (buffer == null)
|
||||
return null;
|
||||
return buffer.slice();
|
||||
return buffer == null ? null : buffer.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -583,7 +595,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
else
|
||||
buffer = _mappedBuffer.get();
|
||||
}
|
||||
else
|
||||
// Since MappedBuffers don't use heap, we don't care about the resource.length
|
||||
else if (_resource.length() < _maxCachedFileSize)
|
||||
{
|
||||
ByteBuffer direct = CachedContentFactory.this.getDirectBuffer(_resource);
|
||||
if (direct != null)
|
||||
|
@ -601,7 +614,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
}
|
||||
else
|
||||
{
|
||||
LOG.warn("Could not load " + this);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Could not load " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,11 +291,23 @@ public class HttpConfiguration implements Dumpable
|
|||
return _sendXPoweredBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the {@code Date} header should be sent in responses.
|
||||
*
|
||||
* @param sendDateHeader true if the {@code Date} header should be sent in responses
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7231#section-7.1.1.2">HTTP/1.1 Standard Header: Date</a>
|
||||
* @see #getSendDateHeader()
|
||||
*/
|
||||
public void setSendDateHeader(boolean sendDateHeader)
|
||||
{
|
||||
_sendDateHeader = sendDateHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the {@code Date} header will be sent in responses.
|
||||
*
|
||||
* @return true by default
|
||||
*/
|
||||
@ManagedAttribute("Whether to send the Date header in responses")
|
||||
public boolean getSendDateHeader()
|
||||
{
|
||||
|
|
|
@ -683,9 +683,21 @@ public class Request implements HttpServletRequest
|
|||
MetaData.Request metadata = _metaData;
|
||||
if (metadata == null)
|
||||
return -1;
|
||||
if (metadata.getContentLength() != Long.MIN_VALUE)
|
||||
return (int)metadata.getContentLength();
|
||||
return (int)metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.toString());
|
||||
|
||||
long contentLength = metadata.getContentLength();
|
||||
if (contentLength != Long.MIN_VALUE)
|
||||
{
|
||||
if (contentLength > Integer.MAX_VALUE)
|
||||
{
|
||||
// Per ServletRequest#getContentLength() javadoc this must return -1 for values exceeding Integer.MAX_VALUE
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)contentLength;
|
||||
}
|
||||
}
|
||||
return (int)metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.asString());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -699,7 +711,7 @@ public class Request implements HttpServletRequest
|
|||
return -1L;
|
||||
if (metadata.getContentLength() != Long.MIN_VALUE)
|
||||
return metadata.getContentLength();
|
||||
return metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.toString());
|
||||
return metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.asString());
|
||||
}
|
||||
|
||||
public long getContentRead()
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
|
@ -46,9 +45,10 @@ import org.eclipse.jetty.http.PreEncodedHttpField;
|
|||
import org.eclipse.jetty.http.QuotedCSV;
|
||||
import org.eclipse.jetty.http.QuotedQualityCSV;
|
||||
import org.eclipse.jetty.io.WriterOutputStream;
|
||||
import org.eclipse.jetty.server.resource.HttpContentRangeWriter;
|
||||
import org.eclipse.jetty.server.resource.RangeWriter;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.MultiPartOutputStream;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -780,9 +780,6 @@ public class ResourceService
|
|||
MultiPartOutputStream multi = new MultiPartOutputStream(out);
|
||||
response.setContentType(ctp + multi.getBoundary());
|
||||
|
||||
InputStream in = content.getResource().getInputStream();
|
||||
long pos = 0;
|
||||
|
||||
// calculate the content-length
|
||||
int length = 0;
|
||||
String[] header = new String[ranges.size()];
|
||||
|
@ -802,39 +799,17 @@ public class ResourceService
|
|||
length += 2 + 2 + multi.getBoundary().length() + 2 + 2;
|
||||
response.setContentLength(length);
|
||||
|
||||
i = 0;
|
||||
for (InclusiveByteRange ibr : ranges)
|
||||
try (RangeWriter rangeWriter = HttpContentRangeWriter.newRangeWriter(content))
|
||||
{
|
||||
multi.startPart(mimetype, new String[]{HttpHeader.CONTENT_RANGE + ": " + header[i]});
|
||||
|
||||
long start = ibr.getFirst();
|
||||
long size = ibr.getSize();
|
||||
if (in != null)
|
||||
i = 0;
|
||||
for (InclusiveByteRange ibr : ranges)
|
||||
{
|
||||
// Handle non cached resource
|
||||
if (start < pos)
|
||||
{
|
||||
in.close();
|
||||
in = content.getResource().getInputStream();
|
||||
pos = 0;
|
||||
}
|
||||
if (pos < start)
|
||||
{
|
||||
in.skip(start - pos);
|
||||
pos = start;
|
||||
}
|
||||
|
||||
IO.copy(in, multi, size);
|
||||
pos += size;
|
||||
multi.startPart(mimetype, new String[]{HttpHeader.CONTENT_RANGE + ": " + header[i]});
|
||||
rangeWriter.writeTo(multi, ibr.getFirst(), ibr.getSize());
|
||||
i++;
|
||||
}
|
||||
else
|
||||
// Handle cached resource
|
||||
content.getResource().writeTo(multi, start, size);
|
||||
|
||||
i++;
|
||||
}
|
||||
if (in != null)
|
||||
in.close();
|
||||
|
||||
multi.close();
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* ByteBuffer based RangeWriter
|
||||
*/
|
||||
public class ByteBufferRangeWriter implements RangeWriter
|
||||
{
|
||||
private final ByteBuffer buffer;
|
||||
private boolean closed = false;
|
||||
|
||||
public ByteBufferRangeWriter(ByteBuffer buffer)
|
||||
{
|
||||
this.buffer = buffer.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream outputStream, long skipTo, long length) throws IOException
|
||||
{
|
||||
if (skipTo > Integer.MAX_VALUE)
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported skipTo " + skipTo + " > " + Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
if (length > Integer.MAX_VALUE)
|
||||
{
|
||||
throw new IllegalArgumentException("Unsupported length " + skipTo + " > " + Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
ByteBuffer src = buffer.slice();
|
||||
src.position((int)skipTo);
|
||||
src.limit(Math.addExact((int)skipTo, (int)length));
|
||||
BufferUtil.writeTo(src, outputStream);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* Range Writer selection for HttpContent
|
||||
*/
|
||||
public class HttpContentRangeWriter
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpContentRangeWriter.class);
|
||||
|
||||
/**
|
||||
* Obtain a new RangeWriter for the supplied HttpContent.
|
||||
*
|
||||
* @param content the HttpContent to base RangeWriter on
|
||||
* @return the RangeWriter best suited for the supplied HttpContent
|
||||
*/
|
||||
public static RangeWriter newRangeWriter(HttpContent content)
|
||||
{
|
||||
Objects.requireNonNull(content, "HttpContent");
|
||||
|
||||
// Try direct buffer
|
||||
ByteBuffer buffer = content.getDirectBuffer();
|
||||
if (buffer == null)
|
||||
{
|
||||
buffer = content.getIndirectBuffer();
|
||||
}
|
||||
if (buffer != null)
|
||||
{
|
||||
return new ByteBufferRangeWriter(buffer);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ReadableByteChannel channel = content.getReadableByteChannel();
|
||||
if (channel != null)
|
||||
{
|
||||
if (channel instanceof SeekableByteChannel)
|
||||
{
|
||||
SeekableByteChannel seekableByteChannel = (SeekableByteChannel)channel;
|
||||
return new SeekableByteChannelRangeWriter(seekableByteChannel);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Skipping non-SeekableByteChannel option " + channel + " from content " + content);
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Skipping ReadableByteChannel option", e);
|
||||
}
|
||||
|
||||
return new InputStreamRangeWriter(() -> content.getInputStream());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
||||
/**
|
||||
* Default Range Writer for InputStream
|
||||
*/
|
||||
public class InputStreamRangeWriter implements RangeWriter
|
||||
{
|
||||
|
||||
public static final int NO_PROGRESS_LIMIT = 3;
|
||||
|
||||
public interface InputStreamSupplier
|
||||
{
|
||||
InputStream newInputStream() throws IOException;
|
||||
}
|
||||
|
||||
private final InputStreamSupplier inputStreamSupplier;
|
||||
private boolean closed = false;
|
||||
private InputStream inputStream;
|
||||
private long pos;
|
||||
|
||||
/**
|
||||
* Create InputStremRangeWriter
|
||||
*
|
||||
* @param inputStreamSupplier Supplier of the InputStream. If the stream needs to be regenerated, such as the next
|
||||
* requested range being before the current position, then the current InputStream is closed and a new one obtained
|
||||
* from this supplier.
|
||||
*/
|
||||
public InputStreamRangeWriter(InputStreamSupplier inputStreamSupplier)
|
||||
{
|
||||
this.inputStreamSupplier = inputStreamSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
closed = true;
|
||||
if (inputStream != null)
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream outputStream, long skipTo, long length) throws IOException
|
||||
{
|
||||
if (closed)
|
||||
{
|
||||
throw new IOException("RangeWriter is closed");
|
||||
}
|
||||
|
||||
if (inputStream == null)
|
||||
{
|
||||
inputStream = inputStreamSupplier.newInputStream();
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if (skipTo < pos)
|
||||
{
|
||||
inputStream.close();
|
||||
inputStream = inputStreamSupplier.newInputStream();
|
||||
pos = 0;
|
||||
}
|
||||
if (pos < skipTo)
|
||||
{
|
||||
long skipSoFar = pos;
|
||||
long actualSkipped;
|
||||
int noProgressLoopLimit = NO_PROGRESS_LIMIT;
|
||||
// loop till we reach desired point, break out on lack of progress.
|
||||
while (noProgressLoopLimit > 0 && skipSoFar < skipTo)
|
||||
{
|
||||
actualSkipped = inputStream.skip(skipTo - skipSoFar);
|
||||
if (actualSkipped == 0)
|
||||
{
|
||||
noProgressLoopLimit--;
|
||||
}
|
||||
else if (actualSkipped > 0)
|
||||
{
|
||||
skipSoFar += actualSkipped;
|
||||
noProgressLoopLimit = NO_PROGRESS_LIMIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// negative values means the stream was closed or reached EOF
|
||||
// either way, we've hit a state where we can no longer
|
||||
// fulfill the requested range write.
|
||||
throw new IOException("EOF reached before InputStream skip destination");
|
||||
}
|
||||
}
|
||||
|
||||
if (noProgressLoopLimit <= 0)
|
||||
{
|
||||
throw new IOException("No progress made to reach InputStream skip position " + (skipTo - pos));
|
||||
}
|
||||
|
||||
pos = skipTo;
|
||||
}
|
||||
|
||||
IO.copy(inputStream, outputStream, length);
|
||||
pos += length;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.resource;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Interface for writing sections (ranges) of a single resource (SeekableByteChannel, Resource, etc) to an outputStream.
|
||||
*/
|
||||
public interface RangeWriter extends Closeable
|
||||
{
|
||||
/**
|
||||
* Write the specific range (start, size) to the outputStream.
|
||||
*
|
||||
* @param outputStream the stream to write to
|
||||
* @param skipTo the offset / skip-to / seek-to / position in the resource to start the write from
|
||||
* @param length the size of the section to write
|
||||
*/
|
||||
void writeTo(OutputStream outputStream, long skipTo, long length) throws IOException;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
||||
public class SeekableByteChannelRangeWriter implements RangeWriter
|
||||
{
|
||||
private final SeekableByteChannel channel;
|
||||
private final int bufSize;
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
public SeekableByteChannelRangeWriter(SeekableByteChannel seekableByteChannel)
|
||||
{
|
||||
this.channel = seekableByteChannel;
|
||||
this.bufSize = IO.bufferSize;
|
||||
this.buffer = BufferUtil.allocate(this.bufSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
this.channel.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream outputStream, long skipTo, long length) throws IOException
|
||||
{
|
||||
this.channel.position(skipTo);
|
||||
|
||||
// copy from channel to output stream
|
||||
long readTotal = 0;
|
||||
while (readTotal < length)
|
||||
{
|
||||
BufferUtil.clearToFill(buffer);
|
||||
int size = (int)Math.min(bufSize, length - readTotal);
|
||||
buffer.limit(size);
|
||||
int readLen = channel.read(buffer);
|
||||
BufferUtil.flipToFlush(buffer, 0);
|
||||
BufferUtil.writeTo(buffer, outputStream);
|
||||
readTotal += readLen;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -575,6 +575,56 @@ public class RequestTest
|
|||
assertThat(responses, startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContentLength_ExceedsMaxInteger() throws Exception
|
||||
{
|
||||
final long HUGE_LENGTH = (long) Integer.MAX_VALUE * 10L;
|
||||
|
||||
_handler._checker = (request, response) ->
|
||||
request.getContentLength() == (-1) // per HttpServletRequest javadoc this must return (-1);
|
||||
&& request.getContentLengthLong() == HUGE_LENGTH;
|
||||
|
||||
//Send a request with encoded form content
|
||||
String request="POST / HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: application/octet-stream\n"+
|
||||
"Content-Length: " + HUGE_LENGTH + "\n"+
|
||||
"Connection: close\n"+
|
||||
"\n"+
|
||||
"<insert huge amount of content here>\n";
|
||||
|
||||
System.out.println(request);
|
||||
|
||||
String responses=_connector.getResponse(request);
|
||||
assertThat(responses,startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Servlet spec and API cannot parse Content-Length that exceeds Long.MAX_VALUE
|
||||
*/
|
||||
@Test
|
||||
public void testContentLength_ExceedsMaxLong() throws Exception
|
||||
{
|
||||
String HUGE_LENGTH = Long.MAX_VALUE + "0";
|
||||
|
||||
_handler._checker = (request, response) ->
|
||||
request.getHeader("Content-Length").equals(HUGE_LENGTH)
|
||||
&& request.getContentLength() == (-1) // per HttpServletRequest javadoc this must return (-1);
|
||||
&& request.getContentLengthLong() == (-1); // exact behavior here not specified in Servlet javadoc
|
||||
|
||||
//Send a request with encoded form content
|
||||
String request="POST / HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: application/octet-stream\n"+
|
||||
"Content-Length: " + HUGE_LENGTH + "\n"+
|
||||
"Connection: close\n"+
|
||||
"\n"+
|
||||
"<insert huge amount of content here>\n";
|
||||
|
||||
String responses=_connector.getResponse(request);
|
||||
assertThat(responses, startsWith("HTTP/1.1 400"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdentityParamExtraction() throws Exception
|
||||
{
|
||||
|
|
|
@ -18,32 +18,106 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.ResourceHttpContent;
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(WorkDirExtension.class)
|
||||
public class ResourceCacheTest
|
||||
{
|
||||
public WorkDir workDir;
|
||||
|
||||
public Path createUtilTestResources(Path basePath) throws IOException
|
||||
{
|
||||
// root
|
||||
makeFile(basePath.resolve("resource.txt"), "this is test data");
|
||||
|
||||
// - one/
|
||||
Path one = basePath.resolve("one");
|
||||
FS.ensureDirExists(one);
|
||||
makeFile(one.resolve("1.txt"), "1 - one");
|
||||
|
||||
// - one/dir/
|
||||
Path oneDir = one.resolve("dir");
|
||||
FS.ensureDirExists(oneDir);
|
||||
makeFile(oneDir.resolve("1.txt"), "1 - one");
|
||||
|
||||
// - two/
|
||||
Path two = basePath.resolve("two");
|
||||
FS.ensureDirExists(two);
|
||||
makeFile(two.resolve("1.txt"), "1 - two");
|
||||
makeFile(two.resolve("2.txt"), "2 - two");
|
||||
|
||||
// - two/dir/
|
||||
Path twoDir = two.resolve("dir");
|
||||
FS.ensureDirExists(twoDir);
|
||||
makeFile(twoDir.resolve("2.txt"), "2 - two");
|
||||
|
||||
// - three/
|
||||
Path three = basePath.resolve("three");
|
||||
FS.ensureDirExists(three);
|
||||
makeFile(three.resolve("2.txt"), "2 - three");
|
||||
makeFile(three.resolve("3.txt"), "3 - three");
|
||||
|
||||
// - three/dir/
|
||||
Path threeDir = three.resolve("dir");
|
||||
FS.ensureDirExists(threeDir);
|
||||
makeFile(threeDir.resolve("3.txt"), "3 - three");
|
||||
|
||||
// - four/
|
||||
Path four = basePath.resolve("four");
|
||||
FS.ensureDirExists(four);
|
||||
makeFile(four.resolve("four"), "4 - four (no extension)");
|
||||
makeFile(four.resolve("four.txt"), "4 - four");
|
||||
|
||||
return basePath;
|
||||
}
|
||||
|
||||
private void makeFile(Path file, String contents) throws IOException
|
||||
{
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(file, UTF_8, StandardOpenOption.CREATE_NEW))
|
||||
{
|
||||
writer.write(contents);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMutlipleSources1() throws Exception
|
||||
{
|
||||
ResourceCollection rc = new ResourceCollection(new String[]{
|
||||
"../jetty-util/src/test/resources/org/eclipse/jetty/util/resource/one/",
|
||||
"../jetty-util/src/test/resources/org/eclipse/jetty/util/resource/two/",
|
||||
"../jetty-util/src/test/resources/org/eclipse/jetty/util/resource/three/"
|
||||
});
|
||||
Path basePath = createUtilTestResources(workDir.getEmptyPathDir());
|
||||
|
||||
ResourceCollection rc = new ResourceCollection(
|
||||
new PathResource(basePath.resolve("one")),
|
||||
new PathResource(basePath.resolve("two")),
|
||||
new PathResource(basePath.resolve("three")));
|
||||
|
||||
Resource[] r = rc.getResources();
|
||||
MimeTypes mime = new MimeTypes();
|
||||
|
@ -68,11 +142,12 @@ public class ResourceCacheTest
|
|||
@Test
|
||||
public void testUncacheable() throws Exception
|
||||
{
|
||||
ResourceCollection rc = new ResourceCollection(new String[]{
|
||||
"../jetty-util/src/test/resources/org/eclipse/jetty/util/resource/one/",
|
||||
"../jetty-util/src/test/resources/org/eclipse/jetty/util/resource/two/",
|
||||
"../jetty-util/src/test/resources/org/eclipse/jetty/util/resource/three/"
|
||||
});
|
||||
Path basePath = createUtilTestResources(workDir.getEmptyPathDir());
|
||||
|
||||
ResourceCollection rc = new ResourceCollection(
|
||||
new PathResource(basePath.resolve("one")),
|
||||
new PathResource(basePath.resolve("two")),
|
||||
new PathResource(basePath.resolve("three")));
|
||||
|
||||
Resource[] r = rc.getResources();
|
||||
MimeTypes mime = new MimeTypes();
|
||||
|
@ -110,19 +185,21 @@ public class ResourceCacheTest
|
|||
String[] names = new String[files.length];
|
||||
CachedContentFactory cache;
|
||||
|
||||
Path basePath = workDir.getEmptyPathDir();
|
||||
|
||||
for (int i = 0; i < files.length; i++)
|
||||
{
|
||||
files[i] = File.createTempFile("R-" + i + "-", ".txt");
|
||||
files[i].deleteOnExit();
|
||||
names[i] = files[i].getName();
|
||||
try (OutputStream out = new FileOutputStream(files[i]))
|
||||
Path tmpFile = basePath.resolve("R-" + i + ".txt");
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(tmpFile, UTF_8, StandardOpenOption.CREATE_NEW))
|
||||
{
|
||||
for (int j = 0; j < (i * 10 - 1); j++)
|
||||
{
|
||||
out.write(' ');
|
||||
writer.write(' ');
|
||||
}
|
||||
out.write('\n');
|
||||
writer.write('\n');
|
||||
}
|
||||
files[i] = tmpFile.toFile();
|
||||
names[i] = tmpFile.getFileName().toString();
|
||||
}
|
||||
|
||||
directory = Resource.newResource(files[0].getParentFile().getAbsolutePath());
|
||||
|
@ -139,7 +216,7 @@ public class ResourceCacheTest
|
|||
|
||||
HttpContent content;
|
||||
content = cache.getContent(names[8], 4096);
|
||||
assertTrue(content != null);
|
||||
assertThat(content, is(not(nullValue())));
|
||||
assertEquals(80, content.getContentLengthValue());
|
||||
assertEquals(0, cache.getCachedSize());
|
||||
|
||||
|
@ -272,14 +349,12 @@ public class ResourceCacheTest
|
|||
@Test
|
||||
public void testNoextension() throws Exception
|
||||
{
|
||||
ResourceCollection rc = new ResourceCollection(new String[]{
|
||||
"../jetty-util/src/test/resources/org/eclipse/jetty/util/resource/four/"
|
||||
});
|
||||
Path basePath = createUtilTestResources(workDir.getEmptyPathDir());
|
||||
|
||||
Resource[] resources = rc.getResources();
|
||||
Resource resource = new PathResource(basePath.resolve("four"));
|
||||
MimeTypes mime = new MimeTypes();
|
||||
|
||||
CachedContentFactory cache = new CachedContentFactory(null, resources[0], mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory cache = new CachedContentFactory(null, resource, mime, false, false, CompressedContentFormat.NONE);
|
||||
|
||||
assertEquals(getContent(cache, "four.txt"), "4 - four");
|
||||
assertEquals(getContent(cache, "four"), "4 - four (no extension)");
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.resource;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class RangeWriterTest
|
||||
{
|
||||
public static final String DATA = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZ!@#$%^&*()_+/.,[]";
|
||||
|
||||
public static Path initDataFile() throws IOException
|
||||
{
|
||||
Path testDir = MavenTestingUtils.getTargetTestingPath(RangeWriterTest.class.getSimpleName());
|
||||
FS.ensureEmpty(testDir);
|
||||
|
||||
Path dataFile = testDir.resolve("data.dat");
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(dataFile, UTF_8, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))
|
||||
{
|
||||
writer.write(DATA);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
return dataFile;
|
||||
}
|
||||
|
||||
public static Stream<Arguments> impls() throws IOException
|
||||
{
|
||||
Resource resource = new PathResource(initDataFile());
|
||||
|
||||
return Stream.of(
|
||||
Arguments.of(new ByteBufferRangeWriter(BufferUtil.toBuffer(resource, true))),
|
||||
Arguments.of(new ByteBufferRangeWriter(BufferUtil.toBuffer(resource, false))),
|
||||
Arguments.of(new SeekableByteChannelRangeWriter((SeekableByteChannel)resource.getReadableByteChannel())),
|
||||
Arguments.of(new InputStreamRangeWriter(() -> resource.getInputStream()))
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("impls")
|
||||
public void testSimpleRange(RangeWriter rangeWriter) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream outputStream;
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 10, 50);
|
||||
assertThat("Range: 10 (len=50)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(10, 60)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("impls")
|
||||
public void testSameRange_MultipleTimes(RangeWriter rangeWriter) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream outputStream;
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 10, 50);
|
||||
assertThat("Range(a): 10 (len=50)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(10, 60)));
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 10, 50);
|
||||
assertThat("Range(b): 10 (len=50)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(10, 60)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("impls")
|
||||
public void testMultipleRanges_Ordered(RangeWriter rangeWriter) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream outputStream;
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 10, 20);
|
||||
assertThat("Range(a): 10 (len=20)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(10, 10 + 20)));
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 35, 10);
|
||||
assertThat("Range(b): 35 (len=10)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(35, 35 + 10)));
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 55, 10);
|
||||
assertThat("Range(b): 55 (len=10)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(55, 55 + 10)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("impls")
|
||||
public void testMultipleRanges_Overlapping(RangeWriter rangeWriter) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream outputStream;
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 10, 20);
|
||||
assertThat("Range(a): 10 (len=20)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(10, 10 + 20)));
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 15, 20);
|
||||
assertThat("Range(b): 15 (len=20)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(15, 15 + 20)));
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 20, 20);
|
||||
assertThat("Range(b): 20 (len=20)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(20, 20 + 20)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("impls")
|
||||
public void testMultipleRanges_ReverseOrder(RangeWriter rangeWriter) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream outputStream;
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 55, 10);
|
||||
assertThat("Range(b): 55 (len=10)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(55, 55 + 10)));
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 35, 10);
|
||||
assertThat("Range(b): 35 (len=10)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(35, 35 + 10)));
|
||||
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
rangeWriter.writeTo(outputStream, 10, 20);
|
||||
assertThat("Range(a): 10 (len=20)", new String(outputStream.toByteArray(), UTF_8), is(DATA.substring(10, 10 + 20)));
|
||||
}
|
||||
}
|
|
@ -19,17 +19,19 @@
|
|||
package org.eclipse.jetty.util.resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.DirectoryIteratorException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.LinkOption;
|
||||
|
@ -40,6 +42,7 @@ import java.nio.file.attribute.FileTime;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
@ -58,6 +61,7 @@ public class PathResource extends Resource
|
|||
private final Path path;
|
||||
private final Path alias;
|
||||
private final URI uri;
|
||||
private final boolean belongsToDefaultFileSystem;
|
||||
|
||||
private final Path checkAliasPath()
|
||||
{
|
||||
|
@ -196,6 +200,7 @@ public class PathResource extends Resource
|
|||
assertValidPath(path);
|
||||
this.uri = this.path.toUri();
|
||||
this.alias = checkAliasPath();
|
||||
this.belongsToDefaultFileSystem = this.path.getFileSystem() == FileSystems.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,6 +221,7 @@ public class PathResource extends Resource
|
|||
childPath += "/";
|
||||
this.uri = URIUtil.addPath(parent.uri, childPath);
|
||||
this.alias = checkAliasPath();
|
||||
this.belongsToDefaultFileSystem = this.path.getFileSystem() == FileSystems.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,6 +262,7 @@ public class PathResource extends Resource
|
|||
this.path = path.toAbsolutePath();
|
||||
this.uri = path.toUri();
|
||||
this.alias = checkAliasPath();
|
||||
this.belongsToDefaultFileSystem = this.path.getFileSystem() == FileSystems.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -371,6 +378,8 @@ public class PathResource extends Resource
|
|||
@Override
|
||||
public File getFile() throws IOException
|
||||
{
|
||||
if (!belongsToDefaultFileSystem)
|
||||
return null;
|
||||
return path.toFile();
|
||||
}
|
||||
|
||||
|
@ -385,9 +394,8 @@ public class PathResource extends Resource
|
|||
@Override
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
// Use a FileInputStream rather than Files.newInputStream(path)
|
||||
// since it produces a stream with a fast skip implementation
|
||||
return new FileInputStream(getFile());
|
||||
// TODO: investigate if SPARSE use for default FileSystem usages is worth it
|
||||
return Files.newInputStream(path, StandardOpenOption.READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -399,7 +407,8 @@ public class PathResource extends Resource
|
|||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return FileChannel.open(path, StandardOpenOption.READ);
|
||||
// TODO: investigate if SPARSE use for default FileSystem usages is worth it
|
||||
return Files.newByteChannel(path, StandardOpenOption.READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -552,6 +561,43 @@ public class PathResource extends Resource
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param outputStream the output stream to write to
|
||||
* @param start First byte to write
|
||||
* @param count Bytes to write or -1 for all of them.
|
||||
* @throws IOException if unable to copy the Resource to the output
|
||||
*/
|
||||
@Override
|
||||
public void writeTo(OutputStream outputStream, long start, long count)
|
||||
throws IOException
|
||||
{
|
||||
long length = count;
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
length = Files.size(path) - start;
|
||||
}
|
||||
|
||||
try (SeekableByteChannel channel = Files.newByteChannel(path, StandardOpenOption.READ))
|
||||
{
|
||||
ByteBuffer buffer = BufferUtil.allocate(IO.bufferSize);
|
||||
channel.position(start);
|
||||
|
||||
// copy from channel to output stream
|
||||
long readTotal = 0;
|
||||
while (readTotal < length)
|
||||
{
|
||||
BufferUtil.clearToFill(buffer);
|
||||
int size = (int)Math.min(IO.bufferSize, length - readTotal);
|
||||
buffer.limit(size);
|
||||
int readLen = channel.read(buffer);
|
||||
BufferUtil.flipToFlush(buffer, 0);
|
||||
BufferUtil.writeTo(buffer, outputStream);
|
||||
readTotal += readLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util.resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class PathResourceTest
|
||||
{
|
||||
@Test
|
||||
public void testNonDefaultFileSystem_GetInputStream() throws URISyntaxException, IOException
|
||||
{
|
||||
Path exampleJar = MavenTestingUtils.getTestResourcePathFile("example.jar");
|
||||
|
||||
URI uri = new URI("jar", exampleJar.toUri().toASCIIString(), null);
|
||||
System.err.println("URI = " + uri);
|
||||
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("multi-release", "runtime");
|
||||
|
||||
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env))
|
||||
{
|
||||
Path manifestPath = zipfs.getPath("/META-INF/MANIFEST.MF");
|
||||
assertThat(manifestPath, is(not(nullValue())));
|
||||
|
||||
PathResource resource = new PathResource(manifestPath);
|
||||
|
||||
try (InputStream inputStream = resource.getInputStream())
|
||||
{
|
||||
assertThat("InputStream", inputStream, is(not(nullValue())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonDefaultFileSystem_GetReadableByteChannel() throws URISyntaxException, IOException
|
||||
{
|
||||
Path exampleJar = MavenTestingUtils.getTestResourcePathFile("example.jar");
|
||||
|
||||
URI uri = new URI("jar", exampleJar.toUri().toASCIIString(), null);
|
||||
System.err.println("URI = " + uri);
|
||||
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("multi-release", "runtime");
|
||||
|
||||
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env))
|
||||
{
|
||||
Path manifestPath = zipfs.getPath("/META-INF/MANIFEST.MF");
|
||||
assertThat(manifestPath, is(not(nullValue())));
|
||||
|
||||
PathResource resource = new PathResource(manifestPath);
|
||||
|
||||
try (ReadableByteChannel channel = resource.getReadableByteChannel())
|
||||
{
|
||||
assertThat("ReadableByteChannel", channel, is(not(nullValue())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonDefaultFileSystem_GetFile() throws URISyntaxException, IOException
|
||||
{
|
||||
Path exampleJar = MavenTestingUtils.getTestResourcePathFile("example.jar");
|
||||
|
||||
URI uri = new URI("jar", exampleJar.toUri().toASCIIString(), null);
|
||||
System.err.println("URI = " + uri);
|
||||
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("multi-release", "runtime");
|
||||
|
||||
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env))
|
||||
{
|
||||
Path manifestPath = zipfs.getPath("/META-INF/MANIFEST.MF");
|
||||
assertThat(manifestPath, is(not(nullValue())));
|
||||
|
||||
PathResource resource = new PathResource(manifestPath);
|
||||
File file = resource.getFile();
|
||||
assertThat("File should be null for non-default FileSystem", file, is(nullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultFileSystem_GetFile() throws Exception
|
||||
{
|
||||
Path exampleJar = MavenTestingUtils.getTestResourcePathFile("example.jar");
|
||||
PathResource resource = new PathResource(exampleJar);
|
||||
|
||||
File file = resource.getFile();
|
||||
assertThat("File for default FileSystem", file, is(exampleJar.toFile()));
|
||||
}
|
||||
}
|
|
@ -92,5 +92,16 @@
|
|||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,339 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.webapp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.InputStreamResponseListener;
|
||||
import org.eclipse.jetty.client.util.MultiPartContentProvider;
|
||||
import org.eclipse.jetty.client.util.PathContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class HugeResourceTest
|
||||
{
|
||||
private static final long KB = 1024;
|
||||
private static final long MB = 1024 * KB;
|
||||
private static final long GB = 1024 * MB;
|
||||
public static Path staticBase;
|
||||
public static Path outputDir;
|
||||
public static Path multipartTempDir;
|
||||
|
||||
public Server server;
|
||||
public HttpClient client;
|
||||
|
||||
@BeforeAll
|
||||
public static void prepareStaticFiles() throws IOException
|
||||
{
|
||||
staticBase = MavenTestingUtils.getTargetTestingPath(HugeResourceTest.class.getSimpleName() + "-static-base");
|
||||
FS.ensureDirExists(staticBase);
|
||||
|
||||
makeStaticFile(staticBase.resolve("test-1g.dat"), 1 * GB);
|
||||
makeStaticFile(staticBase.resolve("test-4g.dat"), 4 * GB);
|
||||
makeStaticFile(staticBase.resolve("test-10g.dat"), 10 * GB);
|
||||
|
||||
outputDir = MavenTestingUtils.getTargetTestingPath(HugeResourceTest.class.getSimpleName() + "-outputdir");
|
||||
FS.ensureEmpty(outputDir);
|
||||
|
||||
multipartTempDir = MavenTestingUtils.getTargetTestingPath(HugeResourceTest.class.getSimpleName() + "-multipart-tmp");
|
||||
FS.ensureEmpty(multipartTempDir);
|
||||
}
|
||||
|
||||
public static Stream<Arguments> staticFiles()
|
||||
{
|
||||
ArrayList<Arguments> ret = new ArrayList<>();
|
||||
|
||||
ret.add(Arguments.of("test-1g.dat", 1 * GB));
|
||||
ret.add(Arguments.of("test-4g.dat", 4 * GB));
|
||||
ret.add(Arguments.of("test-10g.dat", 10 * GB));
|
||||
|
||||
return ret.stream();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void cleanupStaticFiles()
|
||||
{
|
||||
FS.ensureDeleted(staticBase);
|
||||
FS.ensureDeleted(outputDir);
|
||||
}
|
||||
|
||||
private static void makeStaticFile(Path staticFile, long size) throws IOException
|
||||
{
|
||||
byte[] buf = new byte[(int)(1 * MB)];
|
||||
Arrays.fill(buf, (byte)'x');
|
||||
ByteBuffer src = ByteBuffer.wrap(buf);
|
||||
|
||||
if (Files.exists(staticFile) && Files.size(staticFile) == size)
|
||||
{
|
||||
// all done, nothing left to do.
|
||||
return;
|
||||
}
|
||||
|
||||
System.err.printf("Creating %,d byte file: %s ...%n", size, staticFile.getFileName());
|
||||
try (SeekableByteChannel channel = Files.newByteChannel(staticFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING))
|
||||
{
|
||||
long remaining = size;
|
||||
while (remaining > 0)
|
||||
{
|
||||
ByteBuffer slice = src.slice();
|
||||
int len = buf.length;
|
||||
if (remaining < Integer.MAX_VALUE)
|
||||
{
|
||||
len = Math.min(buf.length, (int)remaining);
|
||||
slice.limit(len);
|
||||
}
|
||||
|
||||
channel.write(slice);
|
||||
remaining -= len;
|
||||
}
|
||||
}
|
||||
System.err.println(" Done");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
WebAppContext context = new WebAppContext();
|
||||
context.setContextPath("/");
|
||||
context.setBaseResource(new PathResource(staticBase));
|
||||
|
||||
context.addServlet(PostServlet.class, "/post");
|
||||
|
||||
String location = multipartTempDir.toString();
|
||||
long maxFileSize = Long.MAX_VALUE;
|
||||
long maxRequestSize = Long.MAX_VALUE;
|
||||
int fileSizeThreshold = (int)(2 * MB);
|
||||
|
||||
MultipartConfigElement multipartConfig = new MultipartConfigElement(location, maxFileSize, maxRequestSize, fileSizeThreshold);
|
||||
ServletHolder holder = context.addServlet(MultipartServlet.class, "/multipart");
|
||||
holder.getRegistration().setMultipartConfig(multipartConfig);
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.addHandler(context);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
|
||||
server.setHandler(handlers);
|
||||
server.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void startClient() throws Exception
|
||||
{
|
||||
client = new HttpClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("staticFiles")
|
||||
public void testDownload(String filename, long expectedSize) throws Exception
|
||||
{
|
||||
URI destUri = server.getURI().resolve("/" + filename);
|
||||
InputStreamResponseListener responseListener = new InputStreamResponseListener();
|
||||
|
||||
Request request = client.newRequest(destUri)
|
||||
.method(HttpMethod.GET);
|
||||
request.send(responseListener);
|
||||
Response response = responseListener.get(5, TimeUnit.SECONDS);
|
||||
|
||||
assertThat("HTTP Response Code", response.getStatus(), is(200));
|
||||
dumpResponse(response);
|
||||
|
||||
String contentLength = response.getHeaders().get(HttpHeader.CONTENT_LENGTH);
|
||||
long contentLengthLong = Long.parseLong(contentLength);
|
||||
assertThat("Http Response Header: \"Content-Length: " + contentLength + "\"", contentLengthLong, is(expectedSize));
|
||||
|
||||
Path outputFile = outputDir.resolve(filename);
|
||||
try (OutputStream out = Files.newOutputStream(outputFile);
|
||||
InputStream in = responseListener.getInputStream())
|
||||
{
|
||||
IO.copy(in, out);
|
||||
}
|
||||
assertThat("Downloaded Files Size: " + filename, Files.size(outputFile), is(expectedSize));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("staticFiles")
|
||||
public void testUpload(String filename, long expectedSize) throws Exception
|
||||
{
|
||||
Path inputFile = staticBase.resolve(filename);
|
||||
|
||||
PathContentProvider pathContentProvider = new PathContentProvider(inputFile);
|
||||
URI destUri = server.getURI().resolve("/post");
|
||||
Request request = client.newRequest(destUri).method(HttpMethod.POST).content(pathContentProvider);
|
||||
ContentResponse response = request.send();
|
||||
assertThat("HTTP Response Code", response.getStatus(), is(200));
|
||||
dumpResponse(response);
|
||||
|
||||
String responseBody = response.getContentAsString();
|
||||
assertThat("Response", responseBody, containsString("bytes-received=" + expectedSize));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("staticFiles")
|
||||
public void testUpload_Multipart(String filename, long expectedSize) throws Exception
|
||||
{
|
||||
MultiPartContentProvider multipart = new MultiPartContentProvider();
|
||||
Path inputFile = staticBase.resolve(filename);
|
||||
String name = String.format("file-%d", expectedSize);
|
||||
multipart.addFilePart(name, filename, new PathContentProvider(inputFile), null);
|
||||
|
||||
URI destUri = server.getURI().resolve("/multipart");
|
||||
Request request = client.newRequest(destUri).method(HttpMethod.POST).content(multipart);
|
||||
ContentResponse response = request.send();
|
||||
assertThat("HTTP Response Code", response.getStatus(), is(200));
|
||||
dumpResponse(response);
|
||||
|
||||
String responseBody = response.getContentAsString();
|
||||
String expectedResponse = String.format("part[%s].size=%d", name, expectedSize);
|
||||
assertThat("Response", responseBody, containsString(expectedResponse));
|
||||
}
|
||||
|
||||
private void dumpResponse(Response response)
|
||||
{
|
||||
System.out.printf(" %s %d %s%n", response.getVersion(), response.getStatus(), response.getReason());
|
||||
response.getHeaders().forEach((field) -> System.out.printf(" %s%n", field));
|
||||
}
|
||||
|
||||
public static class ByteCountingOutputStream extends OutputStream
|
||||
{
|
||||
private long count = 0;
|
||||
|
||||
public long getCount()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b)
|
||||
{
|
||||
count += b.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len)
|
||||
{
|
||||
count += len;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PostServlet extends HttpServlet
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException
|
||||
{
|
||||
ByteCountingOutputStream byteCounting = new ByteCountingOutputStream();
|
||||
IO.copy(req.getInputStream(), byteCounting);
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("utf-8");
|
||||
resp.getWriter().printf("bytes-received=%d%n", byteCounting.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultipartServlet extends HttpServlet
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("utf-8");
|
||||
PrintWriter out = resp.getWriter();
|
||||
|
||||
req.getParts().forEach((part) ->
|
||||
{
|
||||
out.printf("part[%s].filename=%s%n", part.getName(), part.getSubmittedFileName());
|
||||
out.printf("part[%s].size=%d%n", part.getName(), part.getSize());
|
||||
try (InputStream inputStream = part.getInputStream();
|
||||
ByteCountingOutputStream byteCounting = new ByteCountingOutputStream())
|
||||
{
|
||||
IO.copy(inputStream, byteCounting);
|
||||
out.printf("part[%s].inputStream.length=%d%n", part.getName(), byteCounting.getCount());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(out);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue