You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2009/02/01 20:15:05 UTC
svn commit: r739817 [1/3] - in /httpcomponents/httpcore/trunk: ./
src/docbkx/ src/docbkx/resources/ src/docbkx/resources/xsl/
Author: olegk
Date: Sun Feb 1 19:15:05 2009
New Revision: 739817
URL: http://svn.apache.org/viewvc?rev=739817&view=rev
Log:
Added HttpCore tutorial
Added:
httpcomponents/httpcore/trunk/src/docbkx/
httpcomponents/httpcore/trunk/src/docbkx/advanced.xml
httpcomponents/httpcore/trunk/src/docbkx/fundamentals.xml
httpcomponents/httpcore/trunk/src/docbkx/index.xml
httpcomponents/httpcore/trunk/src/docbkx/nio-ext.xml
httpcomponents/httpcore/trunk/src/docbkx/preface.xml
httpcomponents/httpcore/trunk/src/docbkx/resources/
httpcomponents/httpcore/trunk/src/docbkx/resources/xsl/
httpcomponents/httpcore/trunk/src/docbkx/resources/xsl/fopdf.xsl
httpcomponents/httpcore/trunk/src/docbkx/resources/xsl/html.xsl
httpcomponents/httpcore/trunk/src/docbkx/resources/xsl/html_chunk.xsl
Modified:
httpcomponents/httpcore/trunk/pom.xml
Modified: httpcomponents/httpcore/trunk/pom.xml
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/pom.xml?rev=739817&r1=739816&r2=739817&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/pom.xml (original)
+++ httpcomponents/httpcore/trunk/pom.xml Sun Feb 1 19:15:05 2009
@@ -157,7 +157,41 @@
</execution>
</executions>
</plugin>
-
+ <plugin>
+ <groupId>com.agilejava.docbkx</groupId>
+ <artifactId>docbkx-maven-plugin</artifactId>
+ <version>2.0.8</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-html</goal>
+ <goal>generate-pdf</goal>
+ </goals>
+ <phase>pre-site</phase>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.docbook</groupId>
+ <artifactId>docbook-xml</artifactId>
+ <version>4.4</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <includes>index.xml</includes>
+ <chunkedOutput>true</chunkedOutput>
+ <xincludeSupported>true</xincludeSupported>
+ <htmlCustomization>src/docbkx/resources/xsl/html_chunk.xsl</htmlCustomization>
+ <foCustomization>src/docbkx/resources/xsl/fopdf.xsl</foCustomization>
+ <entities>
+ <entity>
+ <name>version</name>
+ <value>${pom.version}</value>
+ </entity>
+ </entities>
+ </configuration>
+ </plugin>
</plugins>
</build>
@@ -188,6 +222,13 @@
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <aggregate>true</aggregate>
+ <links>
+ <link>http://java.sun.com/j2se/1.5.0/docs/api/</link>
+ </links>
+ </configuration>
</plugin>
<plugin>
Added: httpcomponents/httpcore/trunk/src/docbkx/advanced.xml
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/src/docbkx/advanced.xml?rev=739817&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/src/docbkx/advanced.xml (added)
+++ httpcomponents/httpcore/trunk/src/docbkx/advanced.xml Sun Feb 1 19:15:05 2009
@@ -0,0 +1,462 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+ "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<!--
+ $HeadURL:$
+ $Revision:$
+ $Date:$
+
+ ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ ====================================================================
+
+-->
+<chapter id="advanced">
+ <title>Advanced topics</title>
+ <section>
+ <title>HTTP message parsing and formatting framework</title>
+ <para>
+ HTTP message processing framework is designed to be expressive and flexible while remaining
+ memory efficient and fast. HttpCore HTTP message processing code achieves near zero
+ intermediate garbage and near zero-copy buffering for its parsing and formatting
+ operations. The same HTTP message parsing and formatting API and implementations are used
+ by both the blocking and non-blocking transport implementations, which helps ensure a
+ consistent behavior of HTTP services regardless of the I/O model.
+ </para>
+ <section>
+ <title>HTTP line parsing and formatting</title>
+ <para>
+ HttpCore utilizes a number of low level components for all its line parsing and
+ formatting methods.
+ </para>
+ <para>
+ <classname>CharArrayBuffer</classname> represents a sequence of characters, usually a
+ single line in an HTTP message stream such as a request line, a status line or a
+ header. Internally <classname>CharArrayBuffer</classname> is backed by an array of
+ chars, which can be expanded to accommodate more input if needed. <classname>
+ CharArrayBuffer</classname> also provides a number of utility methods for manipulating
+ content of the buffer, storing more data and retrieving subsets of data.
+ </para>
+ <programlisting><![CDATA[
+CharArrayBuffer buf = new CharArrayBuffer(64);
+buf.append("header: data ");
+int i = buf.indexOf(':');
+String s = buf.substringTrimmed(i + 1, buf.length());
+System.out.println(s);
+System.out.println(s.length());
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+data
+4
+]]></programlisting>
+ <para>
+ <classname>ParserCursor</classname> represents a context of a parsing operation: the
+ bounds limiting the scope of the parsing operation and the current position the parsing
+ operation is expected to start at.
+ </para>
+ <programlisting><![CDATA[
+CharArrayBuffer buf = new CharArrayBuffer(64);
+buf.append("header: data ");
+int i = buf.indexOf(':');
+ParserCursor cursor = new ParserCursor(0, buf.length());
+cursor.updatePos(i + 1);
+System.out.println(cursor);
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+[0>7>14]
+]]></programlisting>
+ <para>
+ <interfacename>LineParser</interfacename> is the interface for parsing lines in the
+ head section of an HTTP message. There are individual methods for parsing a request
+ line, a status line, or a header line. The lines to parse are passed in memory, the
+ parser does not depend on any specific I/O mechanism.
+ </para>
+ <programlisting><![CDATA[
+CharArrayBuffer buf = new CharArrayBuffer(64);
+buf.append("HTTP/1.1 200");
+ParserCursor cursor = new ParserCursor(0, buf.length());
+
+LineParser parser = new BasicLineParser();
+ProtocolVersion ver = parser.parseProtocolVersion(buf, cursor);
+System.out.println(ver);
+System.out.println(buf.substringTrimmed(
+ cursor.getPos(),
+ cursor.getUpperBound()));
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+HTTP/1.1
+200
+]]></programlisting>
+ <programlisting><![CDATA[
+CharArrayBuffer buf = new CharArrayBuffer(64);
+buf.append("HTTP/1.1 200 OK");
+ParserCursor cursor = new ParserCursor(0, buf.length());
+LineParser parser = new BasicLineParser();
+StatusLine sl = parser.parseStatusLine(buf, cursor);
+System.out.println(sl.getReasonPhrase());
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+OK
+]]></programlisting>
+ <para>
+ <interfacename>LineFormatter</interfacename> for formatting elements of the head
+ section of an HTTP message. This is the complement to <interfacename>LineParser
+ </interfacename>. There are individual methods for formatting a request line, a status
+ line, or a header line.
+ </para>
+ <para>
+ Please note the formatting does not include the trailing line break sequence
+ <literal>CR-LF</literal>.
+ </para>
+ <programlisting><![CDATA[
+CharArrayBuffer buf = new CharArrayBuffer(64);
+LineFormatter formatter = new BasicLineFormatter();
+formatter.formatRequestLine(buf,
+ new BasicRequestLine("GET", "/", HttpVersion.HTTP_1_1));
+System.out.println(buf.toString());
+formatter.formatHeader(buf,
+ new BasicHeader("Content-Type", "text/plain"));
+System.out.println(buf.toString());
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+GET / HTTP/1.1
+Content-Type: text/plain
+]]></programlisting>
+ <para>
+ <interfacename>HeaderValueParser</interfacename> is the interface for parsing header
+ values into elements.
+ </para>
+ <programlisting><![CDATA[
+CharArrayBuffer buf = new CharArrayBuffer(64);
+HeaderValueParser parser = new BasicHeaderValueParser();
+buf.append("name1=value1; param1=p1, " +
+ "name2 = \"value2\", name3 = value3");
+ParserCursor cursor = new ParserCursor(0, buf.length());
+System.out.println(parser.parseHeaderElement(buf, cursor));
+System.out.println(parser.parseHeaderElement(buf, cursor));
+System.out.println(parser.parseHeaderElement(buf, cursor));
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+name1=value1; param1=p1
+name2=value2
+name3=value3
+]]></programlisting>
+ <para>
+ <interfacename>HeaderValueFormatter</interfacename> is the interface for formatting
+ elements of a header value. This is the complement to <interfacename>HeaderValueParser
+ </interfacename>.
+ </para>
+ <programlisting><![CDATA[
+CharArrayBuffer buf = new CharArrayBuffer(64);
+HeaderValueFormatter formatter = new BasicHeaderValueFormatter();
+HeaderElement[] hes = new HeaderElement[] {
+ new BasicHeaderElement("name1", "value1",
+ new NameValuePair[] {
+ new BasicNameValuePair("param1", "p1")} ),
+ new BasicHeaderElement("name2", "value2"),
+ new BasicHeaderElement("name3", "value3"),
+};
+formatter.formatElements(buf, hes, true);
+System.out.println(buf.toString());
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+name1="value1"; param1="p1", name2="value2", name3="value3"
+]]></programlisting>
+ </section>
+ <section>
+ <title>HTTP message streams and session I/O buffers</title>
+ <para>
+ HttpCore provides a number of utility classes for the blocking and non-blocking I/O
+ models that facilitate the processing of HTTP message streams, simplify handling of
+ <literal>CR-LF</literal> delimited lines in HTTP messages and manage intermediate data
+ buffering.
+ </para>
+ <para>
+ HTTP connection implementations usually rely on session input/output buffers for
+ reading and writing data from and to an HTTP message stream. Session input/output
+ buffer implementations are I/O model specific and are optimized either for blocking or
+ non-blocking operations.
+ </para>
+ <para>
+ Blocking HTTP connections use socket bound session buffers to transfer data. Session
+ buffer interfaces are similar to <classname>java.io.InputStream</classname> /
+ <classname>java.io.OutputStream</classname> classes, but they also provide methods for
+ reading and writing <literal>CR-LF</literal> delimited lines.
+ </para>
+ <programlisting><![CDATA[
+Socket socket1;
+Socket socket2;
+HttpParams params = new BasicHttpParams();
+SessionInputBuffer inbuffer = new SocketInputBuffer(
+ socket1, 4096, params);
+SessionOutputBuffer outbuffer = new SocketOutputBuffer(
+ socket2, 4096, params);
+
+CharArrayBuffer linebuf = new CharArrayBuffer(1024);
+inbuffer.readLine(linebuf);
+outbuffer.writeLine(linebuf);
+]]></programlisting>
+ <para>
+ Non-blocking HTTP connections use session buffers optimized for reading and writing
+ data from and to non-blocking NIO channels. NIO session input/output sessions help deal
+ with <literal>CR-LF</literal> delimited lines in a non-blocking I/O mode.
+ </para>
+ <programlisting><![CDATA[
+ReadableByteChannel channel1;
+WritableByteChannel channel2;
+
+HttpParams params = new BasicHttpParams();
+SessionInputBuffer inbuffer = new SessionInputBufferImpl(
+ 4096, 1024, params);
+SessionOutputBuffer outbuffer = new SessionOutputBufferImpl(
+ 4096, 1024, params);
+
+CharArrayBuffer linebuf = new CharArrayBuffer(1024);
+boolean endOfStream = false;
+int bytesRead = inbuffer.fill(channel1);
+if (bytesRead == -1) {
+ endOfStream = true;
+}
+if (inbuffer.readLine(linebuf, endOfStream)) {
+ outbuffer.writeLine(linebuf);
+}
+if (outbuffer.hasData()) {
+ outbuffer.flush(channel2);
+}
+]]></programlisting>
+ </section>
+ <section>
+ <title>HTTP message parsers and formatter</title>
+ <para>
+ HttpCore also provides a coarse-grained facade type of interfaces for parsing and
+ formatting of HTTP messages. Default implementations of those interfaces build upon the
+ functionality provided by <interfacename>SessionInputBuffer</interfacename> /
+ <interfacename>SessionOutputBuffer</interfacename> and <interfacename>HttpLineParser
+ </interfacename>/ <interfacename>HttpLineFormatter</interfacename> implementations.
+ </para>
+ <para>
+ Example of HTTP request parsing / writing for blocking HTTP connections:
+ </para>
+ <programlisting><![CDATA[
+SessionInputBuffer inbuffer;
+SessionOutputBuffer outbuffer;
+
+HttpParams params = new BasicHttpParams();
+
+HttpMessageParser requestParser = new HttpRequestParser(
+ inbuffer,
+ new BasicLineParser(),
+ new DefaultHttpRequestFactory(),
+ params);
+
+HttpRequest request = (HttpRequest) requestParser.parse();
+
+HttpMessageWriter requestWriter = new HttpRequestWriter(
+ outbuffer,
+ new BasicLineFormatter(),
+ params);
+
+requestWriter.write(request);
+]]></programlisting>
+ <para>
+ Example of HTTP response parsing / writing for blocking HTTP connections:
+ </para>
+ <programlisting><![CDATA[
+SessionInputBuffer inbuffer;
+SessionOutputBuffer outbuffer;
+
+HttpParams params = new BasicHttpParams();
+
+HttpMessageParser responseParser = new HttpResponseParser(
+ inbuffer,
+ new BasicLineParser(),
+ new DefaultHttpResponseFactory(),
+ params);
+
+HttpResponse response = (HttpResponse) responseParser.parse();
+
+HttpMessageWriter responseWriter = new HttpResponseWriter(
+ outbuffer,
+ new BasicLineFormatter(),
+ params);
+
+responseWriter.write(response);
+]]></programlisting>
+ <para>
+ Example of HTTP request parsing / writing for non-blocking HTTP connections:
+ </para>
+ <programlisting><![CDATA[
+SessionInputBuffer inbuffer;
+SessionOutputBuffer outbuffer;
+
+HttpParams params = new BasicHttpParams();
+
+NHttpMessageParser requestParser = new HttpRequestParser(
+ inbuffer,
+ new BasicLineParser(),
+ new DefaultHttpRequestFactory(),
+ params);
+
+HttpRequest request = (HttpRequest) requestParser.parse();
+
+NHttpMessageWriter requestWriter = new HttpRequestWriter(
+ outbuffer,
+ new BasicLineFormatter(),
+ params);
+
+requestWriter.write(request);
+]]></programlisting>
+ <para>
+ Example of HTTP response parsing / writing for non-blocking HTTP connections:
+ </para>
+ <programlisting><![CDATA[
+SessionInputBuffer inbuffer;
+SessionOutputBuffer outbuffer;
+
+HttpParams params = new BasicHttpParams();
+
+NHttpMessageParser responseParser = new HttpResponseParser(
+ inbuffer,
+ new BasicLineParser(),
+ new DefaultHttpResponseFactory(),
+ params);
+
+HttpResponse response = (HttpResponse) responseParser.parse();
+
+NHttpMessageWriter responseWriter = new HttpResponseWriter(
+ outbuffer,
+ new BasicLineFormatter(),
+ params);
+
+responseWriter.write(response);
+]]></programlisting>
+ </section>
+ <section>
+ <title>HTTP header parsing on demand</title>
+ <para>
+ The default implementations of <interfacename>HttpMessageParser</interfacename> and
+ <interfacename>NHttpMessageParser</interfacename> interfaces do not parse HTTP headers
+ immediately. Parsing of header value is deferred until its properties are accessed.
+ Those headers that are never used by the application will not be parsed at all. The
+ <classname>CharArrayBuffer</classname> backing the header can be obtained through an
+ optional <interfacename>FormattedHeader</interfacename> interface.
+ </para>
+ <programlisting><![CDATA[
+Header h1 = response.getFirstHeader("Content-Type");
+if (h1 instanceof FormattedHeader) {
+ CharArrayBuffer buf = ((FormattedHeader) h1).getBuffer();
+ System.out.println(buf);
+}
+]]></programlisting>
+ </section>
+ </section>
+ <section>
+ <title>Customizing HTTP connections</title>
+ <para>
+ One can customize the way HTTP connections parse and format HTTP messages by extending the
+ default implementations and overriding factory methods and replacing the default parser or
+ formatter implementations with a custom one.
+ </para>
+ <para>
+ For blocking HTTP connections one also can provide custom implementation of session
+ input/output buffers.
+ </para>
+ <programlisting><![CDATA[
+class MyDefaultNHttpClientConnection
+ extends DefaultNHttpClientConnection {
+
+ public MyDefaultNHttpClientConnection(
+ IOSession session,
+ HttpResponseFactory responseFactory,
+ ByteBufferAllocator allocator,
+ HttpParams params) {
+ super(session, responseFactory, allocator, params);
+ }
+
+ @Override
+ protected NHttpMessageWriter createRequestWriter(
+ SessionOutputBuffer buffer,
+ HttpParams params) {
+ return new HttpRequestWriter(
+ buffer, new BasicLineFormatter(), params);
+ }
+
+ @Override
+ protected NHttpMessageParser createResponseParser(
+ SessionInputBuffer buffer,
+ HttpResponseFactory responseFactory,
+ HttpParams params) {
+ return new HttpResponseParser(
+ buffer, new BasicLineParser(), responseFactory, params);
+ }
+
+};
+]]></programlisting>
+ <para>
+ For non-blocking HTTP connection implementation one can replace the default HTTP message
+ parser and formatter implementations. The session input/output buffer implementations can
+ be overridden at the I/O reactor level.
+ </para>
+ <programlisting><![CDATA[
+class MyDefaultHttpClientConnection
+ extends DefaultHttpClientConnection {
+
+ @Override
+ protected SessionInputBuffer createSessionInputBuffer(
+ Socket socket,
+ int buffersize,
+ HttpParams params) throws IOException {
+ return new MySocketInputBuffer(socket, buffersize, params);
+ }
+
+ @Override
+ protected SessionOutputBuffer createSessionOutputBuffer(
+ Socket socket,
+ int buffersize,
+ HttpParams params) throws IOException {
+ return new MySocketOutputBuffer(socket, buffersize, params);
+ }
+
+ @Override
+ protected HttpMessageWriter createRequestWriter(
+ SessionOutputBuffer buffer,
+ HttpParams params) {
+ return new MyHttpRequestWriter(
+ buffer, new BasicLineFormatter(), params);
+ }
+
+ @Override
+ protected HttpMessageParser createResponseParser(
+ SessionInputBuffer buffer,
+ HttpResponseFactory responseFactory,
+ HttpParams params) {
+ return new MyHttpResponseParser(
+ buffer, new BasicLineParser(), responseFactory, params);
+ }
+
+};
+]]></programlisting>
+ </section>
+</chapter>
Added: httpcomponents/httpcore/trunk/src/docbkx/fundamentals.xml
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/src/docbkx/fundamentals.xml?rev=739817&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/src/docbkx/fundamentals.xml (added)
+++ httpcomponents/httpcore/trunk/src/docbkx/fundamentals.xml Sun Feb 1 19:15:05 2009
@@ -0,0 +1,1215 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+ "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<!--
+ $HeadURL:$
+ $Revision:$
+ $Date:$
+
+ ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ ====================================================================
+
+-->
+<chapter id="fundamentals">
+ <title>Fundamentals</title>
+ <section>
+ <title>HTTP messages</title>
+ <section>
+ <title>Structure</title>
+ <para>
+ A HTTP message consists of a head and an optional body. The message head of an HTTP
+ request consists of a request line and a collection of header fields. The message head
+ of an HTTP response consists of a status line and a collection of header fields. All
+ HTTP messages must include the protocol version. Some HTTP messages can optionally
+ enclose a content body.
+ </para>
+ <para>
+ HttpCore defines the HTTP message object model that closely follows the definition and
+ provides an extensive support for serialization (formatting) and deserialization
+ (parsing) of HTTP message elements.
+ </para>
+ </section>
+ <section>
+ <title>Basic operations</title>
+ <section>
+ <title>HTTP request message</title>
+ <para>
+ HTTP request is a message sent from the client to the server. The first line of
+ that message includes the method to be applied to the resource, the identifier of
+ the resource, and the protocol version in use.
+ </para>
+ <programlisting><![CDATA[
+HttpRequest request = new BasicHttpRequest("GET", "/",
+ HttpVersion.HTTP_1_1);
+
+System.out.println(request.getRequestLine().getMethod());
+System.out.println(request.getRequestLine().getUri());
+System.out.println(request.getProtocolVersion());
+System.out.println(request.getRequestLine().toString());
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+GET
+/
+HTTP/1.1
+GET / HTTP/1.1
+]]></programlisting>
+ </section>
+ <section>
+ <title>HTTP response message</title>
+ <para>
+ HTTP response is a message sent by the server back to the client after having
+ received and interpreted a request message. The first line of that message
+ consists of the protocol version followed by a numeric status code and its
+ associated textual phrase.
+ </para>
+ <programlisting><![CDATA[
+HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
+ HttpStatus.SC_OK, "OK");
+
+System.out.println(response.getProtocolVersion());
+System.out.println(response.getStatusLine().getStatusCode());
+System.out.println(response.getStatusLine().getReasonPhrase());
+System.out.println(response.getStatusLine().toString());
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+HTTP/1.1
+200
+OK
+HTTP/1.1 200 OK
+]]></programlisting>
+ </section>
+ <section>
+ <title>HTTP message common properties and methods</title>
+ <para>
+ An HTTP message can contain a number of headers describing properties of the
+ message such as the content length, content type and so on. HttpCore provides
+ methods to retrieve, add, remove and enumerate headers.
+ </para>
+ <programlisting><![CDATA[
+HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
+ HttpStatus.SC_OK, "OK");
+response.addHeader("Set-Cookie",
+ "c1=a; path=/; domain=localhost");
+response.addHeader("Set-Cookie",
+ "c2=b; path=\"/\", c3=c; domain=\"localhost\"");
+Header h1 = response.getFirstHeader("Set-Cookie");
+System.out.println(h1);
+Header h2 = response.getLastHeader("Set-Cookie");
+System.out.println(h2);
+Header[] hs = response.getHeaders("Set-Cookie");
+System.out.println(hs.length);
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+Set-Cookie: c1=a; path=/; domain=localhost
+Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
+2
+]]></programlisting>
+ <para>
+ There is an efficient way to obtain all headers of a given type using the
+ <interfacename>HeaderIterator</interfacename> interface.
+ </para>
+ <programlisting><![CDATA[
+HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
+ HttpStatus.SC_OK, "OK");
+response.addHeader("Set-Cookie",
+ "c1=a; path=/; domain=localhost");
+response.addHeader("Set-Cookie",
+ "c2=b; path=\"/\", c3=c; domain=\"localhost\"");
+
+HeaderIterator it = response.headerIterator("Set-Cookie");
+
+while (it.hasNext()) {
+ System.out.println(it.next());
+}
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+Set-Cookie: c1=a; path=/; domain=localhost
+Set-Cookie: c2=b; path="/", c3=c; domain="localhost"
+]]></programlisting>
+ <para>
+ It also provides convenience methods to parse HTTP messages into individual
+ header elements.
+ </para>
+ <programlisting><![CDATA[
+HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
+ HttpStatus.SC_OK, "OK");
+response.addHeader("Set-Cookie",
+ "c1=a; path=/; domain=localhost");
+response.addHeader("Set-Cookie",
+ "c2=b; path=\"/\", c3=c; domain=\"localhost\"");
+
+HeaderElementIterator it = new BasicHeaderElementIterator(
+ response.headerIterator("Set-Cookie"));
+
+while (it.hasNext()) {
+ HeaderElement elem = it.nextElement();
+ System.out.println(elem.getName() + " = " + elem.getValue());
+ NameValuePair[] params = elem.getParameters();
+ for (int i = 0; i < params.length; i++) {
+ System.out.println(" " + params[i]);
+ }
+}
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+c1 = a
+ path=/
+ domain=localhost
+c2 = b
+ path=/
+c3 = c
+ domain=localhost
+]]></programlisting>
+ <para>
+ HTTP headers get tokenized into individual header elements only on demand. HTTP
+ headers received over an HTTP connection are stored internally as an array of
+ chars and parsed lazily only when their properties are accessed.
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>HTTP entity</title>
+ <para>
+ HTTP messages can carry a content entity associated with the request or response.
+ Entities can be found in some requests and in some responses, as they are optional.
+ Requests that use entities are referred to as entity enclosing requests. The HTTP
+ specification defines two entity enclosing methods: POST and PUT. Responses are
+ usually expected to enclose a content entity. There are exceptions to this rule such
+ as responses to HEAD method and 204 No Content, 304 Not Modified, 205 Reset Content
+ responses.
+ </para>
+ <para>
+ HttpCore distinguishes three kinds of entities, depending on where their content
+ originates:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <formalpara>
+ <title>streamed:</title>
+ The content is received from a stream, or generated on the fly. In particular,
+ this category includes entities being received from a connection. Streamed
+ entities are generally not repeatable.
+ </formalpara>
+ </listitem>
+ <listitem>
+ <formalpara>
+ <title>self-contained:</title>
+ The content is in memory or obtained by means that are independent from
+ a connection or other entity. Self-contained entities are generally repeatable.
+ </formalpara>
+ </listitem>
+ <listitem>
+ <formalpara>
+ <title>wrapping:</title>
+ The content is obtained from another entity.
+ </formalpara>
+ </listitem>
+ </itemizedlist>
+ <para>
+ This distinction is important for connection management with incoming entities. For
+ entities that are created by an application and only sent using the HttpCore framework,
+ the difference between streamed and self-contained is of little importance. In that
+ case, it is suggested to consider non-repeatable entities as streamed, and those that
+ are repeatable as self-contained.
+ </para>
+ <section>
+ <title>Repeatable entities</title>
+ <para>
+ An entity can be repeatable, meaning its content can be read more than once. This
+ is only possible with self contained entities (like
+ <classname>ByteArrayEntity</classname> or <classname>StringEntity</classname>).
+ </para>
+ </section>
+ <section>
+ <title>Using HTTP entities</title>
+ <para>
+ Since an entity can represent both binary and character content, it has support
+ for character encodings (to support the latter, ie. character content).
+ </para>
+ <para>
+ The entity is created when executing a request with enclosed content or when the
+ request was successful and the response body is used to send the result back to
+ the client.
+ </para>
+ <para>
+ To read the content from the entity, one can either retrieve the input stream via
+ the <methodname>HttpEntity#getContent()</methodname> method, which returns an
+ <classname>java.io.InputStream</classname>, or one can supply an output stream to
+ the <methodname>HttpEntity#writeTo(OutputStream)</methodname> method, which will
+ return once all content has been written to the given stream.
+ </para>
+ <para>
+ The <classname>EntityUtils</classname> class exposes several static methods to
+ more easily read the content or information from an entity. Instead of reading
+ the <classname>java.io.InputStream</classname> directly, one can retrieve the whole
+ content body in a string / byte array by using the methods from this class.
+ </para>
+ <para>
+ When the entity has been received with an incoming message, the methods
+ <methodname>HttpEntity#getContentType()</methodname> and
+ <methodname>HttpEntity#getContentLength()</methodname> methods can be used for
+ reading the common metadata such as <literal>Content-Type</literal> and
+ <literal>Content-Length</literal> headers (if they are available). Since the
+ <literal>Content-Type</literal> header can contain a character encoding for text
+ mime-types like <literal>text/plain</literal> or <literal>text/html</literal>,
+ the <methodname>HttpEntity#getContentEncoding()</methodname> method is used to
+ read this information. If the headers aren't available, a length of -1 will be
+ returned, and <literal>NULL</literal> for the content type. If the
+ <literal>Content-Type</literal> header is available, a Header object will be
+ returned.
+ </para>
+ <para>
+ When creating an entity for a outgoing message, this meta data has to be supplied
+ by the creator of the entity.
+ </para>
+ <programlisting><![CDATA[
+StringEntity myEntity = new StringEntity("important message",
+ "UTF-8");
+
+System.out.println(myEntity.getContentType());
+System.out.println(myEntity.getContentLength());
+System.out.println(EntityUtils.getContentCharSet(myEntity));
+System.out.println(EntityUtils.toString(myEntity));
+System.out.println(EntityUtils.toByteArray(myEntity).length);
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+Content-Type: text/plain; charset=UTF-8
+17
+UTF-8
+important message
+17
+]]></programlisting>
+ </section>
+ <section>
+ <title>Ensuring release of low level resources</title>
+ <para>
+ When finished with an entity that relies on an underlying input stream, it's
+ important to execute the <methodname>HttpEntity#consumeContent()</methodname>
+ method, so as to consume any available content on the stream, so the connection
+ could be released to any connection pools. If the incoming content is not consumed
+ fully, other requests may fail when this connection is re-used.
+ </para>
+ <para>
+ Alternatively one can simply check the result of <methodname>
+ HttpEntity#isStreaming()</methodname>, and keep reading from the input stream
+ until it returns false.
+ </para>
+ <para>
+ Self contained entities will always return false with <methodname>
+ HttpEntity#isStreaming()</methodname>, as there is no underlying stream it depends
+ on. For these entities <methodname>HttpEntity#consumeContent()</methodname> will
+ do nothing, and does not need to be called.
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>Creating entities</title>
+ <para>
+ There are a few ways to create entities. The following implementations are provided
+ by HttpCore:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <link linkend="basic-entity">
+ <classname>BasicHttpEntity</classname>
+ </link>
+ </listitem>
+ <listitem>
+ <link linkend="byte-array-entity">
+ <classname>ByteArrayEntity</classname>
+ </link>
+ </listitem>
+ <listitem>
+ <link linkend="string-entity">
+ <classname>StringEntity</classname>
+ </link>
+ </listitem>
+ <listitem>
+ <link linkend="input-stream-entity">
+ <classname>InputStreamEntity</classname>
+ </link>
+ </listitem>
+ <listitem>
+ <link linkend="file-entity">
+ <classname>FileEntity</classname>
+ </link>
+ </listitem>
+ <listitem>
+ <link linkend="entity-template">
+ <classname>EntityTemplate</classname>
+ </link>
+ </listitem>
+ <listitem>
+ <link linkend="entity-wrapper">
+ <classname>HttpEntityWrapper</classname>
+ </link>
+ </listitem>
+ <listitem>
+ <link linkend="buffered-entity">
+ <classname>BufferedHttpEntity</classname>
+ </link>
+ <classname>BufferedHttpEntity</classname>
+ </listitem>
+ </itemizedlist>
+ <section id="basic-entity">
+ <title><classname>BasicHttpEntity</classname></title>
+ <para>
+ This is exactly as the name implies, a basic entity that represents an underlying
+ stream. This is generally used for the entities received from HTTP messages.
+ </para>
+ <para>
+ This entity has an empty constructor. After construction it represents no content,
+ and has a negative content length.
+ </para>
+ <para>
+ One needs to set the content stream, and optionally the length. This can be done
+ with the <methodname>BasicHttpEntity#setContent(InputStream)</methodname> and
+ <methodname>BasicHttpEntity#setContentLength(long)</methodname> methods
+ respectively.
+ </para>
+ <programlisting><![CDATA[
+BasicHttpEntity myEntity = new BasicHttpEntity();
+myEntity.setContent(someInputStream);
+myEntity.setContentLength(340); // sets the length to 340
+]]></programlisting>
+ </section>
+ <section id="byte-array-entity">
+ <title><classname>ByteArrayEntity</classname></title>
+ <para>
+ <classname>ByteArrayEntity</classname> is a self contained, repeatable entity
+ that obtains its content from a given byte array. This byte array is supplied
+ to the constructor.
+ </para>
+ <programlisting><![CDATA[
+String myData = "Hello world on the other side!!";
+ByteArrayEntity myEntity = new ByteArrayEntity(myData.getBytes());
+]]></programlisting>
+ </section>
+ <section id="string-entity">
+ <title><classname>StringEntity</classname></title>
+ <para>
+ <classname>StringEntity</classname> is a self contained, repeatable entity that
+ obtains its content from a <classname>java.lang.String</classname> object. It has
+ two constructors, one simply constructs with a given <classname>java.lang.String
+ </classname> object; the other also takes a character encoding for the data in the
+ string.
+ </para>
+ <programlisting><![CDATA[
+StringBuffer sb = new StringBuffer();
+Map<String, String> env = System.getenv();
+for (Entry<String, String> envEntry : env.entrySet()) {
+ sb.append(envEntry.getKey()).append(": ")
+ .append(envEntry.getValue()).append("\n");
+}
+
+// construct without a character encoding
+HttpEntity myEntity1 = new StringEntity(sb.toString());
+
+// alternatively construct with an encoding
+HttpEntity myEntity2 = new StringEntity(sb.toString(), "UTF-8");
+]]></programlisting>
+ </section>
+ <section id="input-stream-entity">
+ <title><classname>InputStreamEntity</classname></title>
+ <para>
+ <classname>InputStreamEntity</classname> is a streamed, non-repeatable entity that
+ obtains its content from an input stream. It is constructed by supplying the input
+ stream and the content length. The content length is used to limit the amount of
+ data read from the <classname>java.io.InputStream</classname>. If the length matches
+ the content length available on the input stream, then all data will be sent.
+ Alternatively a negative content length will read all data from the input stream,
+ which is the same as supplying the exact content length, so the length is most
+ often used to limit the length.
+ </para>
+ <programlisting><![CDATA[
+InputStream instream = getSomeInputStream();
+InputStreamEntity myEntity = new InputStreamEntity(instream, 16);
+]]></programlisting>
+ </section>
+ <section id="file-entity">
+ <title><classname>FileEntity</classname></title>
+ <para>
+ <classname>FileEntity</classname> is a self contained, repeatable entity that
+ obtains its content from a file. Since this is mostly used to stream large files
+ of different types, one needs to supply the content type of the file, for
+ instance, sending a zip file would require the content type <literal>
+ application/zip</literal>, for XML <literal>application/xml</literal>.
+ </para>
+ <programlisting><![CDATA[
+HttpEntity entity = new FileEntity(staticFile,
+ "application/java-archive");
+]]></programlisting>
+ </section>
+ <section id="entity-template">
+ <title><classname>EntityTemplate</classname></title>
+ <para>
+ This is an entity which receives its content from a
+ <interfacename>ContentProducer</interfacename> interface. Content producers are
+ objects which produce their content on demand, by writing it out to an output
+ stream. They are expected to be able produce their content every time they are
+ requested to do so. So creating a <classname>EntityTemplate</classname>, one is
+ expected to supply a reference to a content producer, which effectively creates
+ a repeatable entity.
+ </para>
+ <para>
+ There are no standard !ContentProducers in HttpCore. It is basically just a
+ convenience interface to allow wrapping up complex logic into an entity. To use
+ this entity one needs to create a class that implements <interfacename>
+ ContentProducer</interfacename> and override the <methodname>
+ ContentProducer#writeTo(OutputStream)</methodname> method. Then, an instance of
+ custom <interfacename>ContentProducer</interfacename> will be used to write the
+ full content body to the output stream. For instance, an HTTP server would serve
+ static files with the <classname>FileEntity</classname>, but running CGI programs
+ could be done with a <interfacename>ContentProducer</interfacename>, inside which
+ one could implement custom logic to supply the content as it becomes available.
+ This way one does not need to buffer it in a string and then use a <classname>
+ StringEntity</classname> or <classname>ByteArrayEntity</classname>.
+ </para>
+ <programlisting><![CDATA[
+ContentProducer myContentProducer = new ContentProducer() {
+
+ public void writeTo(OutputStream out) throws IOException {
+ out.write("ContentProducer rocks! ".getBytes());
+ out.write(("Time requested: " + new Date()).getBytes());
+ }
+
+};
+
+HttpEntity myEntity = new EntityTemplate(myContentProducer);
+myEntity.writeTo(System.out);
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+ContentProducer rocks! Time requested: Fri Sep 05 12:20:22 CEST 2008
+]]></programlisting>
+</section>
+ <section id="entity-wrapper">
+ <title><classname>HttpEntityWrapper</classname></title>
+ <para>
+ This is the base class for creating wrapped entities. The wrapping entity holds
+ a reference to a wrapped entity and delegates all calls to it. Implementations
+ of wrapping entities can derive from this class and need to override only those
+ methods that should not be delegated to the wrapped entity.
+ </para>
+ </section>
+ <section id="buffered-entity">
+ <title><classname>BufferedHttpEntity</classname></title>
+ <para>
+ <classname>BufferedHttpEntity</classname> is a subclass of <classname>
+ HttpEntityWrapper</classname>. It is constructed by supplying another entity. It
+ reads the content from the supplied entity, and buffers it in memory.
+ </para>
+ <para>
+ This makes it possible to make a repeatable entity, from a non-repeatable entity.
+ If the supplied entity is already repeated, calls are simply passed through to the
+ underlying entity.
+ </para>
+ <programlisting><![CDATA[
+myNonRepeatableEntity.setContent(someInputStream);
+BufferedHttpEntity myBufferedEntity = new BufferedHttpEntity(
+ myNonRepeatableEntity);
+]]></programlisting>
+ </section>
+ </section>
+ </section>
+ <section>
+ <title>Blocking HTTP connections</title>
+ <para>
+ HTTP connections are responsible for HTTP message serialization and deserialization. One
+ should rarely need to use HTTP connection objects directly. There are higher level protocol
+ components intended for execution and processing of HTTP requests. However, in some cases
+ direct interaction with HTTP connections may be necessary, for instance, to access
+ properties such as the connection status, the socket timeout or the local and remote
+ addresses.
+ </para>
+ <para>
+ It is important to bear in mind that HTTP connections are not thread-safe. It is strongly
+ recommended to limit all interactions with HTTP connection objects to one thread. The only
+ method of <interfacename>HttpConnection</interfacename> interface and its sub-interfaces,
+ which is safe to invoke from another thread, is <methodname> HttpConnection#shutdown()
+ </methodname>.
+ </para>
+ <section>
+ <title>Working with blocking HTTP connections</title>
+ <para>
+ HttpCore does not provide full support for opening connections because the process of
+ establishing a new connection especially on the client side can be very complex
+ involving one or several authenticating or/and tunneling proxies. Instead, blocking
+ HTTP connections can be bound to any arbitrary network socket.
+ </para>
+ <programlisting><![CDATA[
+Socket socket = new Socket();
+// Initialize socket
+BasicHttpParams params = new BasicHttpParams();
+DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+conn.bind(socket, params);
+conn.isOpen();
+HttpConnectionMetrics metrics = conn.getMetrics();
+metrics.getRequestCount();
+metrics.getResponseCount();
+metrics.getReceivedBytesCount();
+metrics.getSentBytesCount();
+]]></programlisting>
+ <para>
+ HTTP connection interfaces, both client and server, send and receive messages in two
+ stages. The message head is transmitted first. Depending on properties of the message
+ head it may be followed by a message body. Please note it is very important to call
+ <methodname>HttpEntity#consumeContent()</methodname> to signal that the processing of
+ the message is complete. HTTP entities that stream out their content directly from the
+ input stream of the underlying connection must ensure the content of the message body
+ is fully consumed for that connection to be potentially re-usable.
+ </para>
+ <para>
+ Over-simplified process of client side request execution may look like this:
+ </para>
+ <programlisting><![CDATA[
+Socket socket = new Socket();
+// Initialize socket
+HttpParams params = new BasicHttpParams();
+DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+conn.bind(socket, params);
+HttpRequest request = new BasicHttpRequest("GET", "/");
+conn.sendRequestHeader(request);
+HttpResponse response = conn.receiveResponseHeader();
+conn.receiveResponseEntity(response);
+HttpEntity entity = response.getEntity();
+if (entity != null) {
+ // Do something useful with the entity and, when done, call
+ // consumeContent() to make sure the connection can be re-used
+ entity.consumeContent();
+}
+]]></programlisting>
+ <para>
+ Over-simplified process of server side request handling may look like this:
+ </para>
+ <programlisting><![CDATA[
+Socket socket = new Socket();
+// Initialize socket
+HttpParams params = new BasicHttpParams();
+DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
+conn.bind(socket, params);
+HttpRequest request = conn.receiveRequestHeader();
+if (request instanceof HttpEntityEnclosingRequest) {
+ conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
+ HttpEntity entity = ((HttpEntityEnclosingRequest) request)
+ .getEntity();
+ if (entity != null) {
+ // Do something useful with the entity and, when done,
+ // call consumeContent() to make sure the connection
+ // can be re-used
+ entity.consumeContent();
+ }
+}
+HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
+ 200, "OK");
+response.setEntity(new StringEntity("Got it"));
+conn.sendResponseHeader(response);
+conn.sendResponseEntity(response);
+]]></programlisting>
+ <para>
+ Please note that one should rarely need to transmit messages using these low level
+ methods and should use appropriate higher level HTTP service implementations instead.
+ </para>
+ </section>
+ <section>
+ <title>Content transfer with blocking I/O</title>
+ <para>
+ HTTP connections manage the process of the content transfer using the <interfacename>
+ HttpEntity</interfacename> interface. HTTP connections generate an entity object that
+ encapsulates the content stream of the incoming message. Please note that <methodname>
+ HttpServerConnection#receiveRequestEntity()</methodname> and <methodname>
+ HttpClientConnection#receiveResponseEntity()</methodname> do not retrieve or buffer any
+ incoming data. They merely inject an appropriate content codec based on the properties
+ of the incoming message. The content can be retrieved by reading from the content input
+ stream of the enclosed entity using <methodname>HttpEntity#getContent()</methodname>.
+ The incoming data will be decoded automatically completely transparently for the data
+ consumer. Likewise, HTTP connections rely on <methodname>
+ HttpEntity#writeTo(OutputStream)</methodname> method to generate the content of an
+ outgoing message. If an outgoing messages encloses an entity, the content will be
+ encoded automatically based on the properties of the message.
+ </para>
+ </section>
+ <section>
+ <title>Supported content transfer mechanisms</title>
+ <para>
+ Default implementations of HTTP connections support three content transfer mechanisms
+ defined by the HTTP/1.1 specification:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <formalpara>
+ <title><literal>Content-Length</literal> delimited:</title>
+ The end of the content entity is determined by the value of the <literal>
+ Content-Length</literal> header. Maximum entity length: <methodname>
+ Long#MAX_VALUE</methodname>.
+ </formalpara>
+ </listitem>
+ <listitem>
+ <formalpara>
+ <title>Identity coding:</title>
+ The end of the content entity is demarcated by closing the underlying
+ connection (end of stream condition). For obvious reasons the identity encoding
+ can only be used on the server side. Max entity length: unlimited.
+ </formalpara>
+ </listitem>
+ <listitem>
+ <formalpara>
+ <title>Chunk coding:</title>
+ The content is sent in small chunks. Max entity length: unlimited.
+ </formalpara>
+ </listitem>
+ </itemizedlist>
+ <para>
+ The appropriate content stream class will be created automatically depending on
+ properties of the entity enclosed with the message.
+ </para>
+ </section>
+ <section>
+ <title>Terminating HTTP connections</title>
+ <para>
+ HTTP connections can be terminated either gracefully by calling <methodname>
+ HttpConnection#close()</methodname> or forcibly by calling <methodname>
+ HttpConnection#shutdown()</methodname>. The former tries to flush all buffered data
+ prior to terminating the connection and may block indefinitely. The <methodname>
+ HttpConnection#close()</methodname> method is not thread-safe. The latter terminates
+ the connection without flushing internal buffers and returns control to the caller as
+ soon as possible without blocking for long. The <methodname>HttpConnection#shutdown()
+ </methodname> method is expected to be thread-safe.
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>HTTP exception handling</title>
+ <para>
+ All HttpCore components potentially throw two types of exceptions: <classname>IOException
+ </classname>in case of an I/O failure such as socket timeout or an socket reset and
+ <classname>HttpException</classname> that signals an HTTP failure such as a violation of
+ the HTTP protocol. Usually I/O errors are considered non-fatal and recoverable, whereas
+ HTTP protocol errors are considered fatal and cannot be automatically recovered from.
+ </para>
+ <section>
+ <title>Protocol exception</title>
+ <para>
+ <classname>ProtocolException</classname> signals a fatal HTTP protocol violation that
+ usually results in an immediate termination of the HTTP message processing.
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>HTTP protocol processors</title>
+ <para>
+ HTTP protocol interceptor is a routine that implements a specific aspect of the HTTP
+ protocol. Usually protocol interceptors are expected to act upon one specific header or a
+ group of related headers of the incoming message or populate the outgoing message with one
+ specific header or a group of related headers. Protocol interceptors can also manipulate
+ content entities enclosed with messages, transparent content compression / decompression
+ being a good example. Usually this is accomplished by using the 'Decorator' pattern where
+ a wrapper entity class is used to decorate the original entity. Several protocol
+ interceptors can be combined to form one logical unit.
+ </para>
+ <para>
+ HTTP protocol processor is a collection of protocol interceptors that implements the
+ 'Chain of Responsibility' pattern, where each individual protocol interceptor is expected
+ to work on a particular aspect of the HTTP protocol the interceptor is responsible for.
+ </para>
+ <para>
+ Usually the order in which interceptors are executed should not matter as long as they do
+ not depend on a particular state of the execution context. If protocol interceptors have
+ interdependencies and therefore must be executed in a particular order, they should be
+ added to the protocol processor in the same sequence as their expected execution order.
+ </para>
+ <para>
+ Protocol interceptors must be implemented as thread-safe. Similarly to servlets, protocol
+ interceptors should not use instance variables unless access to those variables is
+ synchronized.
+ </para>
+ <section>
+ <title>Standard protocol interceptors</title>
+ <para>
+ HttpCore comes with a number of most essential protocol interceptors for client and
+ server HTTP processing.
+ </para>
+ <section>
+ <title><classname>RequestContent</classname></title>
+ <para>
+ <classname>RequestContent</classname> is the most important interceptor for
+ outgoing requests. It is responsible for delimiting content length by adding
+ <literal>Content-Length</literal> or <literal>Transfer-Content</literal> headers
+ based on the properties of the enclosed entity and the protocol version. This
+ interceptor is required for correct functioning of client side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>ResponseContent</classname></title>
+ <para>
+ <classname>ResponseContent</classname> is the most important interceptor for
+ outgoing responses. It is responsible for delimiting content length by adding
+ <literal>Content-Length</literal> or <literal>Transfer-Content</literal> headers
+ based on the properties of the enclosed entity and the protocol version. This
+ interceptor is required for correct functioning of server side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>RequestConnControl</classname></title>
+ <para>
+ <classname>RequestConnControl</classname> is responsible for adding
+ <literal>Connection</literal> header to the outgoing requests, which is essential
+ for managing persistence of <literal>HTTP/1.0</literal> connections. This
+ interceptor is recommended for client side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>ResponseConnControl</classname></title>
+ <para>
+ <classname>ResponseConnControl</classname> is responsible for adding
+ <literal>Connection</literal> header to the outgoing responses, which is essential
+ for managing persistence of <literal>HTTP/1.0</literal> connections. This
+ interceptor is recommended for server side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>RequestDate</classname></title>
+ <para>
+ <classname>RequestDate</classname> is responsible for adding
+ <literal>Date</literal> header to the outgoing requests This interceptor is
+ optional for client side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>ResponseDate</classname></title>
+ <para>
+ <classname>ResponseDate</classname> is responsible for adding
+ <literal>Date</literal> header to the outgoing responses. This interceptor is
+ recommended for server side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>RequestExpectContinue</classname></title>
+ <para>
+ <classname>RequestExpectContinue</classname> is responsible for enabling the
+ 'expect-continue' handshake by adding <literal>Expect</literal> header. This
+ interceptor is recommended for client side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>RequestTargetHost</classname></title>
+ <para>
+ <classname>RequestTargetHost</classname> is responsible for adding
+ <literal>Host</literal> header. This interceptor is required for client side
+ protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>RequestUserAgent</classname></title>
+ <para>
+ <classname>RequestUserAgent</classname> is responsible for adding
+ <literal>User-Agent</literal> header. This interceptor is recommended for client
+ side protocol processors.
+ </para>
+ </section>
+ <section>
+ <title><classname>ResponseServer</classname></title>
+ <para>
+ <classname>ResponseServer</classname> is responsible for adding
+ <literal>Server</literal> header. This interceptor is recommended for server side
+ protocol processors.
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>Working with protocol processors</title>
+ <para>
+ Usually HTTP protocol processors are used to pre-process incoming messages prior to
+ executing application specific processing logic and to post-process outgoing messages.
+ </para>
+ <programlisting><![CDATA[
+BasicHttpProcessor httpproc = new BasicHttpProcessor();
+// Required protocol interceptors
+httpproc.addInterceptor(new RequestContent());
+httpproc.addInterceptor(new RequestTargetHost());
+// Recommended protocol interceptors
+httpproc.addInterceptor(new RequestConnControl());
+httpproc.addInterceptor(new RequestUserAgent());
+httpproc.addInterceptor(new RequestExpectContinue());
+
+HttpContext context = new BasicHttpContext();
+
+HttpRequest request = new BasicHttpRequest("GET", "/");
+httpproc.process(request, context);
+HttpResponse response = null;
+]]></programlisting>
+ <para>
+ Send the request to the target host and get a response.
+ </para>
+ <programlisting><![CDATA[
+httpproc.process(response, context);
+]]></programlisting>
+ </section>
+ <section>
+ <title>HTTP context</title>
+ <para>
+ Protocol interceptors can collaborate by sharing information - such as a processing
+ state - through an HTTP execution context. HTTP context is a structure that can be
+ used to map an attribute name to an attribute value. Internally HTTP context
+ implementations are usually backed by a <classname>HashMap</classname>. The primary
+ purpose of the HTTP context is to facilitate information sharing among various
+ logically related components. HTTP context can be used to store a processing state for
+ one message or several consecutive messages. Multiple logically related messages can
+ participate in a logical session if the same context is reused between consecutive
+ messages.
+ </para>
+ <programlisting><![CDATA[
+BasicHttpProcessor httpproc = new BasicHttpProcessor();
+httpproc.addInterceptor(new HttpRequestInterceptor() {
+
+ public void process(
+ HttpRequest request,
+ HttpContext context) throws HttpException, IOException {
+ String id = (String) context.getAttribute("session-id");
+ if (id != null) {
+ request.addHeader("Session-ID", id);
+ }
+ }
+
+
+});
+HttpRequest request = new BasicHttpRequest("GET", "/");
+httpproc.process(request, context);
+]]></programlisting>
+ <para>
+ <interfacename>HttpContext</interfacename> instances can be linked together to form a
+ hierarchy. In the simplest form one context can use content of another context to
+ obtain default values of attributes not present in the local context.
+ </para>
+ <programlisting><![CDATA[
+HttpContext parentContext = new BasicHttpContext();
+parentContext.setAttribute("param1", Integer.valueOf(1));
+parentContext.setAttribute("param2", Integer.valueOf(2));
+
+HttpContext localContext = new BasicHttpContext();
+localContext.setAttribute("param2", Integer.valueOf(0));
+localContext.setAttribute("param3", Integer.valueOf(3));
+HttpContext stack = new DefaultedHttpContext(localContext,
+ parentContext);
+
+System.out.println(stack.getAttribute("param1"));
+System.out.println(stack.getAttribute("param2"));
+System.out.println(stack.getAttribute("param3"));
+System.out.println(stack.getAttribute("param4"));
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+1
+0
+3
+null
+]]></programlisting>
+ </section>
+ </section>
+ <section>
+ <title>HTTP parameters</title>
+ <para>
+ <interfacename>HttpParams</interfacename> interface represents a collection of immutable
+ values that define a runtime behavior of a component. In many ways <interfacename>HttpParams
+ </interfacename> is similar to <interfacename>HttpContext</interfacename>. The main
+ distinction between the two lies in their use at runtime. Both interfaces represent a
+ collection of objects that are organized as a map of textual names to object values, but
+ serve distinct purposes:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <interfacename>HttpParams</interfacename> is intended to contain simple objects:
+ integers, doubles, strings, collections and objects that remain immutable at
+ runtime. <interfacename>HttpParams</interfacename> is expected to be used in the
+ 'write once - ready many' mode. <interfacename>HttpContext</interfacename> is
+ intended to contain complex objects that are very likely to mutate in the course of
+ HTTP message processing.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The purpose of <interfacename>HttpParams</interfacename> is to define a behavior of
+ other components. Usually each complex component has its own <interfacename>
+ HttpParams</interfacename> object. The purpose of <interfacename>HttpContext
+ </interfacename> is to represent an execution state of an HTTP process. Usually
+ the same execution context is shared among many collaborating objects.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ <interfacename>HttpParams</interfacename>, like <interfacename>HttpContext</interfacename>
+ can be linked together to form a hierarchy. In the simplest form one set of parameters can
+ use content of another one to obtain default values of parameters not present in the local
+ set.
+ </para>
+ <programlisting><![CDATA[
+HttpParams parentParams = new BasicHttpParams();
+parentParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
+ HttpVersion.HTTP_1_0);
+parentParams.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET,
+ "UTF-8");
+
+HttpParams localParams = new BasicHttpParams();
+localParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
+ HttpVersion.HTTP_1_1);
+localParams.setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,
+ Boolean.FALSE);
+HttpParams stack = new DefaultedHttpParams(localParams,
+ parentParams);
+
+System.out.println(stack.getParameter(
+ CoreProtocolPNames.PROTOCOL_VERSION));
+System.out.println(stack.getParameter(
+ CoreProtocolPNames.HTTP_CONTENT_CHARSET));
+System.out.println(stack.getParameter(
+ CoreProtocolPNames.USE_EXPECT_CONTINUE));
+System.out.println(stack.getParameter(
+ CoreProtocolPNames.USER_AGENT));
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+HTTP/1.1
+UTF-8
+false
+null
+]]></programlisting>
+ <section>
+ <title>HTTP parameter beans</title>
+ <para>
+ <interfacename>HttpParams</interfacename> interface allows for a great deal of
+ flexibility in handling configuration of components. Most importantly, new parameters
+ can be introduced without affecting binary compatibility with older versions. However,
+ <interfacename>HttpParams</interfacename> also has a certain disadvantage compared to
+ regular Java beans: <interfacename>HttpParams</interfacename> cannot be assembled using
+ a DI framework. To mitigate the limitation, HttpCore includes a number of bean classes
+ that can used in order to initialize <interfacename>HttpParams</interfacename> objects
+ using standard Java bean conventions.
+ </para>
+ <programlisting><![CDATA[
+HttpParams params = new BasicHttpParams();
+HttpProtocolParamBean paramsBean = new HttpProtocolParamBean(params);
+paramsBean.setVersion(HttpVersion.HTTP_1_1);
+paramsBean.setContentCharset("UTF-8");
+paramsBean.setUseExpectContinue(true);
+
+System.out.println(params.getParameter(
+ CoreProtocolPNames.PROTOCOL_VERSION));
+System.out.println(params.getParameter(
+ CoreProtocolPNames.HTTP_CONTENT_CHARSET));
+System.out.println(params.getParameter(
+ CoreProtocolPNames.USE_EXPECT_CONTINUE));
+System.out.println(params.getParameter(
+ CoreProtocolPNames.USER_AGENT));
+]]></programlisting>
+ <para>stdout ></para>
+ <programlisting><![CDATA[
+HTTP/1.1
+UTF-8
+false
+null
+]]></programlisting>
+ </section>
+ </section>
+ <section>
+ <title>Blocking HTTP protocol handlers</title>
+ <section>
+ <title>HTTP service</title>
+ <para>
+ <classname>HttpService</classname> is a server side HTTP protocol handler based in the
+ blocking I/O model that implements the essential requirements of the HTTP protocol for
+ the server side message processing as described by RFC 2616.
+ </para>
+ <para>
+ <classname>HttpService</classname> relies on <interfacename>HttpProcessor
+ </interfacename> instance to generate mandatory protocol headers for all outgoing
+ messages and apply common, cross-cutting message transformations to all incoming and
+ outgoing messages, whereas HTTP request handlers are expected to take care of
+ application specific content generation and processing.
+ </para>
+ <programlisting><![CDATA[
+HttpParams params;
+// Initialize HTTP parameters
+HttpProcessor httpproc;
+// Initialize HTTP processor
+
+HttpService httpService = new HttpService(
+ httpproc,
+ new DefaultConnectionReuseStrategy(),
+ new DefaultHttpResponseFactory());
+httpService.setParams(params);
+]]></programlisting>
+ <section>
+ <title>HTTP request handlers</title>
+ <para>
+ The <interfacename>HttpRequestHandler</interfacename> interface represents a
+ routine for processing of a specific group of HTTP requests. <classname>HttpService
+ </classname> is designed to take care of protocol specific aspects, whereas
+ individual request handlers are expected to take care of application specific HTTP
+ processing. The main purpose of a request handler is to generate a response object
+ with a content entity to be sent back to the client in response to the given
+ request.
+ </para>
+ <programlisting><![CDATA[
+HttpRequestHandler myRequestHandler = new HttpRequestHandler() {
+
+ public void handle(
+ HttpRequest request,
+ HttpResponse response,
+ HttpContext context) throws HttpException, IOException {
+ response.setStatusCode(HttpStatus.SC_OK);
+ response.addHeader("Content-Type", "text/plain");
+ response.setEntity(
+ new StringEntity("some important message"));
+ }
+
+};
+]]></programlisting>
+ </section>
+ <section>
+ <title>Request handler resolver</title>
+ <para>
+ HTTP request handlers are usually managed by a <interfacename>
+ HttpRequestHandlerResolver</interfacename> that matches a request URI to a request
+ handler. HttpCore includes a very simple implementation of the request handler
+ resolver based on a trivial pattern matching algorithm: <classname>
+ HttpRequestHandlerRegistry</classname> supports only three formats:
+ <literal>*</literal>, <literal><uri>*</literal> and
+ <literal>*<uri></literal>.
+ </para>
+ <programlisting><![CDATA[
+HttpService httpService;
+// Initialize HTTP service
+
+HttpRequestHandlerRegistry handlerResolver =
+ new HttpRequestHandlerRegistry();
+handlerReqistry.register("/service/*", myRequestHandler1);
+handlerReqistry.register("*.do", myRequestHandler2);
+handlerReqistry.register("*", myRequestHandler3);
+
+// Inject handler resolver
+httpService.setHandlerResolver(handlerResolver);
+]]></programlisting>
+ <para>
+ Users are encouraged to provide more sophisticated implementations of
+ <interfacename>HttpRequestHandlerResolver</interfacename>, for instance, based on
+ regular expressions.
+ </para>
+ </section>
+ <section>
+ <title>Using HTTP service to handle requests</title>
+ <para>
+ When fully initialized and configured, the <classname>HttpService</classname> can
+ be used to execute and handle requests for active HTTP connections. The
+ <methodname>HttpService#handleRequest()</methodname> method reads an incoming
+ request, generates a response and sends it back to the client. This method can be
+ executed in a loop to handle multiple requests on a persistent connection. The
+ <methodname>HttpService#handleRequest()</methodname> method is safe to execute from
+ multiple threads. This allows processing of requests on several connections
+ simultaneously, as long as all the protocol interceptors and requests handlers used
+ by the <classname>HttpService</classname> are thread safe.
+ </para>
+ <programlisting><![CDATA[
+HttpService httpService;
+// Initialize HTTP service
+HttpServerConnection conn;
+// Initialize connection
+HttpContext context;
+// Initialize HTTP context
+
+boolean active = true;
+try {
+ while (active && conn.isOpen()) {
+ httpService.handleRequest(conn, context);
+ }
+} finally {
+ conn.shutdown();
+}
+]]></programlisting>
+ </section>
+ </section>
+ <section>
+ <title>HTTP request executor</title>
+ <para>
+ <classname>HttpRequestExecutor</classname> is a client side HTTP protocol handler based
+ on the blocking I/O model that implements the essential requirements of the HTTP
+ protocol for the client side message processing, as described by RFC 2616.
+ <classname>HttpRequestExecutor</classname> relies on on <interfacename>HttpProcessor
+ </interfacename> instance to generate mandatory protocol headers for all outgoing
+ messages and apply common, cross-cutting message transformations to all incoming and
+ outgoing messages. Application specific processing can be implemented outside
+ <classname>HttpRequestExecutor</classname> once the request has been executed and a
+ response has been received.
+ </para>
+ <programlisting><![CDATA[
+HttpClientConnection conn;
+// Create connection
+HttpParams params;
+// Initialize HTTP parameters
+HttpProcessor httpproc;
+// Initialize HTTP processor
+HttpContext context;
+// Initialize HTTP context
+
+HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
+
+BasicHttpRequest request = new BasicHttpRequest("GET", "/");
+request.setParams(params);
+httpexecutor.preProcess(request, httpproc, context);
+HttpResponse response = httpexecutor.execute(
+ request, conn, context);
+response.setParams(params);
+httpexecutor.postProcess(response, httpproc, context);
+
+HttpEntity entity = response.getEntity();
+if (entity != null) {
+ entity.consumeContent();
+}
+]]></programlisting>
+ <para>
+ Methods of <classname>HttpRequestExecutor</classname> are safe to execute from multiple
+ threads. This allows execution of requests on several connections simultaneously, as
+ long as all the protocol interceptors used by the <classname>HttpRequestExecutor
+ </classname> are thread safe.
+ </para>
+ </section>
+ <section>
+ <title>Connection persistence / re-use</title>
+ <para>
+ The <interfacename>ConnectionReuseStrategy</interfacename> interface is intended to
+ determine whether the underlying connection can be re-used for processing of further
+ messages after the transmission of the current message has been completed. The default
+ connection re-use strategy attempts to keep connections alive whenever possible.
+ Firstly, it examines the version of the HTTP protocol used to transmit the message.
+ <literal>HTTP/1.1</literal> connections are persistent by default, while <literal>
+ HTTP/1.0</literal> connections are not. Secondly, it examines the value of the
+ <literal>Connection</literal> header. The peer can indicate whether it intends to
+ re-use the connection on the opposite side by sending <literal>Keep-Alive</literal> or
+ <literal>Close</literal> values in the <literal>Connection</literal> header. Thirdly,
+ the strategy makes the decision whether the connection is safe to re-use based on the
+ properties of the enclosed entity, if available.
+ </para>
+ </section>
+ </section>
+</chapter>
Added: httpcomponents/httpcore/trunk/src/docbkx/index.xml
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/src/docbkx/index.xml?rev=739817&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/src/docbkx/index.xml (added)
+++ httpcomponents/httpcore/trunk/src/docbkx/index.xml Sun Feb 1 19:15:05 2009
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+ "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<!--
+ $HeadURL:$
+ $Revision:$
+ $Date:$
+
+ ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ ====================================================================
+
+ This software consists of voluntary contributions made by many
+ individuals on behalf of the Apache Software Foundation. For more
+ information on the Apache Software Foundation, please see
+ <http://www.apache.org />.
+ -->
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <bookinfo>
+ <title>HttpCore Tutorial</title>
+ <releaseinfo>&version;</releaseinfo>
+
+ <authorgroup>
+ <author>
+ <firstname>Oleg</firstname>
+ <surname>Kalnichevski</surname>
+ </author>
+ </authorgroup>
+
+ <legalnotice>
+ <para>
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+ </para>
+ <para>
+ <ulink url="http://www.apache.org/licenses/LICENSE-2.0"/>
+ </para>
+ <para>
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+ <toc/>
+
+ <xi:include href="preface.xml"/>
+ <xi:include href="fundamentals.xml"/>
+ <xi:include href="nio-ext.xml"/>
+ <xi:include href="advanced.xml"/>
+
+</book>