blob: 701375aecca128b8ae450565ec0b58ebf24ccff8 [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Chapter&nbsp;3.&nbsp;Advanced topics</title><link rel="stylesheet" type="text/css" href="css/hc-tutorial.css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.76.1"><link rel="home" href="index.html" title="HttpCore Tutorial"><link rel="up" href="index.html" title="HttpCore Tutorial"><link rel="prev" href="nio.html" title="Chapter&nbsp;2.&nbsp;NIO extensions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:fo="http://www.w3.org/1999/XSL/Format" class="banner"><a class="bannerLeft" href="http://www.apache.org/" title="Apache Software Foundation"><img style="border:none;" src="images/asf_logo_wide.gif"></a><a class="bannerRight" href="http://hc.apache.org/httpcomponents-core-ga/" title="Apache HttpComponents Core"><img style="border:none;" src="images/hc_logo.png"></a><div class="clear"></div></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter&nbsp;3.&nbsp;Advanced topics</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="nio.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;</td></tr></table><hr></div><div class="chapter" title="Chapter&nbsp;3.&nbsp;Advanced topics"><div class="titlepage"><div><div><h2 class="title"><a name="advanced"></a>Chapter&nbsp;3.&nbsp;Advanced topics</h2></div></div></div>
<div class="section" title="3.1.&nbsp;HTTP message parsing and formatting framework"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e1304"></a>3.1.&nbsp;HTTP message parsing and formatting framework</h2></div></div></div>
<p>
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.
</p>
<div class="section" title="3.1.1.&nbsp;HTTP line parsing and formatting"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1307"></a>3.1.1.&nbsp;HTTP line parsing and formatting</h3></div></div></div>
<p>
HttpCore utilizes a number of low level components for all its line parsing and
formatting methods.
</p>
<p>
<code class="classname">CharArrayBuffer</code> 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 <code class="classname">CharArrayBuffer</code> is backed by an array of
chars, which can be expanded to accommodate more input if needed. <code class="classname">
CharArrayBuffer</code> also provides a number of utility methods for manipulating
content of the buffer, storing more data and retrieving subsets of data.
</p>
<pre class="programlisting">
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());
</pre>
<p>stdout &gt;</p>
<pre class="programlisting">
data
4
</pre>
<p>
<code class="classname">ParserCursor</code> 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.
</p>
<pre class="programlisting">
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);
</pre>
<p>stdout &gt;</p>
<pre class="programlisting">
[0&gt;7&gt;14]
</pre>
<p>
<code class="interfacename">LineParser</code> 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.
</p>
<pre class="programlisting">
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()));
</pre>
<p>stdout &gt;</p>
<pre class="programlisting">
HTTP/1.1
200
</pre>
<pre class="programlisting">
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());
</pre>
<p>stdout &gt;</p>
<pre class="programlisting">
OK
</pre>
<p>
<code class="interfacename">LineFormatter</code> for formatting elements of the head
section of an HTTP message. This is the complement to <code class="interfacename">LineParser
</code>. There are individual methods for formatting a request line, a status
line, or a header line.
</p>
<p>
Please note the formatting does not include the trailing line break sequence
<code class="literal">CR-LF</code>.
</p>
<pre class="programlisting">
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());
</pre>
<p>stdout &gt;</p>
<pre class="programlisting">
GET / HTTP/1.1
Content-Type: text/plain
</pre>
<p>
<code class="interfacename">HeaderValueParser</code> is the interface for parsing header
values into elements.
</p>
<pre class="programlisting">
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));
</pre>
<p>stdout &gt;</p>
<pre class="programlisting">
name1=value1; param1=p1
name2=value2
name3=value3
</pre>
<p>
<code class="interfacename">HeaderValueFormatter</code> is the interface for formatting
elements of a header value. This is the complement to <code class="interfacename">HeaderValueParser
</code>.
</p>
<pre class="programlisting">
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());
</pre>
<p>stdout &gt;</p>
<pre class="programlisting">
name1="value1"; param1="p1", name2="value2", name3="value3"
</pre>
</div>
<div class="section" title="3.1.2.&nbsp;HTTP message streams and session I/O buffers"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1349"></a>3.1.2.&nbsp;HTTP message streams and session I/O buffers</h3></div></div></div>
<p>
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
<code class="literal">CR-LF</code> delimited lines in HTTP messages and manage intermediate data
buffering.
</p>
<p>
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.
</p>
<p>
Blocking HTTP connections use socket bound session buffers to transfer data. Session
buffer interfaces are similar to <code class="classname">java.io.InputStream</code> /
<code class="classname">java.io.OutputStream</code> classes, but they also provide methods for
reading and writing <code class="literal">CR-LF</code> delimited lines.
</p>
<pre class="programlisting">
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);
</pre>
<p>
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 <code class="literal">CR-LF</code> delimited lines in a non-blocking I/O mode.
</p>
<pre class="programlisting">
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);
}
</pre>
</div>
<div class="section" title="3.1.3.&nbsp;HTTP message parsers and formatters"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1362"></a>3.1.3.&nbsp;HTTP message parsers and formatters</h3></div></div></div>
<p>
HttpCore also provides coarse-grained facade type interfaces for parsing and
formatting of HTTP messages. Default implementations of those interfaces build upon the
functionality provided by <code class="interfacename">SessionInputBuffer</code> /
<code class="interfacename">SessionOutputBuffer</code> and <code class="interfacename">HttpLineParser
</code>/ <code class="interfacename">HttpLineFormatter</code> implementations.
</p>
<p>
Example of HTTP request parsing / writing for blocking HTTP connections:
</p>
<pre class="programlisting">
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);
</pre>
<p>
Example of HTTP response parsing / writing for blocking HTTP connections:
</p>
<pre class="programlisting">
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);
</pre>
<p>
Example of HTTP request parsing / writing for non-blocking HTTP connections:
</p>
<pre class="programlisting">
SessionInputBuffer inbuffer;
SessionOutputBuffer outbuffer;
HttpParams params = new BasicHttpParams();
NHttpMessageParser requestParser = new DefaultHttpRequestParser(
inbuffer,
new BasicLineParser(),
new DefaultHttpRequestFactory(),
params);
HttpRequest request = (HttpRequest) requestParser.parse();
NHttpMessageWriter requestWriter = new DefaultHttpRequestWriter(
outbuffer,
new BasicLineFormatter(),
params);
requestWriter.write(request);
</pre>
<p>
Example of HTTP response parsing / writing for non-blocking HTTP connections:
</p>
<pre class="programlisting">
SessionInputBuffer inbuffer;
SessionOutputBuffer outbuffer;
HttpParams params = new BasicHttpParams();
NHttpMessageParser responseParser = new DefaultHttpResponseParser(
inbuffer,
new BasicLineParser(),
new DefaultHttpResponseFactory(),
params);
HttpResponse response = (HttpResponse) responseParser.parse();
NHttpMessageWriter responseWriter = new DefaultHttpResponseWriter(
outbuffer,
new BasicLineFormatter(),
params);
responseWriter.write(response);
</pre>
</div>
<div class="section" title="3.1.4.&nbsp;HTTP header parsing on demand"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1377"></a>3.1.4.&nbsp;HTTP header parsing on demand</h3></div></div></div>
<p>
The default implementations of <code class="interfacename">HttpMessageParser</code> and
<code class="interfacename">NHttpMessageParser</code> 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
<code class="classname">CharArrayBuffer</code> backing the header can be obtained through an
optional <code class="interfacename">FormattedHeader</code> interface.
</p>
<pre class="programlisting">
Header h1 = response.getFirstHeader("Content-Type");
if (h1 instanceof FormattedHeader) {
CharArrayBuffer buf = ((FormattedHeader) h1).getBuffer();
System.out.println(buf);
}
</pre>
</div>
</div>
<div class="section" title="3.2.&nbsp;Customizing HTTP connections"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e1385"></a>3.2.&nbsp;Customizing HTTP connections</h2></div></div></div>
<p>
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.
</p>
<p>
For blocking HTTP connections one also can provide custom implementation of session
input/output buffers.
</p>
<pre class="programlisting">
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);
}
};
</pre>
<p>
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.
</p>
<pre class="programlisting">
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);
}
};
</pre>
</div>
</div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="nio.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;</td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;2.&nbsp;NIO extensions&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;</td></tr></table></div></body></html>