Dear Wiki user, You have subscribed to a wiki page or wiki category on "Httpcomponents Wiki" for change notification.
The following page has been changed by OlegKalnichevski: http://wiki.apache.org/HttpComponents/HttpCoreTutorial ------------------------------------------------------------------------------ - = Introduction = + ---- + [[TableOfContents]] + ---- - == HttpCore goals and scope == + = Scope = - * A consisntent API for building client side and server side HTTP services + * A consistent API for building client / proxy / server side HTTP services - + * A consistent API for building both synchronous and asynchronous HTTP services - * A set of low level HTTP transport components based on blocking and non-blocking + * A set of low level components based on blocking (classic) and non-blocking (NIO) I/O models - I/O models - + + = Goals = + + * Implementation of the most fundamental HTTP transport aspects + * Balance between good performance and clarify and expressiveness of API - * small, predictable memory footprint + * Small (predictable) memory footprint - - * self-contained library with no external dependencies + * Self contained library (no external dependencies beyond JRE) + + == What HttpCore is NOT == + + * Replacement for !HttpClient + * A replacement for a Servlet container and a competitor to the Servlet API = Fundamentals = - + == HTTP messages == === Structure === + 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. - 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. + !HttpCore defines HTTP message object model that closely follows the definition and provides an extensive support for serialization (formatting) and deserialization (parsing) of HTTP message elements. + - === Common operations === + === Basic operations === + ==== HTTP request properties ==== - Description of basic header operations: add header, remove header, set header, - enumerate headers + 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. + + {{{ + 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()); + }}} + + stdout > + {{{ + GET + / + HTTP/1.1 + GET / HTTP/1.1 + }}} + + ==== HTTP response properties ==== + + 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. + + {{{ + 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()); + }}} + + stdout > + {{{ + HTTP/1.1 + 200 + OK + HTTP/1.1 200 OK + }}} + + ==== HTTP message common properties and methods ==== + + 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. + + {{{ + 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); + }}} + + stdout > + {{{ + Set-Cookie: c1=a; path=/; domain=localhost + Set-Cookie: c2=b; path="/", c3=c; domain="localhost" + 2 + }}} + + There is an efficient way to obtain all headers of a given type using the !HeaderIterator interface. + + {{{ + 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()); + } + }}} + + stdout > + {{{ + Set-Cookie: c1=a; path=/; domain=localhost + Set-Cookie: c2=b; path="/", c3=c; domain="localhost" + }}} + + It also provides convenience methods to parse HTTP messages into individual header elements. + + {{{ + 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]); + } + } + }}} + + stdout > + {{{ + c1 = a + path=/ + domain=localhost + c2 = b + path=/ + c3 = c + domain=localhost + }}} + + HTTP headers get tokenized into individual header elements on demand only. HTTP headers received over an HTTP connection are stored internally as an array of chars and parsed lazily only then their properties are accessed. + + The char array backing the header can be obtained using the optional !FormattedHeader interface. + + {{{ + Header h1 = response.getFirstHeader("Content-Type"); + if (h1 instanceof FormattedHeader) { + CharArrayBuffer buf = ((FormattedHeader) h1).getBuffer(); + System.out.println(buf); + } + }}} + + - === HTTP entity === + == HTTP entity == - Properties of an HTTP entity. Types of HTTP entities. Streaming entities. Repeatable - entities. Entity wrapping. + HTTP messages can carry a content entity associated with the request or response. Entities can be found in some requests and in some responses, where they are optional. Requests that use entities are referred to as entity enclosing requests. 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. + + !HttpCore distinguishes three kinds of entities, depending on where their content originates: + + a. streamed: 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. + a. self-contained: The content is in memory or obtained by means that are independent from a connection or other entity. Self-contained entities are generally repeatable. + a. wrapping: The content is obtained from another entity. + + 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. + + === Repeatable entities === + + An entity can be repeatable, meaning it's content can be read more than once. This is only possible with self contained entities (like !ByteArrayEntity or !StringEntity). + + === Using HTTP entities === + + Since an entity can represent both binary and character content, it has support for character encodings (to support the latter, ie. character content). + + 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. + + To read the content from the entity, you can either retrieve the input stream via the !HttpEntity#getContent() method, which returns an !InputStream, or you can supply an output stream to the !HttpEntity.writeTo(!OutputStream) method, which will return once all content has been written to the given stream. + + The !EntityUtils class exposes several static methods to more easily read the content or information from an entity. Instead of reading the !InputStream yourself, you can retrieve the whole content body in a String/byte array by using the methods from this class. + + When the entity was received with an incoming message, the methods !HttpEntity#getContentType() and !HttpEntity#getContentLength() methods can be used for reading the common metadata such as Content-Type and Content-Length headers (if they are available). Since the Content-Type header can contain a character encoding for text mime-types like text/plain or text/html, the !HttpEntity#getContentEncoding() method is used to read this information. If the headers aren't available, a length of -1 will be returned, and NULL for the content-type. If the Content-Type header is available, a Header object will be returned. + + When creating an entity for a outgoing message, this meta data has to be supplied by the creator of the entity. + + {{{ + 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); + }}} + + stdout > + {{{ + Content-Type: text/plain; charset=UTF-8 + 17 + UTF-8 + important message + 17 + }}} + + === Ensuring release of low level resources === + + When you are finished with an entity that relies on an underlying input stream, it's important to execute the !HttpEntity#consumeContent() method, so as to clean up any available content on the stream so the connection be released to any connection pools. If you don't do this, other requests can't reuse this connection, since there are still available information on the buffer. + + Alternatively you can simply check the result of !HttpEntity#isStreaming(), and keep reading from the input stream until it returns false. + + Self contained entities will always return false with !HttpEntity#isStreaming(), as there is no underlying stream it depends on. For these entities !HttpEntity#consumeContent() will do nothing, and does not need to be called. + + == Creating entities == + + There are a few ways to create entities. You would want to do this when you implement custom responses, or send POST/PUT requests. + + These classes include the following implementations provided by !HttpCore: + a. [#BasicHttpEntity BasicHttpEntity] + a. [#BufferedHttpEntity BufferedHttpEntity] + a. [#ByteArrayEntity ByteArrayEntity] + a. [#EntityTemplate EntityTemplate] + a. [#FileEntity FileEntity] + a. [#InputStreamEntity InputStreamEntity] + a. [#StringEntity StringEntity] + a. [#AbstractHttpEntity AbstractHttpEntity] + a. [#HttpEntityWrapper HttpEntityWrapper] + + [[Anchor(BasicHttpEntity)]] + === BasicHttpEntity === + + This is exactly as the name implies, a basic entity that represents an underlying stream. This is generally the entities received from HTTP responses. + + This entity has an empty constructor. After constructor it represents no content, and has a negative content length. + + You need to set the content stream, and optionally the length. You can do this with the !BasicHttpEntity#setContent(!InputStream) and !BasicHttpEntity#setContentLength(long) methods respectively. + + {{{ + BasicHttpEntity myEntity = new BasicHttpEntity(); + myEntity.setContent(someInputStream); + myEntity.setContentLength(340); // sets the length to 340 + }}} + + [[Anchor(ByteArrayEntity)]] + === ByteArrayEntity === + + This is a simple self contained repeatable entity, which receives it's content from a given byte array. This byte array is supplied to the constructor. + + {{{ + String myData = "Hello world on the other side!!"; + ByteArrayEntity myEntity = new ByteArrayEntity(myData.getBytes()); + }}} + + [[Anchor(StringEntity)]] + === StringEntity === + + Very simple entity. It's is a self contained, repeatable entity that retrieves it's data from a String object. + + It has 2 constructors, one simply constructs with a given String object where the other also takes a character encoding for the data in the String. + + {{{ + 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"); + }}} + + [[Anchor(EntityTemplate)]] + === EntityTemplate === + + This is an entity which receives it's content from a !ContentProducer. 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 !EntityTemplate, you supply a reference to a content producer, which effectively creates a repeatable entity. + + There are no standard !ContentProducers in !HttpCore. It's basically just a convenience interface to allow wrapping up complex logic into an entity. To use this entity you will need to create a class that implements !ContentProducer and override the !ContentProducer#writeTo(!OutputStream) method. Inside this method you will write the full content body to the output stream. + + If you for instance made a HTTP server, you would serve static files with the !FileEntity, but running CGI programs can be done with a !ContentProducer, inside which you run the program and supply the content as it becomes available. This way you don't need to buffer it in a string and then use a !StringEntity or !ByteArrayEntity. + + {{{ + 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); + }}} + + stdout > + {{{ + ContentProducer rocks! Time requested: Fri Sep 05 12:20:22 CEST 2008 + }}} + + [[Anchor(FileEntity)]] + === FileEntity === + + This entity is reads it's content body from a file. Since this is mostly used to stream large files of different types, you need to supply the content type of the file, for instance, sending a zip you would supply the content type "application/zip", for XML "application/xml". + + {{{File staticFile = new File("/path/to/myapp.jar"); + HttpEntity entity = new FileEntity(staticFile, "application/java-archive"); + }}} + + [[Anchor(InputStreamEntity)]] + === InputStreamEntity === + + An entity that reads it's content from an input stream. It is constructed by supplied the input stream as well as the content length. + + The content length is used to limit the amount of data read from the !InputStream. 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. + + {{{ + InputStream instream = getSomeInputStream(); + InputStreamEntity myEntity = new InputStreamEntity(instream, 16); + }}} + + [[Anchor(AbstractHttpEntity)]] + === AbstractHttpEntity === + + This is the base class for streaming and self contained entities. It provides all the commonly used attributes used by these entities, like contentEncoding, contentType and the chunked flag. + + [[Anchor(HttpEntityWrapper)]] + === HttpEntityWrapper === + + This is the base class for creating wrapped entities. It contains an instance variable wrappedEntity which holds the instance to the wrapped entity. + + [[Anchor(BufferedHttpEntity)]] + === BufferedHttpEntity === + + !BufferedHttpEntity is a subclass of !HttpEntityWrapper. It is constructed by supplying another entity. It reads the content from the supplied entity, and buffers it in memory. + + This allows you 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. + + {{{BasicHttpEntity myNonRepeatableEntity = new BasicHttpEntity(); + myNonRepeatableEntity.setContent(someInputStream); + BufferedHttpEntity myBufferedEntity = new BufferedHttpEntity(myNonRepeatableEntity); + }}} == HTTP connections == - HTTP connections are responsible for HTTP message serialization and deserialization + 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. + + HTTP connections are NOT threading safe! It is strongly recommended to limit all interactions with HTTP connection objects to one thread. The only method of !HttpConnection interface and its sub-interfaces, which is safe to invoke from another thread, is !HttpConnection#shutdown(). + + === Using blocking HTTP connections === + + !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, HTTP connection objects can be bound to an arbitrary network socket. + + {{{ + BasicHttpParams params = new BasicHttpParams(); + DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); + conn.bind(mySocket, params); + conn.isOpen(); + HttpConnectionMetrics metrics = conn.getMetrics(); + metrics.getRequestCount(); + metrics.getResponseCount(); + metrics.getReceivedBytesCount(); + metrics.getSentBytesCount(); + }}} + + === Terminating HTTP connections === + + HTTP connections can be terminated either gracefully by calling !HttpConnection#close() or forcibly by calling !HttpConnection#shutdown(). The former tries to flush all buffered data prior to terminating the connection and may block indefinitely. The !HttpConnection#close() method is NOT threading 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 !HttpConnection#shutdown() method is expected to be threading safe. + + === Content transfer === + + * Content-Length delimited + + * Identity coding + + * Chunk coding === Parsing and formatting of HTTP messages === HttpMessageParser / HttpMessageWriter interfaces + - - === Content transfer === - - * Content-Length delimited - - * Identity coding - - * Chunk coding - == HTTP protocol processors == === Protocol interceptor === --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
