SetCookieHeader.java
/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2015-2016 ForgeRock AS.
*/
package org.forgerock.http.header;
import static java.util.Collections.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.forgerock.http.protocol.Cookie;
import org.forgerock.http.protocol.Header;
import org.forgerock.http.protocol.Response;
/**
* Processes the <strong>{@code Set-Cookie}</strong> request message header. For
* more information, see the Http State Management Mechanism specification <a
* href="http://tools.ietf.org/html/rfc6265">RFC 6265</a>.
* <p>
* Note: This implementation is designed to be forgiving when parsing malformed
* cookies.
*/
public class SetCookieHeader extends Header {
/** The name of this header. */
public static final String NAME = "Set-Cookie";
/**
* Constructs a new header, initialized from the specified string value.
*
* @param value
* The value to initialize the header from.
* @return The parsed header.
*/
public static SetCookieHeader valueOf(String value) {
return new SetCookieHeader(singletonList(parseCookie(value)));
}
private static Cookie parseCookie(String value) {
List<String> parts = Arrays.asList(value.split(";"));
Cookie cookie = new Cookie();
for (String part : parts) {
String[] nvp = part.split("=", 2);
if ("Expires".equalsIgnoreCase(nvp[0].trim())) {
cookie.setExpires(HeaderUtil.parseDate(nvp[1].trim()));
} else if ("Max-Age".equalsIgnoreCase(nvp[0].trim())) {
cookie.setMaxAge(parseInteger(nvp[1].trim()));
} else if ("Path".equalsIgnoreCase(nvp[0].trim())) {
cookie.setPath(nvp[1]);
} else if ("Domain".equalsIgnoreCase(nvp[0].trim())) {
cookie.setDomain(nvp[1]);
} else if ("Secure".equalsIgnoreCase(nvp[0].trim())) {
cookie.setSecure(true);
} else if ("HttpOnly".equalsIgnoreCase(nvp[0].trim())) {
cookie.setHttpOnly(true);
} else if (cookie.getName() == null || cookie.getName().isEmpty()) {
cookie.setName(nvp[0].trim());
cookie.setValue(nvp[1].trim());
}
}
if (cookie.getName() == null || cookie.getName().isEmpty()) {
cookie = new Cookie();
}
return cookie;
}
/**
* Constructs a new header, initialized from the specified response message.
*
* @param response
* The response message to initialize the header from.
* @return The parsed header.
*/
public static SetCookieHeader valueOf(Response response) {
if (response == null || !response.getHeaders().containsKey(NAME)) {
return null;
}
return valueOf(response.getHeaders().get(NAME).getValues());
}
/**
* Constructs a new header, initialized from the specified list of Set-Cookie values.
*
* @param values
* The values to initialize the header from.
* @return The parsed header.
*/
public static SetCookieHeader valueOf(List<String> values) {
if (values == null) {
return null;
}
List<Cookie> cookies = new ArrayList<>();
for (String headerValue : values) {
cookies.add(parseCookie(headerValue));
}
return new SetCookieHeader(unmodifiableList(cookies));
}
private static Integer parseInteger(String s) {
try {
return Integer.valueOf(s);
} catch (NumberFormatException nfe) {
return null;
}
}
private final List<Cookie> cookies;
private final List<String> values;
/**
* Constructs a new header with the provided cookies.
*
* @param cookies The cookies.
*/
public SetCookieHeader(List<Cookie> cookies) {
this.cookies = cookies;
if (cookies != null) {
this.values = new ArrayList<>();
for (Cookie cookie : cookies) {
values.add(toString(cookie));
}
} else {
values = null;
}
}
@Override
public String getName() {
return NAME;
}
@Override
public List<String> getValues() {
return values;
}
/**
* Returns the cookies.
*
* @return The cookies.
*/
public List<Cookie> getCookies() {
return cookies;
}
private String toString(Cookie cookie) {
StringBuilder sb = new StringBuilder();
if (cookie.getName() != null) {
sb.append(cookie.getName()).append("=").append(cookie.getValue());
if (cookie.getExpires() != null) {
sb.append("; ").append("Expires").append("=").append(HeaderUtil.formatDate(cookie.getExpires()));
}
if (cookie.getMaxAge() != null ) {
sb.append("; ").append("Max-Age").append("=").append(cookie.getMaxAge());
}
if (cookie.getPath() != null) {
sb.append("; ").append("Path").append("=").append(cookie.getPath());
}
if (cookie.getDomain() != null) {
sb.append("; ").append("Domain").append("=").append(cookie.getDomain());
}
if (cookie.isSecure() != null && cookie.isSecure()) {
sb.append("; ").append("Secure");
}
if (cookie.isHttpOnly() != null && cookie.isHttpOnly()) {
sb.append("; ").append("HttpOnly");
}
}
return sb.toString();
}
static class Factory extends HeaderFactory<SetCookieHeader> {
@Override
public SetCookieHeader parse(String value) {
return valueOf(value);
}
@Override
public SetCookieHeader parse(List<String> values) {
return valueOf(values);
}
}
}