diff options
author | Falko Schumann | 2017-09-08 14:57:29 +0000 |
---|---|---|
committer | Raymond Auge | 2018-01-22 15:55:42 +0000 |
commit | 2dc516548adf468508419079662995742a3457aa (patch) | |
tree | aabfd261c0be595119ceefb533ad8db6834fee9c | |
parent | 4e6efcf250b2ce6dbde81d8c5f4c46382bbf086f (diff) | |
download | rt.equinox.bundles-2dc516548adf468508419079662995742a3457aa.tar.gz rt.equinox.bundles-2dc516548adf468508419079662995742a3457aa.tar.xz rt.equinox.bundles-2dc516548adf468508419079662995742a3457aa.zip |
Bug 519955 - ResourceServlet should handle range request
Support Range Requests (RFC7233) for requesting large files such as
videos.
Change-Id: I2965f3b534457a1a6f3cd41c73af5654331fd641
Signed-off-by: Falko Schumann <falko.schumann@bitctrl.de>
10 files changed, 614 insertions, 14 deletions
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/.classpath b/bundles/org.eclipse.equinox.http.servlet.tests/.classpath index a7328b45b..980d19693 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/.classpath +++ b/bundles/org.eclipse.equinox.http.servlet.tests/.classpath @@ -4,5 +4,6 @@ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> <classpathentry kind="src" output="bundles_bin/tb1" path="bundles_src/tb1"/> + <classpathentry kind="src" output="bundles_bin/tb2" path="bundles_src/tb2"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/build.properties b/bundles/org.eclipse.equinox.http.servlet.tests/build.properties index a5548edfa..5a5e20026 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/build.properties +++ b/bundles/org.eclipse.equinox.http.servlet.tests/build.properties @@ -12,13 +12,17 @@ source.. = src/ bin.includes = .,\ META-INF/,\ bundles_bin/tb1.jar,\ + bundles_bin/tb2.jar,\ about.html,\ http.context.test/,\ test.xml jars.compile.order = .,\ - bundles_bin/tb1.jar + bundles_bin/tb1.jar,\ + bundles_bin/tb2.jar source.bundles_bin/tb1.jar = bundles_src/tb1/ +source.bundles_bin/tb2.jar = bundles_src/tb2/ manifest.bundles_bin/tb1.jar = META-INF/MANIFEST.MF +manifest.bundles_bin/tb2.jar = META-INF/MANIFEST.MF src.includes = test.xml,\ about.html diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/META-INF/MANIFEST.MF new file mode 100644 index 000000000..0638e8cf9 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ActivationPolicy: lazy +Bundle-ManifestVersion: 2 +Bundle-Name: org.eclipse.equinox.http.servlet.tests.tb2 +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-SymbolicName: org.eclipse.equinox.http.servlet.tests.tb2 +Bundle-Vendor: IBM +Bundle-Version: 1.0.0.qualifier +Service-Component: OSGI-INF/*_component.xml +Import-Package: javax.servlet, + javax.servlet.http, + org.eclipse.equinox.http.servlet;version="1.1.0", + org.osgi.framework, + org.osgi.service.component, + org.osgi.service.http;version="1.2.1", + org.osgi.service.http.context;version="1.0.0", + org.osgi.service.http.runtime;version="1.0.0", + org.osgi.service.http.runtime.dto;version="1.0.0", + org.osgi.service.http.whiteboard;version="1.0.0" diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/OSGI-INF/testResource1_component.xml b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/OSGI-INF/testResource1_component.xml new file mode 100644 index 000000000..b11365160 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/OSGI-INF/testResource1_component.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true"> + <implementation class="org.eclipse.equinox.http.servlet.tests.tb2.TestResource1"/> + <service> + <provide interface="org.eclipse.equinox.http.servlet.tests.tb2.TestResource1"/> + </service> + <property name="osgi.http.whiteboard.context.select" type="String" value="(osgi.http.whiteboard.context.name=foo)"/> + <property name="osgi.http.whiteboard.resource.pattern" type="String" value="/TestResource1/*"/> + <property name="osgi.http.whiteboard.resource.prefix" type="String" value="/org/eclipse/equinox/http/servlet/tests/tb2"/> +</scr:component> diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/org/eclipse/equinox/http/servlet/tests/tb2/TestResource1.java b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/org/eclipse/equinox/http/servlet/tests/tb2/TestResource1.java new file mode 100644 index 000000000..3c550ea12 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/org/eclipse/equinox/http/servlet/tests/tb2/TestResource1.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2018 Raymond Augé and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Raymond Augé <raymond.auge@liferay.com> - Bug 519955 + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet.tests.tb2; + +/** + * @author Raymond Augé + */ +public class TestResource1 { +} diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/org/eclipse/equinox/http/servlet/tests/tb2/rangerequest.mp4 b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/org/eclipse/equinox/http/servlet/tests/tb2/rangerequest.mp4 new file mode 100644 index 000000000..800356f07 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet.tests/bundles_src/tb2/org/eclipse/equinox/http/servlet/tests/tb2/rangerequest.mp4 @@ -0,0 +1,255 @@ +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java index 1bc3f8037..9aaabd18c 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/testbase/BaseTest.java @@ -195,6 +195,7 @@ public class BaseTest { protected static final String STATUS_OK = "OK"; protected static final String TEST_BUNDLES_BINARY_DIRECTORY = "/bundles_bin/"; protected static final String TEST_BUNDLE_1 = "tb1"; + protected static final String TEST_BUNDLE_2 = "tb2"; protected static final String[] BUNDLES = new String[] { EQUINOX_DS_BUNDLE diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java index 2a422b046..3f5e679f4 100644 --- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java +++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java @@ -75,6 +75,7 @@ import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.eclipse.equinox.http.servlet.RangeAwareServletContextHelper; import org.eclipse.equinox.http.servlet.ExtendedHttpService; import org.eclipse.equinox.http.servlet.context.ContextPathCustomizer; import org.eclipse.equinox.http.servlet.session.HttpSessionInvalidator; @@ -1775,6 +1776,108 @@ public class ServletTest extends BaseTest { } @Test + public void test_ResourceRangeRequest_Complete() throws Exception { + Bundle bundle = installBundle(TEST_BUNDLE_2); + ServletContextHelper customSCH = new ServletContextHelper(bundle) { + @Override + public String getMimeType(String filename) { + if (filename.endsWith(".mp4")) { //$NON-NLS-1$ + return "video/mp4"; //$NON-NLS-1$ + } + return null; + } + }; + Dictionary<String, Object> contextProps = new Hashtable<String, Object>(); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, "foo"); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/foo"); + registrations.add(getBundleContext().registerService(ServletContextHelper.class, customSCH, contextProps)); + Map<String, List<String>> actual; + Map<String, List<String>> requestHeader = new HashMap<>(); + requestHeader.put("Range", Collections.singletonList("bytes=0-")); + try { + bundle.start(); + actual = requestAdvisor.request("foo/TestResource1/rangerequest.mp4", requestHeader); + } finally { + uninstallBundle(bundle); + } + Assert.assertEquals("Response Code", Collections.singletonList("206"), actual.get("responseCode")); + Assert.assertEquals("Content-Length", Collections.singletonList("20655"), actual.get("Content-Length")); + Assert.assertEquals("Accept-Ranges", Collections.singletonList("bytes"), actual.get("Accept-Ranges")); + Assert.assertEquals("Content-Range", Collections.singletonList("bytes 0-20654/20655"), actual.get("Content-Range")); + } + + @Test + public void test_ResourceRangeRequest_WithRange() throws Exception { + Map<String, List<String>> actual; + Bundle bundle = installBundle(TEST_BUNDLE_2); + ServletContextHelper customSCH = new ServletContextHelper(bundle) { + @Override + public String getMimeType(String filename) { + if (filename.endsWith(".mp4")) { //$NON-NLS-1$ + return "video/mp4"; //$NON-NLS-1$ + } + return null; + } + }; + Dictionary<String, Object> contextProps = new Hashtable<String, Object>(); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, "foo"); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/foo"); + registrations.add(getBundleContext().registerService(ServletContextHelper.class, customSCH, contextProps)); + Map<String, List<String>> requestHeader = new HashMap<>(); + requestHeader.put("Range", Collections.singletonList("bytes=1000-9999")); + try { + bundle.start(); + actual = requestAdvisor.request("foo/TestResource1/rangerequest.mp4", requestHeader); + } finally { + uninstallBundle(bundle); + } + Assert.assertEquals("Response Code", Collections.singletonList("206"), actual.get("responseCode")); + Assert.assertEquals("Content-Length", Collections.singletonList("9000"), actual.get("Content-Length")); + Assert.assertEquals("Accept-Ranges", Collections.singletonList("bytes"), actual.get("Accept-Ranges")); + Assert.assertEquals("Content-Range", Collections.singletonList("bytes 1000-9999/20655"), actual.get("Content-Range")); + Assert.assertEquals("Response Body Prefix", "901", actual.get("responseBody").get(0).substring(0, 3)); + Assert.assertEquals("Response Body Suffix", "567", actual.get("responseBody").get(0).substring(8997, 9000)); + } + + @Test + public void test_ResourceRangeRequest_WithRange_customContext() throws Exception { + Map<String, List<String>> actual; + Bundle bundle = installBundle(TEST_BUNDLE_2); + RangeAwareServletContextHelper customSCH = new RangeAwareServletContextHelper(bundle) { + @Override + public String getMimeType(String filename) { + if (filename.endsWith(".mp4")) { //$NON-NLS-1$ + return "video/mp4"; //$NON-NLS-1$ + } + return null; + } + @Override + public boolean rangeableContentType(String contentType, String userAgent) { + return userAgent.contains("Foo") && contentType.startsWith("video/"); + } + }; + Dictionary<String, Object> contextProps = new Hashtable<String, Object>(); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, "foo"); + contextProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/foo"); + registrations.add(getBundleContext().registerService(ServletContextHelper.class, customSCH, contextProps)); + + Map<String, List<String>> requestHeader = new HashMap<>(); + requestHeader.put("User-Agent", Collections.singletonList("Foo")); + try { + bundle.start(); + actual = requestAdvisor.request("foo/TestResource1/rangerequest.mp4", requestHeader); + } finally { + uninstallBundle(bundle); + } + Assert.assertEquals("Response Code", Collections.singletonList("206"), actual.get("responseCode")); + Assert.assertEquals("Content-Length", Collections.singletonList("20655"), actual.get("Content-Length")); + Assert.assertEquals("Accept-Ranges", Collections.singletonList("bytes"), actual.get("Accept-Ranges")); + Assert.assertEquals("Content-Range", Collections.singletonList("bytes 0-20654/20655"), actual.get("Content-Range")); + Assert.assertEquals("Response Body Prefix", "123", actual.get("responseBody").get(0).substring(0, 3)); + Assert.assertEquals("Response Body Suffix", "789", actual.get("responseBody").get(0).substring(8997, 9000)); + } + + @Test public void test_Runtime() throws Exception { Bundle bundle = installBundle(TEST_BUNDLE_1); try { diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/RangeAwareServletContextHelper.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/RangeAwareServletContextHelper.java new file mode 100644 index 000000000..7241b8418 --- /dev/null +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/RangeAwareServletContextHelper.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) Jan 20, 2018 Liferay, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Liferay, Inc. - initial API and implementation and/or initial + * documentation + ******************************************************************************/ + +package org.eclipse.equinox.http.servlet; + +import org.osgi.framework.Bundle; +import org.osgi.service.http.context.ServletContextHelper; + +/** + * A custom servlet context helper type providing support for predicting the need + * for ranged content responses based on the content type and the user agent. + * + * @since 1.4 + */ +public abstract class RangeAwareServletContextHelper extends ServletContextHelper { + + public RangeAwareServletContextHelper() { + super(); + } + + public RangeAwareServletContextHelper(Bundle bundle) { + super(bundle); + } + + /** + * Return true if the content type should result in a ranged content response + * based on the user agent. The user agent value is obtained from the + * {@code User-Agent} request header. + * <p> + * This mechanism is only applicable if the browser didn't make a range request + * for a known ranged content type. + * + * @param contentType the content type of the request + * @param userAgent the value obtained from the "User-Agent" header + */ + public boolean rangeableContentType(String contentType, String userAgent) { + return false; + } + +} diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java index e07d4aa10..2385f4f12 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ResourceServlet.java @@ -9,6 +9,7 @@ * Cognos Incorporated - initial API and implementation * IBM Corporation - bug fixes and enhancements * Raymond Augé <raymond.auge@liferay.com> - Bug 436698 + * Falko Schumann <falko.schumann@bitctrl.de> - Bug 519955 *******************************************************************************/ package org.eclipse.equinox.http.servlet.internal.servlet; @@ -16,7 +17,10 @@ import java.io.*; import java.net.URL; import java.net.URLConnection; import java.security.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.http.*; +import org.eclipse.equinox.http.servlet.RangeAwareServletContextHelper; import org.eclipse.equinox.http.servlet.internal.util.Const; import org.osgi.service.http.context.ServletContextHelper; @@ -26,16 +30,20 @@ public class ResourceServlet extends HttpServlet { private static final String IF_MODIFIED_SINCE = "If-Modified-Since"; //$NON-NLS-1$ private static final String IF_NONE_MATCH = "If-None-Match"; //$NON-NLS-1$ private static final String ETAG = "ETag"; //$NON-NLS-1$ + private static final String RANGE = "Range"; //$NON-NLS-1$ + private static final String ACCEPT_RANGES = "Accept-Ranges"; //$NON-NLS-1$ + private static final String RANGE_UNIT_BYTES = "bytes"; //$NON-NLS-1$ + private static final String CONTENT_RANGE = "Content-Range"; //$NON-NLS-1$ - private String internalName; - private ServletContextHelper servletContextHelper; - private AccessControlContext acc; + private final String internalName; + final ServletContextHelper servletContextHelper; + private final AccessControlContext acc; public ResourceServlet(String internalName, ServletContextHelper servletContextHelper, AccessControlContext acc) { - this.internalName = internalName; if (internalName.equals(Const.SLASH)) { - this.internalName = Const.BLANK; + internalName = Const.BLANK; } + this.internalName = internalName; this.servletContextHelper = servletContextHelper; this.acc = acc; } @@ -86,13 +94,28 @@ public class ResourceServlet extends HttpServlet { return Boolean.TRUE; } + String rangeHeader = req.getHeader(RANGE); + Range range = null; + if (rangeHeader != null) { + range = Range.createFromRangeHeader(rangeHeader); + range.completeLength = contentLength; + range.updateBytePos(); + + if (!range.isValid()) { + resp.setHeader(ACCEPT_RANGES, RANGE_UNIT_BYTES); + resp.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return Boolean.TRUE; + } + } + // return the full contents regularly if (contentLength != -1) resp.setContentLength(contentLength); - String contentType = servletContextHelper.getMimeType(resourcePath); + String filename = new File(resourcePath).getName(); + String contentType = servletContextHelper.getMimeType(filename); if (contentType == null) - contentType = getServletConfig().getServletContext().getMimeType(resourcePath); + contentType = getServletConfig().getServletContext().getMimeType(filename); if (contentType != null) resp.setContentType(contentType); @@ -103,6 +126,23 @@ public class ResourceServlet extends HttpServlet { if (etag != null) resp.setHeader(ETAG, etag); + if (range == null && + (servletContextHelper instanceof RangeAwareServletContextHelper) && + ((RangeAwareServletContextHelper)servletContextHelper).rangeableContentType(contentType, req.getHeader("User-Agent"))) { //$NON-NLS-1$ + + range = new Range(); + range.firstBytePos = 0; + range.completeLength = contentLength; + range.updateBytePos(); + } + + if (range != null) { + resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); + resp.setHeader(ACCEPT_RANGES, RANGE_UNIT_BYTES); + resp.setContentLength(range.contentLength()); + resp.setHeader(CONTENT_RANGE, RANGE_UNIT_BYTES + " " + range.firstBytePos + "-" + range.lastBytePos + "/" + range.completeLength); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if (contentLength != 0) { // open the input stream InputStream is = null; @@ -111,12 +151,12 @@ public class ResourceServlet extends HttpServlet { // write the resource try { OutputStream os = resp.getOutputStream(); - int writtenContentLength = writeResourceToOutputStream(is, os); + int writtenContentLength = writeResourceToOutputStream(is, os, range); if (contentLength == -1 || contentLength != writtenContentLength) resp.setContentLength(writtenContentLength); } catch (IllegalStateException e) { // can occur if the response output is already open as a Writer Writer writer = resp.getWriter(); - writeResourceToWriter(is, writer); + writeResourceToWriter(is, writer, range); // Since ContentLength is a measure of the number of bytes contained in the body // of a message when we use a Writer we lose control of the exact byte count and // defer the problem to the Servlet Engine's Writer implementation. @@ -158,11 +198,22 @@ public class ResourceServlet extends HttpServlet { } } - int writeResourceToOutputStream(InputStream is, OutputStream os) throws IOException { + int writeResourceToOutputStream(InputStream is, OutputStream os, Range range) throws IOException { + if (range != null) { + if (range.firstBytePos != Range.NOT_SET) { + is.skip(range.firstBytePos); + } else { + is.skip(range.completeLength - range.lastBytePos); + } + } + byte[] buffer = new byte[8192]; int bytesRead = is.read(buffer); int writtenContentLength = 0; - while (bytesRead != -1) { + while (bytesRead != -1 && (range == null || range.lastBytePos == Range.NOT_SET || writtenContentLength < range.lastBytePos)) { + if (range != null && range.lastBytePos != Range.NOT_SET && (bytesRead + writtenContentLength) > range.lastBytePos) { + bytesRead = range.contentLength() - writtenContentLength; + } os.write(buffer, 0, bytesRead); writtenContentLength += bytesRead; bytesRead = is.read(buffer); @@ -170,13 +221,26 @@ public class ResourceServlet extends HttpServlet { return writtenContentLength; } - void writeResourceToWriter(InputStream is, Writer writer) throws IOException { + void writeResourceToWriter(InputStream is, Writer writer, Range range) throws IOException { + if (range != null) { + if (range.firstBytePos != Range.NOT_SET) { + is.skip(range.firstBytePos); + } else { + is.skip(range.completeLength - range.lastBytePos); + } + } + Reader reader = new InputStreamReader(is); try { char[] buffer = new char[8192]; int charsRead = reader.read(buffer); - while (charsRead != -1) { + int writtenContentLength = 0; + while (charsRead != -1 && (range == null || range.lastBytePos == Range.NOT_SET || writtenContentLength < range.lastBytePos)) { + if (range != null && range.lastBytePos != Range.NOT_SET && (charsRead + writtenContentLength) > range.lastBytePos) { + charsRead = range.contentLength() - writtenContentLength; + } writer.write(buffer, 0, charsRead); + writtenContentLength += charsRead; charsRead = reader.read(buffer); } } finally { @@ -185,4 +249,80 @@ public class ResourceServlet extends HttpServlet { } } } + + static class Range { + + private static final Pattern RANGE_PATTERN = Pattern.compile("^(.+)=(\\d+)?-(\\d+)?$"); //$NON-NLS-1$ + + static final int NOT_SET = -1; + + String rangeUnit = RANGE_UNIT_BYTES; + int firstBytePos = NOT_SET; + int lastBytePos = NOT_SET; + int completeLength = NOT_SET; + + static Range createFromRangeHeader(String header) { + Range range = new Range(); + + Matcher matcher = RANGE_PATTERN.matcher(header); + if (!matcher.matches()) { + // use default values + return range; + } + + range.rangeUnit = matcher.group(1); + if (matcher.group(2) != null) { + try { + range.firstBytePos = Integer.parseInt(matcher.group(2)); + } catch (NumberFormatException ignored) { + // use default value + } + } + if (matcher.group(3) != null) { + try { + range.lastBytePos = Integer.parseInt(matcher.group(3)); + } catch (NumberFormatException ignored) { + // use default value + } + } + return range; + } + + void updateBytePos() { + if (lastBytePos == -1 || lastBytePos >= completeLength) { + lastBytePos = completeLength - 1; + } + if (firstBytePos == -1) { + firstBytePos = completeLength - lastBytePos - 1; + lastBytePos = completeLength - 1; + } + } + + boolean isValid() { + // we accept bytes unit only + if (!RANGE_UNIT_BYTES.equals(rangeUnit)) { + return false; + } + + if (firstBytePos == NOT_SET && lastBytePos == NOT_SET) { + return false; + } + + if (firstBytePos >= completeLength) { + return false; + } + + if (lastBytePos >= completeLength) { + return false; + } + + return true; + } + + int contentLength() { + return lastBytePos - firstBytePos + 1; + } + + } + } |