8663716d38
Split the project into the following modules: * common * buffer * codec * codec-http * transport * transport-* * handler * example * testsuite (integration tests that involve 2+ modules) * all (does nothing yet, but will make it generate netty.jar) This commit also fixes the compilation errors with transport-sctp on non-Linux systems. It will at least compile without complaints.
260 lines
8.8 KiB
Java
260 lines
8.8 KiB
Java
/*
|
|
* Copyright 2011 The Netty Project
|
|
*
|
|
* The Netty Project 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.
|
|
*/
|
|
package io.netty.handler.codec.http;
|
|
|
|
import java.util.Date;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
/**
|
|
* Encodes {@link Cookie}s into an HTTP header value. This encoder can encode
|
|
* the HTTP cookie version 0, 1, and 2.
|
|
* <p>
|
|
* This encoder is stateful. It maintains an internal data structure that
|
|
* holds the {@link Cookie}s added by the {@link #addCookie(String, String)}
|
|
* method. Once {@link #encode()} is called, all added {@link Cookie}s are
|
|
* encoded into an HTTP header value and all {@link Cookie}s in the internal
|
|
* data structure are removed so that the encoder can start over.
|
|
* <pre>
|
|
* // Client-side example
|
|
* {@link HttpRequest} req = ...;
|
|
* {@link CookieEncoder} encoder = new {@link CookieEncoder}(false);
|
|
* encoder.addCookie("JSESSIONID", "1234");
|
|
* res.setHeader("Cookie", encoder.encode());
|
|
*
|
|
* // Server-side example
|
|
* {@link HttpResponse} res = ...;
|
|
* {@link CookieEncoder} encoder = new {@link CookieEncoder}(true);
|
|
* encoder.addCookie("JSESSIONID", "1234");
|
|
* res.setHeader("Set-Cookie", encoder.encode());
|
|
* </pre>
|
|
*
|
|
* @see CookieDecoder
|
|
*
|
|
* @apiviz.stereotype utility
|
|
* @apiviz.has io.netty.handler.codec.http.Cookie oneway - - encodes
|
|
*/
|
|
public class CookieEncoder {
|
|
|
|
private final Set<Cookie> cookies = new TreeSet<Cookie>();
|
|
private final boolean server;
|
|
|
|
/**
|
|
* Creates a new encoder.
|
|
*
|
|
* @param server {@code true} if and only if this encoder is supposed to
|
|
* encode server-side cookies. {@code false} if and only if
|
|
* this encoder is supposed to encode client-side cookies.
|
|
*/
|
|
public CookieEncoder(boolean server) {
|
|
this.server = server;
|
|
}
|
|
|
|
/**
|
|
* Adds a new {@link Cookie} created with the specified name and value to
|
|
* this encoder.
|
|
*/
|
|
public void addCookie(String name, String value) {
|
|
cookies.add(new DefaultCookie(name, value));
|
|
}
|
|
|
|
/**
|
|
* Adds the specified {@link Cookie} to this encoder.
|
|
*/
|
|
public void addCookie(Cookie cookie) {
|
|
cookies.add(cookie);
|
|
}
|
|
|
|
/**
|
|
* Encodes the {@link Cookie}s which were added by {@link #addCookie(Cookie)}
|
|
* so far into an HTTP header value. If no {@link Cookie}s were added,
|
|
* an empty string is returned.
|
|
*/
|
|
public String encode() {
|
|
String answer;
|
|
if (server) {
|
|
answer = encodeServerSide();
|
|
} else {
|
|
answer = encodeClientSide();
|
|
}
|
|
cookies.clear();
|
|
return answer;
|
|
}
|
|
|
|
private String encodeServerSide() {
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
for (Cookie cookie: cookies) {
|
|
add(sb, cookie.getName(), cookie.getValue());
|
|
|
|
if (cookie.getMaxAge() >= 0) {
|
|
if (cookie.getVersion() == 0) {
|
|
addUnquoted(sb, CookieHeaderNames.EXPIRES,
|
|
new HttpHeaderDateFormat().format(
|
|
new Date(System.currentTimeMillis() +
|
|
cookie.getMaxAge() * 1000L)));
|
|
} else {
|
|
add(sb, CookieHeaderNames.MAX_AGE, cookie.getMaxAge());
|
|
}
|
|
}
|
|
|
|
if (cookie.getPath() != null) {
|
|
if (cookie.getVersion() > 0) {
|
|
add(sb, CookieHeaderNames.PATH, cookie.getPath());
|
|
} else {
|
|
addUnquoted(sb, CookieHeaderNames.PATH, cookie.getPath());
|
|
}
|
|
}
|
|
|
|
if (cookie.getDomain() != null) {
|
|
if (cookie.getVersion() > 0) {
|
|
add(sb, CookieHeaderNames.DOMAIN, cookie.getDomain());
|
|
} else {
|
|
addUnquoted(sb, CookieHeaderNames.DOMAIN, cookie.getDomain());
|
|
}
|
|
}
|
|
if (cookie.isSecure()) {
|
|
sb.append(CookieHeaderNames.SECURE);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
if (cookie.isHttpOnly()) {
|
|
sb.append(CookieHeaderNames.HTTPONLY);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
if (cookie.getVersion() >= 1) {
|
|
if (cookie.getComment() != null) {
|
|
add(sb, CookieHeaderNames.COMMENT, cookie.getComment());
|
|
}
|
|
|
|
add(sb, CookieHeaderNames.VERSION, 1);
|
|
|
|
if (cookie.getCommentUrl() != null) {
|
|
addQuoted(sb, CookieHeaderNames.COMMENTURL, cookie.getCommentUrl());
|
|
}
|
|
|
|
if(!cookie.getPorts().isEmpty()) {
|
|
sb.append(CookieHeaderNames.PORT);
|
|
sb.append((char) HttpCodecUtil.EQUALS);
|
|
sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
|
|
for (int port: cookie.getPorts()) {
|
|
sb.append(port);
|
|
sb.append((char) HttpCodecUtil.COMMA);
|
|
}
|
|
sb.setCharAt(sb.length() - 1, (char) HttpCodecUtil.DOUBLE_QUOTE);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
if (cookie.isDiscard()) {
|
|
sb.append(CookieHeaderNames.DISCARD);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sb.length() > 0) {
|
|
sb.setLength(sb.length() - 1);
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
private String encodeClientSide() {
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
for (Cookie cookie: cookies) {
|
|
if (cookie.getVersion() >= 1) {
|
|
add(sb, '$' + CookieHeaderNames.VERSION, 1);
|
|
}
|
|
|
|
add(sb, cookie.getName(), cookie.getValue());
|
|
|
|
if (cookie.getPath() != null) {
|
|
add(sb, '$' + CookieHeaderNames.PATH, cookie.getPath());
|
|
}
|
|
|
|
if (cookie.getDomain() != null) {
|
|
add(sb, '$' + CookieHeaderNames.DOMAIN, cookie.getDomain());
|
|
}
|
|
|
|
if (cookie.getVersion() >= 1) {
|
|
if(!cookie.getPorts().isEmpty()) {
|
|
sb.append('$');
|
|
sb.append(CookieHeaderNames.PORT);
|
|
sb.append((char) HttpCodecUtil.EQUALS);
|
|
sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
|
|
for (int port: cookie.getPorts()) {
|
|
sb.append(port);
|
|
sb.append((char) HttpCodecUtil.COMMA);
|
|
}
|
|
sb.setCharAt(sb.length() - 1, (char) HttpCodecUtil.DOUBLE_QUOTE);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(sb.length() > 0)
|
|
sb.setLength(sb.length() - 1);
|
|
return sb.toString();
|
|
}
|
|
|
|
private static void add(StringBuilder sb, String name, String val) {
|
|
if (val == null) {
|
|
addQuoted(sb, name, "");
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < val.length(); i ++) {
|
|
char c = val.charAt(i);
|
|
switch (c) {
|
|
case '\t': case ' ': case '"': case '(': case ')': case ',':
|
|
case '/': case ':': case ';': case '<': case '=': case '>':
|
|
case '?': case '@': case '[': case '\\': case ']':
|
|
case '{': case '}':
|
|
addQuoted(sb, name, val);
|
|
return;
|
|
}
|
|
}
|
|
|
|
addUnquoted(sb, name, val);
|
|
}
|
|
|
|
private static void addUnquoted(StringBuilder sb, String name, String val) {
|
|
sb.append(name);
|
|
sb.append((char) HttpCodecUtil.EQUALS);
|
|
sb.append(val);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
|
|
private static void addQuoted(StringBuilder sb, String name, String val) {
|
|
if (val == null) {
|
|
val = "";
|
|
}
|
|
|
|
sb.append(name);
|
|
sb.append((char) HttpCodecUtil.EQUALS);
|
|
sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
|
|
sb.append(val.replace("\\", "\\\\").replace("\"", "\\\""));
|
|
sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
|
|
private static void add(StringBuilder sb, String name, int val) {
|
|
sb.append(name);
|
|
sb.append((char) HttpCodecUtil.EQUALS);
|
|
sb.append(val);
|
|
sb.append((char) HttpCodecUtil.SEMICOLON);
|
|
}
|
|
}
|