net.officefloor.server.http.WritableHttpCookie Maven / Gradle / Ivy
/*-
* #%L
* HTTP Server
* %%
* Copyright (C) 2005 - 2020 Daniel Sagenschneider
* %%
* Licensed 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.
* #L%
*/
package net.officefloor.server.http;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import net.officefloor.frame.api.managedobject.ManagedObjectContext;
import net.officefloor.server.stream.StreamBuffer;
import net.officefloor.server.stream.StreamBufferPool;
/**
* Writable HTTP Cookie.
*
* @author Daniel Sagenschneider
*/
public class WritableHttpCookie implements HttpResponseCookie {
/**
* Set-Cookie
{@link HttpHeaderName}.
*/
private static final HttpHeaderName SET_COOKIE = new HttpHeaderName("set-cookie");
/**
* : then space encoded bytes.
*/
private static final byte[] COLON_SPACE = ": ".getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* = encoded bytes.
*/
private static final byte[] EQUALS = "=".getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* Expires
prefix.
*/
private static final String EXPIRES_STRING = "; Expires=";
/**
* Expires
prefix bytes.
*/
private static final byte[] EXPIRES_BYTES = EXPIRES_STRING.getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* Expires {@link DateTimeFormatter}. Default {@link ZoneId} to allow
* {@link Instant#now()} (and derived {@link TemporalAccessor} instances) to be
* formatted.
*/
private static final DateTimeFormatter EXPIRE_FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME
.withZone(ZoneId.of("GMT"));
/**
* Max-Age
prefix.
*/
private static final String MAX_AGE_STRING = "; Max-Age=";
/**
* Max-Age
prefix bytes.
*/
private static final byte[] MAX_AGE_BYTES = MAX_AGE_STRING.getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* Domain
prefix.
*/
private static final String DOMAIN_STRING = "; Domain=";
/**
* Domain
prefix bytes.
*/
private static final byte[] DOMAIN_BYTES = DOMAIN_STRING.getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* Path
prefix.
*/
private static final String PATH_STRING = "; Path=";
/**
* Path
prefix bytes.
*/
private static final byte[] PATH_BYTES = PATH_STRING.getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* Secure.
*/
private static final String SECURE_STRING = "; Secure";
/**
* Secure
bytes.
*/
private static final byte[] SECURE_BYTES = SECURE_STRING.getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* HttpOnly
.
*/
private static final String HTTP_ONLY_STRING = "; HttpOnly";
/**
* HttpOnly
bytes.
*/
private static final byte[] HTTP_ONLY_BYTES = HTTP_ONLY_STRING.getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* Extension attribute.
*/
private static final String EXTENSION_STRING = "; ";
/**
* Extension attribute prefix.
*/
private static final byte[] EXTENSION_BYTES = EXTENSION_STRING.getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* {@link HttpHeader} end of line encoded bytes.
*/
private static final byte[] HEADER_EOLN = "\r\n".getBytes(ServerHttpConnection.HTTP_CHARSET);
/**
* No extensions.
*/
private static final String[] NO_EXTENSIONS = new String[0];
/**
* Cached {@link StringBuilder} to reduce object creation, when creating
* {@link HttpHeader} value.
*/
private static final ThreadLocal stringBuilder = new ThreadLocal() {
@Override
protected StringBuilder initialValue() {
return new StringBuilder(256);
}
};
/**
* Next {@link WritableHttpCookie} to enable chaining together into linked list.
*/
public WritableHttpCookie next = null;
/**
* Name.
*/
private final String name;
/**
* Value.
*/
private String value;
/**
* {@link ManagedObjectContext}.
*/
private final ManagedObjectContext context;
/**
* Expires.
*/
private TemporalAccessor expires = null;
/**
* Max age.
*/
private long maxAge = BROWSER_SESSION_MAX_AGE;
/**
* Domain.
*/
private String domain = null;
/**
* Path.
*/
private String path = null;
/**
* Indicates if secure.
*/
private boolean isSecure = false;
/**
* Indicates if HTTP only.
*/
private boolean isHttpOnly = false;
/**
* Extensions.
*/
private List extensions = null;
/**
* Instantiate.
*
* @param name Name.
* @param value Value.
* @param context {@link ManagedObjectContext}.
*/
public WritableHttpCookie(String name, String value, ManagedObjectContext context) {
this.name = name;
this.value = value;
this.context = context;
}
/**
* Writes this HTTP Cookie to the {@link StreamBuffer} stream.
*
* @param Buffer type.
* @param head Head {@link StreamBuffer} of linked list of
* {@link StreamBuffer} instances.
* @param bufferPool {@link StreamBufferPool}.
*/
public void write(StreamBuffer head, StreamBufferPool bufferPool) {
SET_COOKIE.write(head, bufferPool);
StreamBuffer.write(COLON_SPACE, head, bufferPool);
StreamBuffer.write(this.name, head, bufferPool);
StreamBuffer.write(EQUALS, head, bufferPool);
StreamBuffer.write(this.value, head, bufferPool);
if (this.expires != null) {
StreamBuffer.write(EXPIRES_BYTES, head, bufferPool);
EXPIRE_FORMATTER.formatTo(this.expires, StreamBuffer.getAppendable(head, bufferPool));
}
if (this.maxAge != BROWSER_SESSION_MAX_AGE) {
StreamBuffer.write(MAX_AGE_BYTES, head, bufferPool);
StreamBuffer.write(this.maxAge, head, bufferPool);
}
if (this.domain != null) {
StreamBuffer.write(DOMAIN_BYTES, head, bufferPool);
StreamBuffer.write(this.domain, head, bufferPool);
}
if (this.path != null) {
StreamBuffer.write(PATH_BYTES, head, bufferPool);
StreamBuffer.write(this.path, head, bufferPool);
}
if (this.isSecure) {
StreamBuffer.write(SECURE_BYTES, head, bufferPool);
}
if (this.isHttpOnly) {
StreamBuffer.write(HTTP_ONLY_BYTES, head, bufferPool);
}
if (this.extensions != null) {
for (String extension : this.extensions) {
StreamBuffer.write(EXTENSION_BYTES, head, bufferPool);
StreamBuffer.write(extension, head, bufferPool);
}
}
StreamBuffer.write(HEADER_EOLN, head, bufferPool);
}
/**
* Obtains the HTTP Cookie value for the HTTP response.
*
* @return HTTP header value.
*/
public String toResponseHeaderValue() {
StringBuilder value = stringBuilder.get();
value.setLength(0); // clear
value.append(this.name);
value.append("=");
value.append(this.value);
if (this.expires != null) {
value.append(EXPIRES_STRING);
EXPIRE_FORMATTER.formatTo(this.expires, value);
}
if (this.maxAge != BROWSER_SESSION_MAX_AGE) {
value.append(MAX_AGE_STRING);
value.append(this.maxAge);
}
if (this.domain != null) {
value.append(DOMAIN_STRING);
value.append(this.domain);
}
if (this.path != null) {
value.append(PATH_STRING);
value.append(this.path);
}
if (this.isSecure) {
value.append(SECURE_STRING);
}
if (this.isHttpOnly) {
value.append(HTTP_ONLY_STRING);
}
if (this.extensions != null) {
for (String extension : this.extensions) {
value.append(EXTENSION_STRING);
value.append(extension);
}
}
return value.toString();
}
/*
* ==================== HttpResponseCookie =====================
*/
@Override
public String getName() {
return this.name;
}
@Override
public String getValue() {
return this.context.run(() -> this.value);
}
@Override
public HttpResponseCookie setValue(String value) {
return this.context.run(() -> {
this.value = value;
return this;
});
}
@Override
public TemporalAccessor getExpires() {
return this.context.run(() -> this.expires);
}
@Override
public HttpResponseCookie setExpires(TemporalAccessor expires) {
return this.context.run(() -> {
this.expires = expires;
return this;
});
}
@Override
public long getMaxAge() {
return this.context.run(() -> this.maxAge);
}
@Override
public HttpResponseCookie setMaxAge(long maxAge) {
return this.context.run(() -> {
this.maxAge = maxAge;
return this;
});
}
@Override
public String getDomain() {
return this.context.run(() -> this.domain);
}
@Override
public HttpResponseCookie setDomain(String domain) {
return this.context.run(() -> {
this.domain = domain;
return this;
});
}
@Override
public String getPath() {
return this.context.run(() -> this.path);
}
@Override
public HttpResponseCookie setPath(String path) {
return this.context.run(() -> {
this.path = path;
return this;
});
}
@Override
public boolean isSecure() {
return this.context.run(() -> this.isSecure);
}
@Override
public HttpResponseCookie setSecure(boolean isSecure) {
return this.context.run(() -> {
this.isSecure = isSecure;
return this;
});
}
@Override
public boolean isHttpOnly() {
return this.context.run(() -> this.isHttpOnly);
}
@Override
public HttpResponseCookie setHttpOnly(boolean isHttpOnly) {
return this.context.run(() -> {
this.isHttpOnly = isHttpOnly;
return this;
});
}
@Override
public HttpResponseCookie addExtension(String extension) {
return this.context.run(() -> {
// Lazy create the extension list
if (this.extensions == null) {
this.extensions = new ArrayList<>(1);
}
// Add the extension
this.extensions.add(extension);
// Return
return this;
});
}
@Override
public String[] getExtensions() {
return this.context.run(() -> this.extensions == null ? NO_EXTENSIONS
: this.extensions.toArray(new String[this.extensions.size()]));
}
@Override
public HttpResponseCookie clearAttributes() {
return this.context.run(() -> {
this.expires = null;
this.maxAge = BROWSER_SESSION_MAX_AGE;
this.domain = null;
this.path = null;
this.isSecure = false;
this.isHttpOnly = false;
this.extensions = null;
return this;
});
}
@Override
public HttpResponseCookie configure(Consumer configurer) {
return this.context.run(() -> {
configurer.accept(this);
return this;
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy