| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |
| <title>Chapter 3. 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 2. 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 3. Advanced topics</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="nio.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr></div><div class="chapter" title="Chapter 3. Advanced topics"><div class="titlepage"><div><div><h2 class="title"><a name="advanced"></a>Chapter 3. Advanced topics</h2></div></div></div> |
| |
| <div class="section" title="3.1. HTTP message parsing and formatting framework"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e1304"></a>3.1. 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. HTTP line parsing and formatting"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1307"></a>3.1.1. 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 ></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 ></p> |
| <pre class="programlisting"> |
| [0>7>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 ></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 ></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 ></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 ></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 ></p> |
| <pre class="programlisting"> |
| name1="value1"; param1="p1", name2="value2", name3="value3" |
| </pre> |
| </div> |
| <div class="section" title="3.1.2. HTTP message streams and session I/O buffers"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1349"></a>3.1.2. 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. HTTP message parsers and formatters"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1362"></a>3.1.3. 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. HTTP header parsing on demand"><div class="titlepage"><div><div><h3 class="title"><a name="d5e1377"></a>3.1.4. 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. Customizing HTTP connections"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d5e1385"></a>3.2. 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> </td><td width="20%" align="center"> </td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Chapter 2. NIO extensions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html> |