Merge remote-tracking branch 'origin/jetty-9.3.x' into jetty-9.4.x

This commit is contained in:
Greg Wilkins 2016-09-02 14:57:44 +10:00
commit 25574d2843
14 changed files with 419 additions and 362 deletions

View File

@ -23,7 +23,6 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
/** /**
* Simple Jetty FileServer. * Simple Jetty FileServer.
@ -41,6 +40,7 @@ public class FileServer
// Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is // Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is
// a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples. // a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples.
ResourceHandler resource_handler = new ResourceHandler(); ResourceHandler resource_handler = new ResourceHandler();
// Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of. // Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of.
// In this example it is the current directory but it can be configured to anything that the jvm has access to. // In this example it is the current directory but it can be configured to anything that the jvm has access to.
resource_handler.setDirectoriesListed(true); resource_handler.setDirectoriesListed(true);
@ -48,11 +48,8 @@ public class FileServer
resource_handler.setResourceBase("."); resource_handler.setResourceBase(".");
// Add the ResourceHandler to the server. // Add the ResourceHandler to the server.
GzipHandler gzip = new GzipHandler();
server.setHandler(gzip);
HandlerList handlers = new HandlerList(); HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() }); handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
gzip.setHandler(handlers);
// Start things up! By using the server.join() the server thread will join with the current thread. // Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details. // See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.

View File

@ -30,15 +30,12 @@ For a more in-depth look at the syntax, see xref:jetty-xml-syntax[].
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Configure class="org.eclipse.jetty.webapp.WebAppContext">
.. ..
</Configure> </Configure>
---- ----
____ ____

View File

@ -80,41 +80,27 @@ bar.getParent().setName("demo2");
===== Understanding DTD and Parsing ===== Understanding DTD and Parsing
The document type descriptor The document type descriptor
(link:{GITBROWSEURL}/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd?h=release-9[configure.dtd]) (link:{GITBROWSEURL}/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd?h=release-9[configure.dtd]) describes all valid elements in a Jetty XML configuration file using the Jetty IoC format.
describes all valid elements in a Jetty XML configuration file using the The first two lines of an XML must reference the DTD to be used to validate the XML like:
Jetty IoC format. The first two lines of an XML must reference the DTD
to be used to validate the XML like:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
... ...
---- ----
Typcically a good XML editor will fetch the DTD from the URL and use it Typcically a good XML editor will fetch the DTD from the URL and use it to give syntax highlighting and validation while a configuration file is being edited.
to give syntax highlighting and validation while a configuration file is Some editors also allows DTD files to be locally cached.
being edited. Some editors also allows DTD files to be locally cached. The URL may point to configure.dtd if you want the latest current version, or to a specific version like configure_9_0.dtd if you want a particular validation feature set.
The URL may point to configure.dtd if you want the latest current
version, or to a specific version like configure_9_0.dtd if you want a
particular validation feature set.
Files that conform to the configure.dtd format are processed in Jetty by Files that conform to the configure.dtd format are processed in Jetty by the `XmlConfiguration` class which may also validate the XML (using a version of the DTD from the classes jar file), but is by default run in a forgiving mode that tries to work around validation failures.
the `XmlConfiguration` class which may also validate the XML (using a
version of the DTD from the classes jar file), but is by default run in
a forgiving mode that tries to work around validation failures.
===== Jetty XML Configuration Scope ===== Jetty XML Configuration Scope
The configuration of object instances with Jetty IoC XML is done on a The configuration of object instances with Jetty IoC XML is done on a scoped basis, so that for any given XML element there is a corresponding Object in scope and the nested XML elements apply to that.
scoped basis, so that for any given XML element there is a corresponding The outer most scope is given by a Configure element and elements like Call, New and Get establish new scopes.
Object in scope and the nested XML elements apply to that. The outer The following example uses the name fields to explain the scope.
most scope is given by a Configure element and elements like Call, New
and Get establish new scopes. The following example uses the name fields
to explain the scope
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -134,50 +120,36 @@ to explain the scope
<Call name="methodOnObjectReturnedByMethodOnFooWithNoArgs"/> <Call name="methodOnObjectReturnedByMethodOnFooWithNoArgs"/>
</Call> </Call>
</Configure> </Configure>
---- ----
===== Coercing Arguments to a Type ===== Coercing Arguments to a Type
When trying to match XML elements to java elements, Jetty When trying to match XML elements to java elements, Jetty `XmlConfiguration` may need to coerces values to match method arguments.
XmlConfiguration may need to coerces values to match method arguments. By default it does so on a best effort basis, but you can also specify explicit types with the `type` attribute.
By default it does so on a best effort basis, but you can also specify Supported values for type are: `String`, `Character`, `Short`, `Byte`, `Integer`, `Long`, `Boolean`, `Float`, `Double`, `char`, `short`, `byte`, `int`, `long`, `boolean`, `float`, `double`, `URL`, `InetAddress`, `InetAddrPort`, and `void`.
explicit types with the `type` attribute. Supported values for type are:
String, Character, Short, Byte, Integer, Long, Boolean, Float, Double,
char, short, byte, int, long, boolean, float, double, URL, InetAddress,
InetAddrPort, void
===== Referring to a Class ===== Referring to a Class
If you do not specify the classname, Jetty assumes you are calling the If you do not specify the classname, Jetty assumes you are calling the method on the object that is current in scope (eg the object of the surrounding `Configure`, `New` or `Get` clause).
method on the object that is current in scope (eg the object of the If the class attribute is specified to a fully-qualified class name, then it is either used to create a new instance (`Configure` and `New` elements) or is used to access a static (`Call`, `Set` or `Get` elements).
surrounding Configure, New or Get clause). If the class attribute is
specified to a fully-qualified class name, then it is either used to
create a new instance (Configure and New elements) or is used to access
a static (Call, Set or Get elements).
===== Referring to an Object ===== Referring to an Object
You can use the id attribute to store a reference to the current object You can use the id attribute to store a reference to the current object when first creating or referring to this object.
when first creating or referring to this object. You can then use the You can then use the link:#jetty-xml-ref[Ref element] to reference the object later.
link:#jetty-xml-ref[Ref element] to reference the object later. The id The ID must be unique for each object you create.
must be unique for each object you create.
===== Attribute vs Element Style ===== Attribute vs Element Style
For XML elements that contain only other XML Elements, there is a choice For XML elements that contain only other XML Elements, there is a choice of using attributes or elements style.
of using attributes or elements style. The following is an example of The following is an example of attribute style:
attribute style:
.... ....
<Call id="result" class="org.example.SomeClass" name="someMethod" arg="value0,value1"/> <Call id="result" class="org.example.SomeClass" name="someMethod" arg="value0,value1"/>
.... ....
Attribute style has the benefit of brevity, but is limited by: values Attribute style has the benefit of brevity, but is limited by: values can only be Strings; multivalued items can not contain ','; values may not be subject to property expansion or other elements that return values.
can only be Strings; multivalued items can not contain ','; values may Thus, the more verbose element style is available and the following is semantically equivalent to the attribute style above:
not be subject to property expansion or other elements that return
values. Thus the more verbose element style is available and the
following is semantically equivalent to the attribute style above:
.... ....
<Call> <Call>
@ -189,11 +161,8 @@ following is semantically equivalent to the attribute style above:
</Call> </Call>
.... ....
Note that multivalued elements like Arg, must be repeated and may not be Note that multivalued elements like `Arg` must be repeated and may not be comma-separated like they are when provided as attributes.
comma separated like they are when provided as attributes. It is It is possible to use a mix of styles and the following example shows a moretypical example that uses property expansion as the reason for element style:
possible to use a mix of styles and the following example shows a more
typical example that uses property expansion as the reason for element
style:
.... ....
<Call id="result" name="someMethod"> <Call id="result" name="someMethod">
@ -205,16 +174,14 @@ style:
</Call> </Call>
.... ....
Attributes may not be expressed as elements when their parent element is Attributes may not be expressed as elements when their parent element is one that contains data.
one that contains data. Thus Arg, Item, Set, Put and Get elements may Thus `Arg`, `Item`, `Set`, `Put` and `Get` elements may not have their attributes expressed as elements.
not have their attributes expressed as elements.
[[jetty-xml-configure]] [[jetty-xml-configure]]
==== <Configure> ==== <Configure>
This is the root element that specifies the class of object that is to This is the root element that specifies the class of object that is to be configured.
be configured. It is usually either the Server, in `jetty.xml`, or a It is usually either the Server, in `jetty.xml`, or a `WebAppContext` in `jetty-web.xml`.
WebAppContext in `jetty-web.xml`.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -226,8 +193,8 @@ You can use this to break up configuration of an object (such as the
Server) across multiple files. Server) across multiple files.
|class |no |The fully qualified classname of the object to be |class |no |The fully qualified classname of the object to be
configured. Could be org.eclipse.jetty.server.Server, configured. Could be `org.eclipse.jetty.server.Server`,
org.eclipse.jetty.webapp.WebAppContext, a handler, etc. `org.eclipse.jetty.webapp.WebAppContext`, a handler, etc.
|======================================================================= |=======================================================================
===== Can Contain ===== Can Contain
@ -257,10 +224,9 @@ org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server();
server.setPort(8080); server.setPort(8080);
---- ----
====== Using id to break up configuration of one object across multiple ====== Using id to break up configuration of one object across multiple files
files
(etc/jetty.xml) In `etc/jetty.xml`:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -269,7 +235,7 @@ files
</Configure> </Configure>
---- ----
(etc/jetty-logging.xml) In `etc/jetty-logging.xml`:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -287,13 +253,11 @@ java -jar start.jar etc/jetty.xml jetty-logging.xml
[[jetty-xml-set]] [[jetty-xml-set]]
==== <Set> ==== <Set>
A Set element maps to a call to a setter method or field on the current A Set element maps to a call to a setter method or field on the current object.
object. It can contain text and/or elements such as Call, New, It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc., as values.
SystemProperty, etc., as values. The name and optional type attributes The name and optional type attributes are used to select the setter method.
are used to select the setter method. If you do not specify a value If you do not specify a value type, white space is trimmed out of the value.
type, white space is trimmed out of the value. If it contains multiple If it contains multiple elements as values, they are added as strings before being converted to any specified type.
elements as values, they are added as strings before being converted to
any specified type.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -370,15 +334,14 @@ server.setThreadPool(threadPool);
---- ----
<Configure id="server" class="org.eclipse.jetty.server.Server"> <Configure id="server" class="org.eclipse.jetty.server.Server">
<Set class="org.eclipse.jetty.util.log.Log" name="logToParent">loggerName</Set> <Set class="org.eclipse.jetty.util.log.Log" name="logToParent">loggerName</Set>
</Configure"> </Configure>
---- ----
[[jetty-xml-get]] [[jetty-xml-get]]
==== <Get> ==== <Get>
A Get element maps to a call to a getter method or field on the current A Get element maps to a call to a getter method or field on the current object.
object. It can contain nested elements such as Set, Put, Call, etc.; It can contain nested elements such as `Set`, `Put`, `Call`, etc.; these act on the object returned by the `Get` call.
these act on the object returned by the Get call.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -406,8 +369,8 @@ link:#jetty-xml-property[Property element]
====== Basic Example ====== Basic Example
This simple example doesn't do much on its own. You would normally use This simple example doesn't do much on its own.
this in conjunction with a <Ref id="Logger" />. You would normally use this in conjunction with a `<Ref id="Logger" />`.
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -432,12 +395,10 @@ this in conjunction with a <Ref id="Logger" />.
[[jetty-xml-put]] [[jetty-xml-put]]
==== <Put> ==== <Put>
A Put element maps to a call to a put method on the current object, A Put element maps to a call to a put method on the current object, which must implement the Map interface.
which must implement the Map interface. It can contain text and/or It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc. as values.
elements such as Call, New, SystemProperty, etc. as values. If you do If you do not specify a no value type, white space is trimmed out of the value.
not specify a no value type, white space is trimmed out of the value. If If it contains multiple elements as values, they are added as strings before being converted to any specified type.
it contains multiple elements as values, they are added as strings
before being converted to any specified type.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -450,7 +411,7 @@ Arg for how to define null and empty string values.
===== Can Contain ===== Can Contain
value text , link:#jetty-xml-get[Get element], link:#jetty-xml-call[Call value text, link:#jetty-xml-get[Get element], link:#jetty-xml-call[Call
element], link:#jetty-xml-new[New element], link:#jetty-xml-ref[Ref element], link:#jetty-xml-new[New element], link:#jetty-xml-ref[Ref
element], link:#jetty-xml-array[Array element], link:#jetty-xml-map[Map element], link:#jetty-xml-array[Array element], link:#jetty-xml-map[Map
element], link:#jetty-xml-system-property[System Property element], element], link:#jetty-xml-system-property[System Property element],
@ -468,11 +429,9 @@ link:#jetty-xml-property[Property element]
[[jetty-xml-call]] [[jetty-xml-call]]
==== <Call> ==== <Call>
A Call element maps to an arbitrary call to a method on the current A `Call` element maps to an arbitrary call to a method on the current object.
object. It can contain a sequence of Arg elements followed by a sequence It can contain a sequence of Arg elements followed by a sequence of configuration elements, such as Set, Put, Call.
of configuration elements, such as Set, Put, Call. The <Arg>s are passed The <Arg>s are passed as arguments to the method; the sequence of configuration elements act on the object returned by the original call.
as arguments to the method; the sequence of configuration elements act
on the object returned by the original call.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -527,7 +486,7 @@ o2.setTest("1, 2, 3");
</Call> </Call>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -548,7 +507,7 @@ com.acme.Foo.setString("somestring");
</Configure> </Configure>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -562,13 +521,11 @@ com.acme.Environment.setPort( server.getPort() );
An Arg element can be an argument of either a method or a constructor. An Arg element can be an argument of either a method or a constructor.
Use it within xref:jetty-syntax-call[] and xref:jetty-syntax-new[]. Use it within xref:jetty-syntax-call[] and xref:jetty-syntax-new[].
It can contain text and/or elements, such as Call, New, SystemProperty, It can contain text and/or elements, such as `Call`, `New`, `SystemProperty`, etc., as values.
etc., as values. The optional type attribute can force the type of the The optional type attribute can force the type of the value.
value. If you don't specify a type, white space is trimmed out of the If you don't specify a type, white space is trimmed out of the value.
value. If it contains multiple elements as values, they are added as If it contains multiple elements as values, they are added as strings before being converted to any specified type.
strings before being converted to any specified type. Simple String Simple `String` arguments can also be specified as a string separated arg attribute on the parent element.
arguments can also be specified as a string separated arg attribute on
the parent element.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -597,7 +554,7 @@ link:#jetty-xml-property[Property element]
<Arg>1</Arg> <!-- int, long, short, float, double --> <Arg>1</Arg> <!-- int, long, short, float, double -->
<Arg><Ref refid="foo" /></Arg> <!-- any object; reference a previously created object with id "foo", and pass it as a parameter --> <Arg><Ref refid="foo" /></Arg> <!-- any object; reference a previously created object with id "foo", and pass it as a parameter -->
<Arg></Arg> <!-- null value --> <Arg></Arg> <!-- null value -->
<Arg type="String"></Arg> <!-- empty string "" -> <Arg type="String"></Arg> <!-- empty string "" -->
---- ----
====== Coercing Type ====== Coercing Type
@ -611,8 +568,7 @@ This explicitly coerces the type to a boolean:
====== As a Parameter ====== As a Parameter
Here are a couple of examples of link:#jetty-xml-arg[Arg element] being Here are a couple of examples of link:#jetty-xml-arg[Arg element] being used as a parameter to methods and to constructors:
used as a parameter to methods and to constructors:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -653,13 +609,11 @@ new com.acme.Baz(com.acme.MyStaticObjectFactory.createObject(2));
[[jetty-xml-new]] [[jetty-xml-new]]
==== <New> ==== <New>
Instantiates an object. Equivalent to new in Java, and allows the Instantiates an object.
creation of a new object. A New element can contain a sequence of Equivalent to `new` in Java, and allows the creation of a new object.
link:#jetty-xml-arg[Arg element]'s, followed by a sequence of A `New` element can contain a sequence of link:#jetty-xml-arg[`Arg` element]'s, followed by a sequence of configuration elements (`Set`, `Put`, etc).
configuration elements (Set, Put, etc). link:#jetty-xml-arg[Arg link:#jetty-xml-arg[`Arg` element]'s are used to select a constructor for the object to be created.
element]'s are used to select a constructor for the object to be The sequence of configuration elements then acts on the newly-created object.
created. The sequence of configuration elements then acts on the
newly-created object.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -694,7 +648,7 @@ element], link:#jetty-xml-property[Property element]
</New> </New>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -708,7 +662,7 @@ com.acme.Foo foo = new com.acme.Foo("bar");
<New class="com.acme.Foo" /> <New class="com.acme.Foo" />
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -726,7 +680,7 @@ com.acme.Foo foo = new com.acme.Foo();
</New> </New>
---- ----
which is equivalent to: Which is equivalent to:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
@ -737,17 +691,14 @@ foo.setTest("1, 2, 3");
[[jetty-xml-ref]] [[jetty-xml-ref]]
==== <Ref> ==== <Ref>
A Ref element allows a previously created object to be referenced by a A `Ref` element allows a previously created object to be referenced by a unique id.
unique id. It can contain a sequence of elements, such as Set or Put It can contain a sequence of elements, such as `Set` or `Put` which then act on the referenced object.
which then act on the referenced object. You can also use a Ref element You can also use a `Ref` element as a value for other elements such as `Set` and `Arg`.
as a value for other elements such as Set and Arg.
The Ref element provides convenience and eases readability. You can The `Ref` element provides convenience and eases readability.
usually achieve the effect of the Ref by nesting elements (method You can usually achieve the effect of the `Ref` by nesting elements (method calls), but this can get complicated very easily.
calls), but this can get complicated very easily. The Ref element makes The Ref element makes it possible to refer to the same object if you're using it multiple times, or passing it into multiple methods.
it possible to refer to the same object if you're using it multiple It also makes it possible to split up configuration across multiple files.
times, or passing it into multiple methods. It also makes it possible to
split up configuration across multiple files.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -768,8 +719,7 @@ link:#jetty-xml-property[Property element]
====== Basic example ====== Basic example
Use the referenced object as an argument to a method call or Use the referenced object as an argument to a method call or constructor:
constructor:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -805,8 +755,8 @@ foo.setTest("1, 2, 3");
====== Ref vs. Nested Elements ====== Ref vs. Nested Elements
Here is an example of the difference in syntax between using the Ref Here is an example of the difference in syntax between using the `Ref` element, and nesting method calls.
element, and nesting method calls. They are exactly equivalent: They are exactly equivalent:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -825,8 +775,7 @@ element, and nesting method calls. They are exactly equivalent:
</Configure> </Configure>
---- ----
Here is a more practical example, taken from the handler configuration Here is a more practical example, taken from the handler configuration section in `etc/jetty.xml`:
section in ` etc/jetty.xml`:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -868,7 +817,7 @@ section in ` etc/jetty.xml`:
[[jetty-xml-array]] [[jetty-xml-array]]
==== <Array> ==== <Array>
An Array element allows the creation of a new array. An `Array` element allows the creation of a new array.
[cols=",,",options="header",] [cols=",,",options="header",]
|================================================================== |==================================================================
@ -901,7 +850,7 @@ String[] a = new String[] { "value0", new String("value1") };
[[jetty-xml-item]] [[jetty-xml-item]]
==== <Item> ==== <Item>
An Item element defines an entry for Array and Map elements. An `Item` element defines an entry for Array and Map elements.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -921,8 +870,7 @@ link:#jetty-xml-property[Property element]
[[jetty-xml-map]] [[jetty-xml-map]]
==== <Map> ==== <Map>
A Map element allows the creation of a new HashMap and to populate it A `Map` element allows the creation of a new HashMap and to populate it with `(key, value)` pairs.
with (key, value) pairs.
[cols=",,",options="header",] [cols=",,",options="header",]
|================================================================ |================================================================
@ -957,8 +905,7 @@ m.put("keyName", new String("value1"));
[[jetty-xml-entry]] [[jetty-xml-entry]]
==== <Entry> ==== <Entry>
An Entry element contains a key-value link:#jetty-xml-item[Item element] An `Entry` element contains a key-value link:#jetty-xml-item[Item element] pair for a `Map`.
pair for a Map.
===== Can Contain ===== Can Contain
@ -967,8 +914,8 @@ link:#jetty-xml-item[Item element]
[[jetty-xml-system-property]] [[jetty-xml-system-property]]
==== <SystemProperty> ==== <SystemProperty>
A SystemProperty element gets the value of a JVM system property. It can A `SystemProperty` element gets the value of a JVM system property.
be used within elements that accept values, such as Set, Put, Arg. It can be used within elements that accept values, such as `Set`, `Put`, `Arg`.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -983,7 +930,7 @@ later.
===== Can Contain ===== Can Contain
Only attributes as Elements (Id, Name, Default). Only attributes as Elements (`Id`, `Name`, `Default`).
===== Example ===== Example
@ -999,15 +946,14 @@ That is equivalent to:
System.getProperty("jetty.http.port", "8080"); System.getProperty("jetty.http.port", "8080");
---- ----
Both try to retrieve the value of jetty.http.port. If jetty.http.port is Both try to retrieve the value of `jetty.http.port`.
not set, then 8080 is used. If `jetty.http.port` is not set, then 8080 is used.
[[jetty-xml-property]] [[jetty-xml-property]]
==== <Property> ==== <Property>
A Property element allows arbitrary properties to be retrieved by name. A `Property` element allows arbitrary properties to be retrieved by name.
It can contain a sequence of elements, such as Set, Put, Call that act It can contain a sequence of elements, such as `Set`, `Put`, `Call` that act on the retrieved object.
on the retrieved object.
[cols=",,",options="header",] [cols=",,",options="header",]
|======================================================================= |=======================================================================
@ -1020,17 +966,13 @@ on the retrieved object.
later. later.
|======================================================================= |=======================================================================
The `name` attribute may be a comma separated list of property names, The `Name` attribute may be a comma separated list of property names, with the first property name being the "official" name, and the others names being old, deprecated property names that are kept for backward compatibility.
with the first property name being the "official" name, and the others A warning log is issued when deprecated property names are used.
names being old, deprecated property names that are kept for backward The `Default` attribute contains the value to use in case none of the property names is found.
compatibility. A warning log is issued when deprecated property names
are used. The `default` attribute contains the value to use in case none
of the property names is found.
===== Can Contain ===== Can Contain
The attributes may be expressed as contained Elements (Id, Name, The attributes may be expressed as contained Elements (`Id`, `Name`, `Default`).
Default).
===== Example ===== Example

View File

@ -18,7 +18,7 @@
=== Jetty XML Usage === Jetty XML Usage
Jetty provides an XML-based configuration. Jetty provides an XML-based configuration.
It is grounded in Java's Reflection API. Classes in the java.lang.reflect represent Java methods and classes, such that you can instantiate objects and invoke their methods based on their names and argument types. It is grounded in Java's Reflection API. Classes in the `java.lang.reflect` represent Java methods and classes, such that you can instantiate objects and invoke their methods based on their names and argument types.
Behind the scenes, Jetty's XML config parser translates the XML elements and attributes into Reflection calls. Behind the scenes, Jetty's XML config parser translates the XML elements and attributes into Reflection calls.
[[using-jettyxml]] [[using-jettyxml]]
@ -48,7 +48,7 @@ If you use the same ID across multiple configuration files, those configurations
[[setting-parameters-in-configuration-files]] [[setting-parameters-in-configuration-files]]
==== Setting Parameters in Configuration Files ==== Setting Parameters in Configuration Files
You can set parameters in configuration files either with system properties (using ` <SystemProperty>`) or properties files (using `<Property>`) passed via the command line. You can set parameters in configuration files either with system properties (using `<SystemProperty>`) or properties files (using `<Property>`) passed via the command line.
For example, this code in `jetty.xml` allows the port to be defined on the command line, falling back onto `8080`if the port is not specified: For example, this code in `jetty.xml` allows the port to be defined on the command line, falling back onto `8080`if the port is not specified:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]

View File

@ -22,17 +22,18 @@ The challenge is to do so without changing the webapp itself. You can use a `jet
But there are some changes that `jetty.xml` cannot accomplish, for example, modifications to servlet init-params and context init-params. But there are some changes that `jetty.xml` cannot accomplish, for example, modifications to servlet init-params and context init-params.
Using `webdefault.xml` is not an option because Jetty applies `webdefault.xml` to a web application _before_ the application's own `WEB-INF/web.xml`, which means that it cannot override values inside the webapp's ` web.xml`. Using `webdefault.xml` is not an option because Jetty applies `webdefault.xml` to a web application _before_ the application's own `WEB-INF/web.xml`, which means that it cannot override values inside the webapp's ` web.xml`.
The solution is `override-web.xml`. It is a `web.xml` file that Jetty applies to a web application _after_ the application's own `WEB-INF/web.xml`, which means that it can override values or add new elements. The solution is `override-web.xml`.
You define it per-webapp, using the xref:jetty-xml-syntax[]. It is a `web.xml` file that Jetty applies to a web application _after_ the application's own `WEB-INF/web.xml`, which means that it can override values or add new elements.
This is defined on a per-webapp basis, using the xref:jetty-xml-syntax[].
[[using-override-web-xml]] [[using-override-web-xml]]
==== Using `override-web.xml` ==== Using override-web.xml
You can specify the `override-web.xml` to use for an individual web application, in that webapp's xref:jetty-web-xml-config[]. You can specify the `override-web.xml` to use for an individual web application in a deployable xml file located in Jetty webapps folder .
For example, if you had a webapp named MyApp, you would place a deployable xml file named `myapp.xml` in `${jetty.base}/webapps` which includes an `overrideDescriptor` entry for the `override-web.xml` file.
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Configure class="org.eclipse.jetty.webapp.WebAppContext">
... ...
<!-- Set up the path to the custom override descriptor, <!-- Set up the path to the custom override descriptor,
@ -40,15 +41,12 @@ You can specify the `override-web.xml` to use for an individual web application,
<Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/my/path/to/override-web.xml</Set> <Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/my/path/to/override-web.xml</Set>
... ...
</Configure> </Configure>
---- ----
The equivalent in code is: The equivalent in code is:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]
---- ----
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
... ...
@ -58,11 +56,9 @@ import org.eclipse.jetty.webapp.WebAppContext;
//Set the path to the override descriptor, based on your $(jetty.home) directory //Set the path to the override descriptor, based on your $(jetty.home) directory
wac.setOverrideDescriptor(System.getProperty("jetty.home")+"/my/path/to/override-web.xml"); wac.setOverrideDescriptor(System.getProperty("jetty.home")+"/my/path/to/override-web.xml");
... ...
---- ----
Alternatively, use the classloader (xref:jetty-classloading[]) to get the path to the override descriptor as a resource. Alternatively, you can use the classloader (xref:jetty-classloading[]) to get the path to the override descriptor as a resource.
[[override-using-jetty-maven-plugin]] [[override-using-jetty-maven-plugin]]
==== Using the Jetty Maven Plugin ==== Using the Jetty Maven Plugin
@ -71,7 +67,6 @@ Use the `<overrideDescriptor>` tag as follows:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
<project> <project>
... ...
<plugins> <plugins>
@ -89,8 +84,6 @@ Use the `<overrideDescriptor>` tag as follows:
</plugins> </plugins>
... ...
</project> </project>
---- ----
[[override-web-xml-additional-resources]] [[override-web-xml-additional-resources]]

View File

@ -18,7 +18,6 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
@ -86,112 +85,8 @@ public class HttpField
if (_value == null) if (_value == null)
return null; return null;
ArrayList<String> list = new ArrayList<>(); QuotedCSV list = new QuotedCSV(false,_value);
int state = 0; return list.getValues().toArray(new String[list.size()]);
int start=0;
int end=0;
StringBuilder builder = new StringBuilder();
for (int i=0;i<_value.length();i++)
{
char c = _value.charAt(i);
switch(state)
{
case 0: // initial white space
switch(c)
{
case '"': // open quote
state=2;
break;
case ',': // ignore leading empty field
break;
case ' ': // more white space
case '\t':
break;
default: // character
start=i;
end=i;
state=1;
}
break;
case 1: // In token
switch(c)
{
case ',': // next field
list.add(_value.substring(start,end+1));
state=0;
break;
case ' ': // more white space
case '\t':
break;
default:
end=i;
}
break;
case 2: // In Quoted
switch(c)
{
case '\\': // next field
state=3;
break;
case '"': // end quote
list.add(builder.toString());
builder.setLength(0);
state=4;
break;
default:
builder.append(c);
}
break;
case 3: // In Quoted Quoted
builder.append(c);
state=2;
break;
case 4: // WS after end quote
switch(c)
{
case ' ': // white space
case '\t': // white space
break;
case ',': // white space
state=0;
break;
default:
throw new IllegalArgumentException("c="+(int)c);
}
break;
}
}
switch(state)
{
case 0:
break;
case 1:
list.add(_value.substring(start,end+1));
break;
case 4:
break;
default:
throw new IllegalArgumentException("state="+state);
}
return list.toArray(new String[list.size()]);
} }
/** /**

View File

@ -282,6 +282,100 @@ public class HttpFields implements Iterable<HttpField>
return list; return list;
} }
/**
* Add comma separated values, but only if not already
* present.
* @param header The header to add the value(s) to
* @param values The value(s) to add
* @return True if headers were modified
*/
public boolean addCSV(HttpHeader header,String... values)
{
QuotedCSV existing = null;
for (HttpField f : this)
{
if (f.getHeader()==header)
{
if (existing==null)
existing = new QuotedCSV(false);
existing.addValue(f.getValue());
}
}
String value = addCSV(existing,values);
if (value!=null)
{
add(header,value);
return true;
}
return false;
}
/**
* Add comma separated values, but only if not already
* present.
* @param header The header to add the value(s) to
* @param values The value(s) to add
* @return True if headers were modified
*/
public boolean addCSV(String name,String... values)
{
QuotedCSV existing = null;
for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name))
{
if (existing==null)
existing = new QuotedCSV(false);
existing.addValue(f.getValue());
}
}
String value = addCSV(existing,values);
if (value!=null)
{
add(name,value);
return true;
}
return false;
}
protected String addCSV(QuotedCSV existing,String... values)
{
// remove any existing values from the new values
boolean add = true;
if (existing!=null && !existing.isEmpty())
{
add = false;
for (int i=values.length;i-->0;)
{
String unquoted = QuotedCSV.unquote(values[i]);
if (existing.getValues().contains(unquoted))
values[i] = null;
else
add = true;
}
}
if (add)
{
StringBuilder value = new StringBuilder();
for (String v:values)
{
if (v==null)
continue;
if (value.length()>0)
value.append(", ");
value.append(v);
}
if (value.length()>0)
return value.toString();
}
return null;
}
/** /**
* Get multiple field values of the same name, split * Get multiple field values of the same name, split
* as a {@link QuotedCSV} * as a {@link QuotedCSV}
@ -292,11 +386,17 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getCSV(HttpHeader header,boolean keepQuotes) public List<String> getCSV(HttpHeader header,boolean keepQuotes)
{ {
QuotedCSV values = new QuotedCSV(keepQuotes); QuotedCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getHeader()==header) if (f.getHeader()==header)
{
if (values==null)
values = new QuotedCSV(keepQuotes);
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**
@ -309,11 +409,17 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getCSV(String name,boolean keepQuotes) public List<String> getCSV(String name,boolean keepQuotes)
{ {
QuotedCSV values = new QuotedCSV(keepQuotes); QuotedCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
{
if (values==null)
values = new QuotedCSV(keepQuotes);
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**
@ -325,11 +431,18 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getQualityCSV(HttpHeader header) public List<String> getQualityCSV(HttpHeader header)
{ {
QuotedQualityCSV values = new QuotedQualityCSV(); QuotedQualityCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getHeader()==header) if (f.getHeader()==header)
{
if (values==null)
values = new QuotedQualityCSV();
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**
@ -341,11 +454,17 @@ public class HttpFields implements Iterable<HttpField>
*/ */
public List<String> getQualityCSV(String name) public List<String> getQualityCSV(String name)
{ {
QuotedQualityCSV values = new QuotedQualityCSV(); QuotedQualityCSV values = null;
for (HttpField f : this) for (HttpField f : this)
{
if (f.getName().equalsIgnoreCase(name)) if (f.getName().equalsIgnoreCase(name))
{
if (values==null)
values = new QuotedQualityCSV();
values.addValue(f.getValue()); values.addValue(f.getValue());
return values.getValues(); }
}
return values==null?Collections.emptyList():values.getValues();
} }
/** /**

View File

@ -22,6 +22,8 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.eclipse.jetty.util.QuotedStringTokenizer;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Implements a quoted comma separated list of values * Implements a quoted comma separated list of values
@ -52,6 +54,9 @@ public class QuotedCSV implements Iterable<String>
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Add and parse a value string(s)
* @param value A value that may contain one or more Quoted CSV items.
*/
public void addValue(String value) public void addValue(String value)
{ {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
@ -241,6 +246,15 @@ public class QuotedCSV implements Iterable<String>
{ {
} }
public int size()
{
return _values.size();
}
public boolean isEmpty()
{
return _values.isEmpty();
}
public List<String> getValues() public List<String> getValues()
{ {

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -340,7 +341,89 @@ public class HttpFieldsTest
} }
@Test @Test
public void testGetQualityValues() throws Exception public void testGetCSV() throws Exception
{
HttpFields fields = new HttpFields();
fields.put("name0", "value0A,value0B");
fields.add("name0", "value0C,value0D");
fields.put("name1", "value1A, \"value\t, 1B\" ");
fields.add("name1", "\"value1C\",\tvalue1D");
Enumeration<String> e = fields.getValues("name0");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0A,value0B");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0C,value0D");
assertEquals(false, e.hasMoreElements());
e = Collections.enumeration(fields.getCSV("name0",false));
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0A");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0B");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0C");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value0D");
assertEquals(false, e.hasMoreElements());
e = Collections.enumeration(fields.getCSV("name1",false));
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value1A");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value\t, 1B");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value1C");
assertEquals(true, e.hasMoreElements());
assertEquals(e.nextElement(), "value1D");
assertEquals(false, e.hasMoreElements());
}
@Test
public void testAddQuotedCSV() throws Exception
{
HttpFields fields = new HttpFields();
fields.put("some", "value");
fields.add("name", "\"zero\"");
fields.add("name", "one, \"1 + 1\"");
fields.put("other", "value");
fields.add("name", "three");
fields.add("name", "four, I V");
List<String> list = fields.getCSV("name",false);
assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null));
assertEquals("three",HttpFields.valueParameters(list.get(3),null));
assertEquals("four",HttpFields.valueParameters(list.get(4),null));
assertEquals("I V",HttpFields.valueParameters(list.get(5),null));
fields.addCSV("name","six");
list = fields.getCSV("name",false);
assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null));
assertEquals("three",HttpFields.valueParameters(list.get(3),null));
assertEquals("four",HttpFields.valueParameters(list.get(4),null));
assertEquals("I V",HttpFields.valueParameters(list.get(5),null));
assertEquals("six",HttpFields.valueParameters(list.get(6),null));
fields.addCSV("name","1 + 1","7","zero");
list = fields.getCSV("name",false);
assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null));
assertEquals("three",HttpFields.valueParameters(list.get(3),null));
assertEquals("four",HttpFields.valueParameters(list.get(4),null));
assertEquals("I V",HttpFields.valueParameters(list.get(5),null));
assertEquals("six",HttpFields.valueParameters(list.get(6),null));
assertEquals("7",HttpFields.valueParameters(list.get(7),null));
}
@Test
public void testGetQualityCSV() throws Exception
{ {
HttpFields fields = new HttpFields(); HttpFields fields = new HttpFields();
@ -351,7 +434,8 @@ public class HttpFieldsTest
fields.add("name", "one;q=0.4"); fields.add("name", "one;q=0.4");
fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3"); fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3");
List<String> list = HttpFields.qualityList(fields.getValues("name",","));
List<String> list = fields.getQualityCSV("name");
assertEquals("zero",HttpFields.valueParameters(list.get(0),null)); assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
assertEquals("one",HttpFields.valueParameters(list.get(1),null)); assertEquals("one",HttpFields.valueParameters(list.get(1),null));
assertEquals("two",HttpFields.valueParameters(list.get(2),null)); assertEquals("two",HttpFields.valueParameters(list.get(2),null));

View File

@ -320,7 +320,7 @@ public class HttpTester
@Override @Override
public void parsedHeader(HttpField field) public void parsedHeader(HttpField field)
{ {
put(field.getName(),field.getValue()); add(field.getName(),field.getValue());
} }
@Override @Override

View File

@ -30,10 +30,8 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.CompressedContentFormat; import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.pathmap.PathSpecSet; import org.eclipse.jetty.http.pathmap.PathSpecSet;
import org.eclipse.jetty.server.HttpOutput; import org.eclipse.jetty.server.HttpOutput;
@ -489,12 +487,22 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
} }
} }
HttpOutput.Interceptor orig_interceptor = out.getInterceptor();
try
{
// install interceptor and handle // install interceptor and handle
out.setInterceptor(new GzipHttpOutputInterceptor(this,getVaryField(),baseRequest.getHttpChannel(),out.getInterceptor(),isSyncFlush())); out.setInterceptor(new GzipHttpOutputInterceptor(this,getVaryField(),baseRequest.getHttpChannel(),orig_interceptor,isSyncFlush()));
if (_handler!=null) if (_handler!=null)
_handler.handle(target,baseRequest, request, response); _handler.handle(target,baseRequest, request, response);
} }
finally
{
// reset interceptor if request not handled
if (!baseRequest.isHandled() && !baseRequest.isAsyncStarted())
out.setInterceptor(orig_interceptor);
}
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http.QuotedCSV;
import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpOutput; import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Response;
@ -190,7 +191,8 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
} }
// Has the Content-Encoding header already been set? // Has the Content-Encoding header already been set?
String ce=response.getHeader("Content-Encoding"); HttpFields fields = response.getHttpFields();
String ce=fields.get(HttpHeader.CONTENT_ENCODING);
if (ce != null) if (ce != null)
{ {
LOG.debug("{} exclude by content-encoding {}",this,ce); LOG.debug("{} exclude by content-encoding {}",this,ce);
@ -203,9 +205,13 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.COMMITTING)) if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.COMMITTING))
{ {
// We are varying the response due to accept encoding header. // We are varying the response due to accept encoding header.
HttpFields fields = response.getHttpFields();
if (_vary != null) if (_vary != null)
{
if (fields.contains(HttpHeader.VARY))
fields.addCSV(HttpHeader.VARY,_vary.getValues());
else
fields.add(_vary); fields.add(_vary);
}
long content_length = response.getContentLength(); long content_length = response.getContentLength();
if (content_length<0 && complete) if (content_length<0 && complete)

View File

@ -134,6 +134,8 @@ public class GzipHandlerTest
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
{ {
if (req.getParameter("vary")!=null)
response.addHeader("Vary",req.getParameter("vary"));
response.setHeader("ETag",__contentETag); response.setHeader("ETag",__contentETag);
String ifnm = req.getHeader("If-None-Match"); String ifnm = req.getHeader("If-None-Match");
if (ifnm!=null && ifnm.equals(__contentETag)) if (ifnm!=null && ifnm.equals(__contentETag))
@ -181,7 +183,7 @@ public class GzipHandlerTest
HttpTester.Response response; HttpTester.Response response;
request.setMethod("GET"); request.setMethod("GET");
request.setURI("/ctx/content"); request.setURI("/ctx/content?vary=Other");
request.setVersion("HTTP/1.0"); request.setVersion("HTTP/1.0");
request.setHeader("Host","tester"); request.setHeader("Host","tester");
@ -190,16 +192,16 @@ public class GzipHandlerTest
assertThat(response.getStatus(),is(200)); assertThat(response.getStatus(),is(200));
assertThat(response.get("Content-Encoding"),not(equalToIgnoringCase("gzip"))); assertThat(response.get("Content-Encoding"),not(equalToIgnoringCase("gzip")));
assertThat(response.get("ETag"),is(__contentETag)); assertThat(response.get("ETag"),is(__contentETag));
assertThat(response.get("Vary"),is("Accept-Encoding")); assertThat(response.getValuesList("Vary"),Matchers.contains("Other","Accept-Encoding"));
InputStream testIn = new ByteArrayInputStream(response.getContentBytes()); InputStream testIn = new ByteArrayInputStream(response.getContentBytes());
ByteArrayOutputStream testOut = new ByteArrayOutputStream(); ByteArrayOutputStream testOut = new ByteArrayOutputStream();
IO.copy(testIn,testOut); IO.copy(testIn,testOut);
assertEquals(__content, testOut.toString("UTF8")); assertEquals(__content, testOut.toString("UTF8"));
} }
@Test @Test
public void testGzipHandler() throws Exception public void testGzipHandler() throws Exception
{ {
@ -208,7 +210,7 @@ public class GzipHandlerTest
HttpTester.Response response; HttpTester.Response response;
request.setMethod("GET"); request.setMethod("GET");
request.setURI("/ctx/content"); request.setURI("/ctx/content?vary=Accept-Encoding,Other");
request.setVersion("HTTP/1.0"); request.setVersion("HTTP/1.0");
request.setHeader("Host","tester"); request.setHeader("Host","tester");
request.setHeader("accept-encoding","gzip"); request.setHeader("accept-encoding","gzip");
@ -218,7 +220,7 @@ public class GzipHandlerTest
assertThat(response.getStatus(),is(200)); assertThat(response.getStatus(),is(200));
assertThat(response.get("Content-Encoding"),Matchers.equalToIgnoringCase("gzip")); assertThat(response.get("Content-Encoding"),Matchers.equalToIgnoringCase("gzip"));
assertThat(response.get("ETag"),is(__contentETagGzip)); assertThat(response.get("ETag"),is(__contentETagGzip));
assertThat(response.get("Vary"),is("Accept-Encoding")); assertThat(response.getCSV("Vary",false),Matchers.contains("Accept-Encoding","Other"));
InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes())); InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
ByteArrayOutputStream testOut = new ByteArrayOutputStream(); ByteArrayOutputStream testOut = new ByteArrayOutputStream();