Merge pull request #422 from Massive-Dynamics/http-doc

Even more documentation changes (mainly) - HTTP
This commit is contained in:
Norman Maurer 2012-06-29 02:55:20 -07:00
commit cd95dc5924
5 changed files with 265 additions and 113 deletions

View File

@ -18,134 +18,191 @@ package io.netty.handler.codec.http;
import java.util.Set; import java.util.Set;
/** /**
* An HTTP <a href="http://en.wikipedia.org/wiki/HTTP_cookie">Cookie</a>. * An interface defining an
* <a href="http://en.wikipedia.org/wiki/HTTP_cookie">HTTP cookie</a>.
*/ */
public interface Cookie extends Comparable<Cookie> { public interface Cookie extends Comparable<Cookie> {
/** /**
* Returns the name of this cookie. * Returns the name of this {@link Cookie}.
*
* @return The name of this {@link Cookie}
*/ */
String getName(); String getName();
/** /**
* Returns the value of this cookie. * Returns the value of this {@link Cookie}.
*
* @return The value of this {@link Cookie}
*/ */
String getValue(); String getValue();
/** /**
* Sets the value of this cookie. * Sets the value of this {@link Cookie}.
*
* @param value The value to set
*/ */
void setValue(String value); void setValue(String value);
/** /**
* Returns the domain of this cookie. * Returns the domain of this {@link Cookie}.
*
* @return The domain of this {@link Cookie}
*/ */
String getDomain(); String getDomain();
/** /**
* Sets the domain of this cookie. * Sets the domain of this {@link Cookie}.
*
* @param domain The domain to use
*/ */
void setDomain(String domain); void setDomain(String domain);
/** /**
* Returns the path of this cookie. * Returns the path of this {@link Cookie}.
*
* @return The {@link Cookie}'s path
*/ */
String getPath(); String getPath();
/** /**
* Sets the path of this cookie. * Sets the path of this {@link Cookie}.
*
* @param path The path to use for this {@link Cookie}
*/ */
void setPath(String path); void setPath(String path);
/** /**
* Returns the comment of this cookie. * Returns the comment of this {@link Cookie}.
*
* @return The comment of this {@link Cookie}
*/ */
String getComment(); String getComment();
/** /**
* Sets the comment of this cookie. * Sets the comment of this {@link Cookie}.
*
* @param comment The comment to use
*/ */
void setComment(String comment); void setComment(String comment);
/** /**
* Returns the max age of this cookie in seconds. * Returns the maximum age of this {@link Cookie} in seconds.
*
* @return The maximum age of this {@link Cookie}
*/ */
long getMaxAge(); long getMaxAge();
/** /**
* Sets the max age of this cookie in seconds. If {@code 0} is specified, * Sets the maximum age of this {@link Cookie} in seconds.
* this cookie will be removed by browser because it will be expired * If an age of {@code 0} is specified, this {@link Cookie} will be
* immediately. If {@code -1} is specified, this cookie will be removed * automatically removed by browser because it will expire immediately.
* when a user terminates browser. * If {@code -1} is specified, this {@link Cookie} will be removed when the
* browser is closed.
*
* @param maxAge The maximum age of this {@link Cookie} in seconds
*/ */
void setMaxAge(long maxAge); void setMaxAge(long maxAge);
/** /**
* Returns the version of this cookie. * Returns the version of this {@link Cookie}.
*
* @return The version of this {@link Cookie}
*/ */
int getVersion(); int getVersion();
/** /**
* Sets the version of this cookie. * Sets the version of this {@link Cookie}.
*
* @param version The new version to use
*/ */
void setVersion(int version); void setVersion(int version);
/** /**
* Returns the secure flag of this cookie. * Checks to see if this {@link Cookie} is secure
*
* @return True if this {@link Cookie} is secure, otherwise false
*/ */
boolean isSecure(); boolean isSecure();
/** /**
* Sets the secure flag of this cookie. * Sets the security status of this {@link Cookie}
*
* @param secure True if this {@link Cookie} is to be secure, otherwise false
*/ */
void setSecure(boolean secure); void setSecure(boolean secure);
/** /**
* Returns if this cookie cannot be accessed through client side script. * Checks to see if this {@link Cookie} can only be accessed via HTTP.
* This flag works only if the browser supports it. For more information, * If this returns true, the {@link Cookie} cannot be accessed through
* see <a href="http://www.owasp.org/index.php/HTTPOnly">here</a>. * client side script - But only if the browser supports it.
* For more information, please look <a href="http://www.owasp.org/index.php/HTTPOnly">here</a>
*
* @return True if this {@link Cookie} is HTTP-only or false if it isn't
*/ */
boolean isHttpOnly(); boolean isHttpOnly();
/** /**
* Sets if this cookie cannot be accessed through client side script. * Determines if this {@link Cookie} is HTTP only.
* This flag works only if the browser supports it. For more information, * If set to true, this {@link Cookie} cannot be accessed by a client
* see <a href="http://www.owasp.org/index.php/HTTPOnly">here</a>. * side script. However, this works only if the browser supports it.
* For for information, please look
* <a href="http://www.owasp.org/index.php/HTTPOnly">here</a>.
*
* @param httpOnly True if the {@link Cookie} is HTTP only, otherwise false.
*/ */
void setHttpOnly(boolean httpOnly); void setHttpOnly(boolean httpOnly);
/** /**
* Returns the comment URL of this cookie. * Returns the comment URL of this {@link Cookie}.
*
* @return The comment URL of this {@link Cookie}
*/ */
String getCommentUrl(); String getCommentUrl();
/** /**
* Sets the comment URL of this cookie. * Sets the comment URL of this {@link Cookie}.
*
* @param commentUrl The comment URL to use
*/ */
void setCommentUrl(String commentUrl); void setCommentUrl(String commentUrl);
/** /**
* Returns the discard flag of this cookie. * Checks to see if this {@link Cookie} is to be discarded by the browser
* at the end of the current session.
*
* @return True if this {@link Cookie} is to be discarded, otherwise false
*/ */
boolean isDiscard(); boolean isDiscard();
/** /**
* Sets the discard flag of this cookie. * Sets the discard flag of this {@link Cookie}.
* If set to true, this {@link Cookie} will be discarded by the browser
* at the end of the current session
*
* @param discard True if the {@link Cookie} is to be discarded
*/ */
void setDiscard(boolean discard); void setDiscard(boolean discard);
/** /**
* Returns the ports of this cookie. * Returns the ports that this {@link Cookie} can be accessed on.
*
* @return The {@link Set} of ports that this {@link Cookie} can use
*/ */
Set<Integer> getPorts(); Set<Integer> getPorts();
/** /**
* Sets the ports of this cookie. * Sets the ports that this {@link Cookie} can be accessed on.
*
* @param ports The ports that this {@link Cookie} can be accessed on
*/ */
void setPorts(int... ports); void setPorts(int... ports);
/** /**
* Sets the ports of this cookie. * Sets the ports that this {@link Cookie} can be accessed on.
*
* @param ports The {@link Iterable} collection of ports that this
* {@link Cookie} can be accessed on.
*/ */
void setPorts(Iterable<Integer> ports); void setPorts(Iterable<Integer> ports);
} }

View File

@ -17,57 +17,84 @@ package io.netty.handler.codec.http;
import java.util.List; import java.util.List;
/**
* A utility class mainly for use with HTTP codec classes
*/
final class HttpCodecUtil { final class HttpCodecUtil {
static void validateHeaderName(String name) { /**
if (name == null) { * Validates the name of a header
throw new NullPointerException("name"); *
* @param headerName The header name being validated
*/
static void validateHeaderName(String headerName) {
//Check to see if the name is null
if (headerName == null) {
throw new NullPointerException("Header names cannot be null");
} }
for (int i = 0; i < name.length(); i ++) { //Go through each of the characters in the name
char c = name.charAt(i); for (int index = 0; index < headerName.length(); index ++) {
if (c > 127) { //Actually get the character
char character = headerName.charAt(index);
//Check to see if the character is not an ASCII character
if (character > 127) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"name contains non-ascii character: " + name); "Header name cannot contain non-ASCII characters: " + headerName);
} }
// Check prohibited characters. //Check for prohibited characters.
switch (c) { switch (character) {
case '\t': case '\n': case 0x0b: case '\f': case '\r': case '\t': case '\n': case 0x0b: case '\f': case '\r':
case ' ': case ',': case ':': case ';': case '=': case ' ': case ',': case ':': case ';': case '=':
throw new IllegalArgumentException( throw new IllegalArgumentException(
"name contains one of the following prohibited characters: " + "Header name cannot contain the following prohibited characters: " +
"=,;: \\t\\r\\n\\v\\f: " + name); "=,;: \\t\\r\\n\\v\\f: " + headerName);
} }
} }
} }
static void validateHeaderValue(String value) { /**
if (value == null) { * Validates the specified header value
throw new NullPointerException("value"); *
* @param value The value being validated
*/
static void validateHeaderValue(String headerValue) {
//Check to see if the value is null
if (headerValue == null) {
throw new NullPointerException("Header values cannot be null");
} }
// 0 - the previous character was neither CR nor LF /*
// 1 - the previous character was CR * Set up the state of the validation
// 2 - the previous character was LF *
* States are as follows:
*
* 0: Previous character was neither CR nor LF
* 1: The previous character was CR
* 2: The previous character was LF
*/
int state = 0; int state = 0;
for (int i = 0; i < value.length(); i ++) { //Start looping through each of the character
char c = value.charAt(i);
// Check the absolutely prohibited characters. for (int index = 0; index < headerValue.length(); index ++) {
switch (c) { char character = headerValue.charAt(index);
//Check the absolutely prohibited characters.
switch (character) {
case 0x0b: // Vertical tab case 0x0b: // Vertical tab
throw new IllegalArgumentException( throw new IllegalArgumentException(
"value contains a prohibited character '\\v': " + value); "Header value contains a prohibited character '\\v': " + headerValue);
case '\f': case '\f':
throw new IllegalArgumentException( throw new IllegalArgumentException(
"value contains a prohibited character '\\f': " + value); "Header value contains a prohibited character '\\f': " + headerValue);
} }
// Check the CRLF (HT | SP) pattern // Check the CRLF (HT | SP) pattern
switch (state) { switch (state) {
case 0: case 0:
switch (c) { switch (character) {
case '\r': case '\r':
state = 1; state = 1;
break; break;
@ -77,47 +104,56 @@ final class HttpCodecUtil {
} }
break; break;
case 1: case 1:
switch (c) { switch (character) {
case '\n': case '\n':
state = 2; state = 2;
break; break;
default: default:
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Only '\\n' is allowed after '\\r': " + value); "Only '\\n' is allowed after '\\r': " + headerValue);
} }
break; break;
case 2: case 2:
switch (c) { switch (character) {
case '\t': case ' ': case '\t': case ' ':
state = 0; state = 0;
break; break;
default: default:
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Only ' ' and '\\t' are allowed after '\\n': " + value); "Only ' ' and '\\t' are allowed after '\\n': " + headerValue);
} }
} }
} }
if (state != 0) { if (state != 0) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"value must not end with '\\r' or '\\n':" + value); "Header value must not end with '\\r' or '\\n':" + headerValue);
} }
} }
static boolean isTransferEncodingChunked(HttpMessage m) { /**
List<String> chunked = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING); * Checks to see if the transfer encoding in a specified {@link HttpMessage} is chunked
if (chunked.isEmpty()) { *
* @param message The message to check
* @return True if transfer encoding is chunked, otherwise false
*/
static boolean isTransferEncodingChunked(HttpMessage message) {
List<String> transferEncodingHeaders = message.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
if (transferEncodingHeaders.isEmpty()) {
return false; return false;
} }
for (String v: chunked) { for (String value: transferEncodingHeaders) {
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) { if (value.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
return true; return true;
} }
} }
return false; return false;
} }
/**
* A constructor to ensure that instances of this class are never made
*/
private HttpCodecUtil() { private HttpCodecUtil() {
} }
} }

View File

@ -25,8 +25,10 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* An HTTP message which provides common properties for {@link HttpRequest} and * An interface that defines a HTTP message, providing common properties for
* {@link HttpResponse}. * {@link HttpRequest} and {@link HttpResponse}.
* @see HttpResponse
* @see HttpRequest
* @see HttpHeaders * @see HttpHeaders
* *
* @apiviz.landmark * @apiviz.landmark
@ -35,86 +37,111 @@ import java.util.Set;
public interface HttpMessage { public interface HttpMessage {
/** /**
* Returns the header value with the specified header name. If there are * Returns the value of a header with the specified name. If there are
* more than one header value for the specified header name, the first * more than one values for the specified name, the first value is returned.
* value is returned.
* *
* @return the header value or {@code null} if there is no such header * @param name The name of the header to search
* @return The first header value or {@code null} if there is no such header
*/ */
String getHeader(String name); String getHeader(String name);
/** /**
* Returns the header values with the specified header name. * Returns the values of headers with the specified name
* *
* @return the {@link List} of header values. An empty list if there is no * @param name The name of the headers to search
* such header. * @return A {@link List} of header values which will be empty if no values
* are found
*/ */
List<String> getHeaders(String name); List<String> getHeaders(String name);
/** /**
* Returns the all header names and values that this message contains. * Returns the all headers that this message contains.
* *
* @return the {@link List} of the header name-value pairs. An empty list * @return A {@link List} of the header name-value entries, which will be
* if there is no header in this message. * empty if no pairs are found
*/ */
List<Map.Entry<String, String>> getHeaders(); List<Map.Entry<String, String>> getHeaders();
/** /**
* Returns {@code true} if and only if there is a header with the specified * Checks to see if there is a header with the specified name
* header name. *
* @param name The name of the header to search for
* @return True if at least one header is found
*/ */
boolean containsHeader(String name); boolean containsHeader(String name);
/** /**
* Returns the {@link Set} of all header names that this message contains. * Gets a {@link Set} of all header names that this message contains
*
* @return A {@link Set} of all header names
*/ */
Set<String> getHeaderNames(); Set<String> getHeaderNames();
/** /**
* Returns the protocol version of this message. * Returns the protocol version of this {@link HttpMessage}
*
* @returns The protocol version
*/ */
HttpVersion getProtocolVersion(); HttpVersion getProtocolVersion();
/** /**
* Sets the protocol version of this message. * Sets the protocol version of this {@link HttpMessage}
*
* @param version The version to set
*/ */
void setProtocolVersion(HttpVersion version); void setProtocolVersion(HttpVersion version);
/** /**
* Returns the content of this message. If there is no content or * Returns the content of this {@link HttpMessage}.
* {@link #isChunked()} returns {@code true}, an *
* {@link Unpooled#EMPTY_BUFFER} is returned. * If there is no content or {@link #isChunked()} returns {@code true},
* an {@link Unpooled#EMPTY_BUFFER} is returned.
*
* @return A {@link ByteBuf} containing this {@link HttpMessage}'s content
*/ */
ByteBuf getContent(); ByteBuf getContent();
/** /**
* Sets the content of this message. If {@code null} is specified, * Sets the content of this {@link HttpMessage}.
* the content of this message will be set to {@link Unpooled#EMPTY_BUFFER}. *
* If {@code null} is specified, the content of this message
* will be set to {@link Unpooled#EMPTY_BUFFER}
*
* @param content The {@link ByteBuf} containing the content to use
*/ */
void setContent(ByteBuf content); void setContent(ByteBuf content);
/** /**
* Adds a new header with the specified name and value. * Adds a new header with the specified name and value.
* If the specified value is not a {@link String}, it is converted into a *
* {@link String} by {@link Object#toString()}, except for {@link Date} * If the specified value is not a {@link String}, it is converted
* and {@link Calendar} which are formatted to the date format defined in * into a {@link String} by {@link Object#toString()}, except in the cases
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>. * of {@link Date} and {@link Calendar}, which are formatted to the date
* format defined in <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>.
*
* @param name The name of the header being added
* @param value The value of the header being added
*/ */
void addHeader(String name, Object value); void addHeader(String name, Object value);
/** /**
* Sets a new header with the specified name and value. If there is an * Sets a header with the specified name and value.
* existing header with the same name, the existing header is removed. *
* If there is an existing header with the same name, it is removed.
* If the specified value is not a {@link String}, it is converted into a * If the specified value is not a {@link String}, it is converted into a
* {@link String} by {@link Object#toString()}, except for {@link Date} * {@link String} by {@link Object#toString()}, except for {@link Date}
* and {@link Calendar} which are formatted to the date format defined in * and {@link Calendar}, which are formatted to the date format defined in
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>. * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>.
*
* @param name The name of the header being set
* @param value The value of the header being set
*/ */
void setHeader(String name, Object value); void setHeader(String name, Object value);
/** /**
* Sets a new header with the specified name and values. If there is an * Sets a header with the specified name and values.
* existing header with the same name, the existing header is removed. *
* If there is an existing header with the same name, it is removed.
* This method can be represented approximately as the following code: * This method can be represented approximately as the following code:
* <pre> * <pre>
* m.removeHeader(name); * m.removeHeader(name);
@ -125,42 +152,62 @@ public interface HttpMessage {
* m.addHeader(name, v); * m.addHeader(name, v);
* } * }
* </pre> * </pre>
*
* @param name The name of the headers being set
* @param values The values of the headers being set
*/ */
void setHeader(String name, Iterable<?> values); void setHeader(String name, Iterable<?> values);
/** /**
* Removes the header with the specified name. * Removes the header with the specified name.
*
* @param name The name of the header to remove
*/ */
void removeHeader(String name); void removeHeader(String name);
/** /**
* Removes all headers from this message. * Removes all headers from this {@link HttpMessage}.
*/ */
void clearHeaders(); void clearHeaders();
/** /**
* Returns {@code true} if and only if this message does not have any * Checks to see if this {@link HttpMessage} is broken into multiple "chunks"
* content but the {@link HttpChunk}s, which is generated by *
* {@link HttpMessageDecoder} consecutively, contain the actual content. * If this returns true, it means that this {@link HttpMessage}
* actually has no content - The {@link HttpChunk}s (which are generated
* by the {@link HttpMessageDecoder} consecutively) contain the actual content.
* <p> * <p>
* Please note that this method will keep returning {@code true} if the * Please note that this method will keep returning {@code true} if the
* {@code "Transfer-Encoding"} of this message is {@code "chunked"}, even if * {@code "Transfer-Encoding"} of this message is {@code "chunked"}, even if
* you attempt to override this property by calling {@link #setChunked(boolean)} * you attempt to override this property by calling {@link #setChunked(boolean)}
* with {@code false}. * with {@code false}.
* </p>
*
* @return True if this message is chunked, otherwise false
*/ */
boolean isChunked(); boolean isChunked();
/** /**
* Sets if this message does not have any content but the * Sets the boolean defining if this {@link HttpMessage} is chunked.
* {@link HttpChunk}s, which is generated by {@link HttpMessageDecoder} *
* consecutively, contain the actual content.
* <p> * <p>
* If this method is called with {@code true}, the content of this message * If this is set to true, it means that this initial {@link HttpMessage}
* becomes {@link Unpooled#EMPTY_BUFFER}. * does not contain any content - The content is contained by multiple
* {@link HttpChunk}s, which are generated by the {@link HttpMessageDecoder}
* consecutively.
*
* Because of this, the content of this {@link HttpMessage} becomes
* {@link Unpooled#EMPTY_BUFFER}
* </p>
*
* <p> * <p>
* Even if this method is called with {@code false}, {@link #isChunked()} * Even if this method is called with {@code false}, {@link #isChunked()}
* will keep returning {@code true} if the {@code "Transfer-Encoding"} of * will keep returning {@code true} if the {@code "Transfer-Encoding"} of
* this message is {@code "chunked"}. * this message is {@code "chunked"}.
* </p>
*
* @param chunked True if this message is to be delivered in chunks,
* otherwise false.
*/ */
void setChunked(boolean chunked); void setChunked(boolean chunked);
} }

View File

@ -34,22 +34,30 @@ package io.netty.handler.codec.http;
public interface HttpRequest extends HttpMessage { public interface HttpRequest extends HttpMessage {
/** /**
* Returns the method of this request. * Returns the {@link HttpMethod} of this {@link HttpRequest}.
*
* @return The {@link HttpMethod} of this {@link HttpRequest}
*/ */
HttpMethod getMethod(); HttpMethod getMethod();
/** /**
* Sets the method of this request. * Sets the {@link HttpMethod} of this {@link HttpRequest}.
*
* @param The {@link HttpMethod} to set
*/ */
void setMethod(HttpMethod method); void setMethod(HttpMethod method);
/** /**
* Returns the URI (or path) of this request. * Returns the requested URI (or alternatively, path)
*
* @return The URI being requested
*/ */
String getUri(); String getUri();
/** /**
* Sets the URI (or path) of this request. * Sets the URI (or alternatively, path) being requested.
*
* @param uri The URI being requested
*/ */
void setUri(String uri); void setUri(String uri);
} }

View File

@ -19,7 +19,7 @@ package io.netty.handler.codec.http;
/** /**
* An HTTP response. * An HTTP response.
* *
* <h3>Accessing Cookie</h3> * <h3>Accessing Cookies</h3>
* <p> * <p>
* Unlike the Servlet API, {@link Cookie} support is provided separately via {@link CookieDecoder}, * Unlike the Servlet API, {@link Cookie} support is provided separately via {@link CookieDecoder},
* {@link ClientCookieEncoder}, and {@link ServerCookieEncoder}. * {@link ClientCookieEncoder}, and {@link ServerCookieEncoder}.
@ -32,12 +32,16 @@ package io.netty.handler.codec.http;
public interface HttpResponse extends HttpMessage { public interface HttpResponse extends HttpMessage {
/** /**
* Returns the status of this response. * Returns the status of this {@link HttpResponse}.
*
* @return The {@link HttpResponseStatus} of this {@link HttpResponse}
*/ */
HttpResponseStatus getStatus(); HttpResponseStatus getStatus();
/** /**
* Sets the status of this response. * Sets the status of this {@link HttpResponse}
*
* @param status The {@link HttpResponseStatus} to use
*/ */
void setStatus(HttpResponseStatus status); void setStatus(HttpResponseStatus status);
} }