Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public interface Cookie {
*
* @return 表示 Cookie 版本号的 {@code int}。
*/
@Deprecated
int version();

/**
Expand All @@ -43,6 +44,7 @@ public interface Cookie {
*
* @return 表示 Cookie 注释的 {@link String}。
*/
@Deprecated
String comment();

/**
Expand Down Expand Up @@ -79,12 +81,20 @@ public interface Cookie {

/**
* 判断 Cookie 是否仅允许在服务端获取。
* <p>该属性并不是 Cookie 的标准,但是被浏览器支持。</p>
* <p>其 HttpOnly 属性的格式为 {@code ;HttpOnly ...},如果存在则表示仅服务端可访问。</p>
*
* @return 如果 Cookie 仅允许在服务端获取,返回 {@code true},否则,返回 {@code false}。
* @return 如果 Cookie 仅允许在服务端访问,则返回 {@code true},否则返回 {@code false}。
*/
boolean httpOnly();

/**
* 获取 Cookie 的 SameSite 属性。
* <p>其 SameSite 属性的格式为 {@code ;SameSite=VALUE ...},表示跨站请求策略。</p>
*
* @return SameSite 值,如 {@code "Strict"}、{@code "Lax"}、{@code "None"}。
*/
String sameSite();

/**
* {@link Cookie} 的构建器。
*/
Expand All @@ -111,6 +121,7 @@ interface Builder {
* @param version 表示待设置的 Cookie 版本的 {@code int}。
* @return 表示当前构建器的 {@link Builder}。
*/
@Deprecated
Builder version(int version);

/**
Expand All @@ -119,6 +130,7 @@ interface Builder {
* @param comment 表示待设置的 Cookie 注释的 {@link String}。
* @return 表示当前构建器的 {@link Builder}。
*/
@Deprecated
Builder comment(String comment);

/**
Expand Down Expand Up @@ -161,6 +173,14 @@ interface Builder {
*/
Builder httpOnly(boolean httpOnly);

/**
* 向当前构建器中设置 Cookie 限制跨站请求时发送行为安全级别。
*
* @param sameSite SameSite 值,如 "Strict", "Lax", "None"。
* @return 表示当前构建器的 {@link Builder}。
*/
Builder sameSite(String sameSite);

/**
* 构建对象。
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import modelengine.fit.http.entity.ReadableBinaryEntity;
import modelengine.fit.http.entity.support.DefaultMultiValueEntity;
import modelengine.fit.http.entity.support.DefaultObjectEntity;
import modelengine.fit.http.header.ConfigurableCookieCollection;
import modelengine.fit.http.header.ContentType;
import modelengine.fit.http.protocol.ClientRequest;
import modelengine.fit.http.protocol.ClientResponse;
Expand Down Expand Up @@ -155,7 +156,7 @@ protected void commit() {
if (this.isCommitted()) {
return;
}
this.headers().set(COOKIE, this.cookies().toString());
this.headers().set(COOKIE, this.cookies().toRequestHeader());
super.commit();
}

Expand All @@ -170,4 +171,9 @@ private void close() {
// Ignore
}
}

@Override
public ConfigurableCookieCollection cookies() {
return (ConfigurableCookieCollection) super.cookies();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,23 @@
public interface CookieCollection extends HeaderValue {
/**
* 获取指定名字的 {@link Cookie}。
* <p>如果存在多个同名 Cookie,返回第一个匹配的 Cookie。</p>
*
* @param name 表示 Cookie 名字的 {@link Optional}{@code <}{@link String}{@code >}。
* @return 表示指定名字的 {@link Cookie}。
*/
Optional<Cookie> get(String name);

/**
* 获取所有的 {@link Cookie}。
* 根据名字查找所有匹配的 {@link Cookie}。
*
* @param name 表示 Cookie 名字的 {@link String}。
* @return 返回所有匹配名字的 {@link Cookie} 列表。
*/
List<Cookie> findByName(String name);

/**
* 获取集合中所有的 {@link Cookie}。
*
* @return 表示所有 {@link Cookie} 列表的 {@link List}{@code <}{@link Cookie}{@code >}。
*/
Expand All @@ -39,4 +48,20 @@ public interface CookieCollection extends HeaderValue {
* @return 表示所有 {@link Cookie} 的数量的 {@code int}。
*/
int size();

/**
* 将集合转换为 HTTP 请求头中 Cookie 形式的字符串。
* <p>格式为 {@code name1=value1; name2=value2; ...}。</p>
*
* @return 表示请求头的字符串。
*/
String toRequestHeader();

/**
* 将集合转换为 HTTP 响应头形式的字符串列表。
* <p>每个 Cookie 对应一个 {@code Set-Cookie: ...} 头。</p>
*
* @return 表示响应头列表的 {@link List}{@code <}{@link String}{@code >}。
*/
List<String> toResponseHeaders();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import static modelengine.fit.http.protocol.MessageHeaderNames.CONNECTION;
import static modelengine.fit.http.protocol.MessageHeaderNames.CONTENT_DISPOSITION;
import static modelengine.fit.http.protocol.MessageHeaderNames.CONTENT_LENGTH;
import static modelengine.fit.http.protocol.MessageHeaderNames.COOKIE;
import static modelengine.fit.http.protocol.MessageHeaderNames.SET_COOKIE;
import static modelengine.fit.http.protocol.MessageHeaderNames.TRANSFER_ENCODING;
import static modelengine.fit.http.protocol.MessageHeaderValues.CHUNKED;
import static modelengine.fit.http.protocol.MessageHeaderValues.KEEP_ALIVE;
Expand All @@ -26,6 +26,7 @@
import modelengine.fit.http.entity.TextEventStreamEntity;
import modelengine.fit.http.entity.WritableBinaryEntity;
import modelengine.fit.http.entity.support.DefaultWritableBinaryEntity;
import modelengine.fit.http.header.ConfigurableCookieCollection;
import modelengine.fit.http.header.ContentDisposition;
import modelengine.fit.http.header.ContentType;
import modelengine.fit.http.header.HeaderValue;
Expand Down Expand Up @@ -255,7 +256,7 @@ protected void commit() {
if (this.isCommitted()) {
return;
}
this.headers().set(COOKIE, this.cookies().toString());
this.headers().set(SET_COOKIE, this.cookies().toResponseHeaders());
if (this.entity != null) {
this.setContentTypeByEntity(this.headers(), this.entity);
if (this.entity instanceof FileEntity) {
Expand All @@ -280,4 +281,9 @@ private void close0() throws IOException {
this.entity = null;
}
}

@Override
public ConfigurableCookieCollection cookies() {
return (ConfigurableCookieCollection) super.cookies();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

package modelengine.fit.http.support;

import static modelengine.fit.http.protocol.MessageHeaderNames.COOKIE;
import static modelengine.fit.http.protocol.MessageHeaderNames.HOST;
import static modelengine.fitframework.inspection.Validation.notNull;

import modelengine.fit.http.HttpClassicRequest;
import modelengine.fit.http.HttpResource;
import modelengine.fit.http.header.ConfigurableCookieCollection;
import modelengine.fit.http.header.CookieCollection;
import modelengine.fit.http.header.HeaderValue;
import modelengine.fit.http.protocol.HttpRequestMethod;
import modelengine.fit.http.protocol.MessageHeaderNames;
import modelengine.fit.http.protocol.MessageHeaders;
Expand All @@ -24,8 +28,11 @@
* @since 2022-11-23
*/
public abstract class AbstractHttpClassicRequest extends AbstractHttpMessage implements HttpClassicRequest {
private static final String COOKIE_DELIMITER = ";";

private final RequestLine startLine;
private final MessageHeaders headers;
private final ConfigurableCookieCollection cookies;

/**
* 创建经典的 Http 请求对象。
Expand All @@ -38,6 +45,8 @@ public AbstractHttpClassicRequest(HttpResource httpResource, RequestLine startLi
super(httpResource, startLine, headers);
this.startLine = notNull(startLine, "The request line cannot be null.");
this.headers = notNull(headers, "The message headers cannot be null.");
String actualCookie = String.join(COOKIE_DELIMITER, this.headers.all(COOKIE));
this.cookies = ConfigurableCookieCollection.create(HeaderValue.create(actualCookie));
}

@Override
Expand Down Expand Up @@ -66,4 +75,9 @@ public String path() {
public QueryCollection queries() {
return this.startLine.queries();
}

@Override
public CookieCollection cookies() {
return this.cookies;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@

package modelengine.fit.http.support;

import static modelengine.fit.http.protocol.MessageHeaderNames.SET_COOKIE;
import static modelengine.fitframework.inspection.Validation.notNull;

import modelengine.fit.http.HttpClassicResponse;
import modelengine.fit.http.HttpResource;
import modelengine.fit.http.header.ConfigurableCookieCollection;
import modelengine.fit.http.header.CookieCollection;
import modelengine.fit.http.protocol.MessageHeaders;
import modelengine.fit.http.protocol.RequestLine;
import modelengine.fit.http.protocol.StatusLine;
import modelengine.fit.http.util.HttpUtils;

import java.util.List;

/**
* {@link HttpClassicResponse} 的默认实现。
Expand All @@ -22,6 +28,7 @@
*/
public abstract class AbstractHttpClassicResponse extends AbstractHttpMessage implements HttpClassicResponse {
private final StatusLine startLine;
private final ConfigurableCookieCollection cookies;

/**
* 创建经典的 Http 响应对象。
Expand All @@ -33,6 +40,10 @@ public abstract class AbstractHttpClassicResponse extends AbstractHttpMessage im
public AbstractHttpClassicResponse(HttpResource httpResource, StatusLine startLine, MessageHeaders headers) {
super(httpResource, startLine, headers);
this.startLine = notNull(startLine, "The status line cannot be null.");
MessageHeaders headers1 = notNull(headers, "The headers cannot be null.");
List<String> actualCookies = headers1.all(SET_COOKIE);
this.cookies = ConfigurableCookieCollection.create();
actualCookies.stream().map(HttpUtils::parseSetCookie).forEach(cookies::add);
}

@Override
Expand All @@ -44,4 +55,9 @@ public int statusCode() {
public String reasonPhrase() {
return this.startLine.reasonPhrase();
}

@Override
public CookieCollection cookies() {
return this.cookies;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,11 @@
* @since 2022-08-03
*/
public abstract class AbstractHttpMessage implements HttpMessage {
private static final String COOKIE_DELIMITER = ";";

private final ParameterCollection parameters =
ParameterCollection.create().set(DefaultContentType.CHARSET, StandardCharsets.UTF_8.name());
private final HttpResource httpResource;
private final StartLine startLine;
private final MessageHeaders headers;
private final ConfigurableCookieCollection cookies;
private final Map<MimeType, EntitySerializer<? extends Entity>> customEntitySerializers = new HashMap<>();
private ObjectSerializer customJsonSerializer;
private boolean isCommitted;
Expand All @@ -70,8 +67,6 @@ protected AbstractHttpMessage(HttpResource httpResource, StartLine startLine, Me
this.httpResource = notNull(httpResource, "The http resource cannot be null.");
this.startLine = notNull(startLine, "The start line cannot be null.");
this.headers = notNull(headers, "The message headers cannot be null.");
String actualCookie = String.join(COOKIE_DELIMITER, this.headers.all(COOKIE));
this.cookies = ConfigurableCookieCollection.create(HttpUtils.parseHeaderValue(actualCookie));
}

@Override
Expand Down Expand Up @@ -140,11 +135,6 @@ public int contentLength() {
return Integer.parseInt(value);
}

@Override
public ConfigurableCookieCollection cookies() {
return this.cookies;
}

/**
* 提交当前的 Http 消息。
* <p>提交之后的 Http 消息将无法修改。</p>
Expand Down
Loading