Introduce 1.0.1-BETA packet model with 1.0.0-BETA backwards compatibility

This commit is contained in:
UnlegitDqrk
2026-02-21 23:12:43 +01:00
parent 0841992363
commit a7ce9982c9
40 changed files with 2228 additions and 213 deletions

View File

@@ -12,14 +12,19 @@ import java.util.List;
*/
public enum ProtocolVersion implements Serializable {
/**
* Support for old OAC-Project => <a href="https://repo.open-autonomous-connection.org/Open-Autonomous-Connection/">*_old</a>
* For classic OAC-Project => <a href="https://repo.open-autonomous-connection.org/Open-Autonomous-Connection/">"classic"-branch</a>
*/
@Deprecated(forRemoval = false, since = "1.0.1-BETA.0.1")
PV_1_0_0_CLASSIC("1.0.0", ProtocolType.CLASSIC, ProtocolSide.WEB_INS, List.of(Protocol.HTTP)),
/**
* First Beta Version of OAC-Protocol
* Version {@link ProtocolVersion#PV_1_0_0_BETA} has many bugs and does not work as expected (occurred by incompleted packets).
* Use {@link ProtocolVersion#PV_1_0_1_BETA} or newer.
*/
PV_1_0_0_BETA("1.0.0", ProtocolType.BETA, ProtocolSide.ALL, List.of(Protocol.OAC), PV_1_0_0_CLASSIC),
@Deprecated(forRemoval = false, since = "1.0.1-BETA.0.1")
PV_1_0_0_BETA("1.0.0", ProtocolType.BETA, ProtocolSide.ALL, List.of(Protocol.OAC)),
PV_1_0_1_BETA("1.0.1", ProtocolType.BETA, ProtocolSide.ALL, List.of(Protocol.OAC), PV_1_0_0_BETA),
;
/**

View File

@@ -149,9 +149,7 @@ public final class INSRecordTools {
return record.ttl >= 0;
}
// -------------------------------------------------------------------------
// Validation helpers
// -------------------------------------------------------------------------
/**
* Validates a collection of records by applying {@link #isValidRecord(INSRecord)}

View File

@@ -0,0 +1,133 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.beta;
import dev.unlegitdqrk.unlegitlibrary.file.FileUtils;
import dev.unlegitdqrk.unlegitlibrary.string.RandomString;
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket;
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
import org.openautonomousconnection.protocol.side.server.ProtocolCustomServer;
import org.openautonomousconnection.protocol.side.web.managers.AuthManager;
import org.openautonomousconnection.protocol.side.web.managers.RuleManager;
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
import java.io.File;
import java.util.Random;
/**
* Represents the web server for the protocol.
*/
@Deprecated(forRemoval = false, since = "1.0.1-BETA.0.1")
@ProtocolInfo(protocolSide = ProtocolVersion.ProtocolSide.WEB)
public abstract class ProtocolWebServer_1_0_0_B extends ProtocolCustomServer {
/**
* Folder for web content.
*/
private final File contentFolder;
/**
* Folder for error pages.
*/
private final File errorsFolder;
/**
* A unique secret for session management.
*/
private final String uniqueSessionString;
/**
* The expiration time of a Session in minutes
*/
private final int sessionExpire;
/**
* The max upload size in MB
*/
private final int maxUploadSize;
/**
* Initializes the web server with the given configuration, authentication, and rules files.
*
* @param authFile The authentication file.
* @param rulesFile The rules file.
* @param sessionExpire The expiration time of a Session in minutes
* @param uploadSize The max upload size in MB
* @throws Exception If an error occurs during initialization.
*/
public ProtocolWebServer_1_0_0_B(File authFile, File rulesFile, int sessionExpire, int uploadSize) throws Exception {
super("server", "server");
this.sessionExpire = sessionExpire;
this.maxUploadSize = uploadSize;
// Set up content and error folders
contentFolder = new File("content");
errorsFolder = new File("errors");
// Create folders if they don't exist
if (!contentFolder.exists()) contentFolder.mkdir();
if (!errorsFolder.exists()) errorsFolder.mkdir();
// Create auth and rules files with default content if they don't exist
if (!authFile.exists()) {
authFile.createNewFile();
FileUtils.writeFile(authFile, """
admin:5e884898da28047151d0e56f8dc6292773603d0d6aabbddab8f91d8e5f99f6c7
user:e99a18c428cb38d5f260853678922e03abd8335f
""");
}
// Create default rules file if it doesn't exist
if (!rulesFile.exists()) {
rulesFile.createNewFile();
FileUtils.writeFile(rulesFile, """
{
"allow": [
"index.html",
"css/*",
"private/info.php"
],
"deny": [
"private/*"
],
"auth": [
"private/*",
"admin/*"
]
}
""");
}
// Load authentication and rules
uniqueSessionString = AuthManager.sha256(new RandomString(new Random(System.currentTimeMillis()).nextInt(10, 20)).nextString());
AuthManager.loadAuthFile(authFile);
RuleManager.loadRules(rulesFile);
}
public final File getContentFolder() {
return contentFolder;
}
public final File getErrorsFolder() {
return errorsFolder;
}
public final String getUniqueSessionString() {
return uniqueSessionString;
}
public final int getSessionExpire() {
return sessionExpire;
}
public final int getMaxUploadSize() {
return maxUploadSize;
}
/**
* Called when the server receives a WebRequestPacket from the client.
*
* @param client The connected web client (pipeline + web socket).
* @param request The full decoded request packet.
* @return The response packet that should be sent back to the client.
*/
@Deprecated(forRemoval = false, since = "1.0.1-BETA.0.1")
public abstract WebResponsePacket onWebRequest(CustomConnectedClient client, WebRequestPacket request);
}

View File

@@ -1,5 +1,5 @@
package org.openautonomousconnection.protocol.versions.v1_0_0.beta;
public enum WebRequestMethod {
GET, POST
GET, POST, EXECUTE, SCRIPT
}

View File

@@ -5,7 +5,7 @@ import java.io.Serializable;
/**
* Enum representing the protocol versions for the Classic protocol.
*/
@Deprecated(forRemoval = false, since = "1.0.0-BETA.3")
@Deprecated(forRemoval = true, since = "1.0.1-BETA.0.1")
public enum Classic_ProtocolVersion implements Serializable {
PV_1_0_0("1.0.0");
public final String version;

View File

@@ -0,0 +1,10 @@
package org.openautonomousconnection.protocol.versions.v1_0_1.beta;
/**
* Cache behavior for navigation/resource requests.
*/
public enum WebCacheMode {
DEFAULT,
BYPASS,
ONLY_CACHE
}

View File

@@ -0,0 +1,250 @@
package org.openautonomousconnection.protocol.versions.v1_0_1.beta;
import java.security.SecureRandom;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
/**
* Factory for creating {@link WebPacketHeader} instances with stable tab/page identifiers and
* monotonic request identifiers.
*
* <p>This class is intended to be used by the WebClient/WebServer integration layer to ensure
* every packet carries a valid header and consistent correlation metadata.</p>
*
* <p>Thread-safety:
* <ul>
* <li>Request id generation is thread-safe.</li>
* <li>Tab/page allocation methods are thread-safe.</li>
* <li>{@link WebTabContext} is thread-safe for reads; writes are synchronized.</li>
* </ul>
* </p>
*/
public final class WebHeaderFactory {
private static final long MIN_ID = 1L;
private final AtomicLong requestIdSeq;
private final AtomicLong tabIdSeq;
private final AtomicLong pageIdSeq;
/**
* Creates a factory with randomized id bases to reduce collisions across process restarts.
*/
public WebHeaderFactory() {
SecureRandom rnd = new SecureRandom();
this.requestIdSeq = new AtomicLong(Math.max(MIN_ID, rnd.nextLong() & Long.MAX_VALUE));
this.tabIdSeq = new AtomicLong(Math.max(MIN_ID, rnd.nextLong() & Long.MAX_VALUE));
this.pageIdSeq = new AtomicLong(Math.max(MIN_ID, rnd.nextLong() & Long.MAX_VALUE));
}
/**
* Creates a new tab context with a fresh tab id and an initial page id.
*
* @return new tab context
*/
public WebTabContext createTab() {
long tabId = nextTabId();
long pageId = nextPageId();
return new WebTabContext(tabId, pageId);
}
/**
* Starts a new navigation by allocating a new page id for the given tab context.
*
* <p>Call this when navigation is initiated (typed URL, link click, reload, back/forward).</p>
*
* @param tab tab context
* @return the new page id
*/
public long beginNavigation(WebTabContext tab) {
Objects.requireNonNull(tab, "tab");
long newPageId = nextPageId();
tab.setPageId(newPageId);
return newPageId;
}
/**
* Creates a header for a navigation request.
*
* @param tab tab context
* @param noStore if true, sets {@link WebPacketFlags#NO_STORE}
* @return header
*/
public WebPacketHeader navigation(WebTabContext tab, boolean noStore) {
Objects.requireNonNull(tab, "tab");
int flags = WebPacketFlags.NAVIGATION;
if (noStore) flags |= WebPacketFlags.NO_STORE;
return header(nextRequestId(), tab.getTabId(), tab.getPageId(), 0L, flags);
}
/**
* Creates a header for a resource request.
*
* @param tab tab context
* @param frameId frame id (0 = main)
* @param noStore if true, sets {@link WebPacketFlags#NO_STORE}
* @return header
*/
public WebPacketHeader resource(WebTabContext tab, long frameId, boolean noStore) {
Objects.requireNonNull(tab, "tab");
int flags = WebPacketFlags.RESOURCE;
if (noStore) flags |= WebPacketFlags.NO_STORE;
return header(nextRequestId(), tab.getTabId(), tab.getPageId(), frameId, flags);
}
/**
* Creates a header for a resource response correlated to a request id.
*
* @param requestId request id to correlate
* @param tabId tab id
* @param pageId page id
* @param frameId frame id
* @return header
*/
public WebPacketHeader resourceResponse(long requestId, long tabId, long pageId, long frameId) {
return header(requestId, tabId, pageId, frameId, WebPacketFlags.RESOURCE);
}
/**
* Creates a header for a streamed payload associated with a request id.
*
* @param requestId correlated request id
* @param tabId tab id
* @param pageId page id
* @param frameId frame id
* @return header
*/
public WebPacketHeader stream(long requestId, long tabId, long pageId, long frameId) {
return header(requestId, tabId, pageId, frameId, WebPacketFlags.STREAM);
}
/**
* Creates an event header (server->client or client->server).
*
* @param tabId tab id
* @param pageId page id
* @param frameId frame id
* @return header
*/
public WebPacketHeader event(long tabId, long pageId, long frameId) {
return header(nextRequestId(), tabId, pageId, frameId, WebPacketFlags.EVENT);
}
/**
* Creates an event header correlated to an existing request id.
*
* @param requestId request id
* @param tabId tab id
* @param pageId page id
* @param frameId frame id
* @return header
*/
public WebPacketHeader correlatedEvent(long requestId, long tabId, long pageId, long frameId) {
return header(requestId, tabId, pageId, frameId, WebPacketFlags.EVENT);
}
/**
* Creates a header for a document snapshot event.
*
* @param tab tab context
* @param frameId frame id
* @return header
*/
public WebPacketHeader documentSnapshotEvent(WebTabContext tab, long frameId) {
Objects.requireNonNull(tab, "tab");
return header(nextRequestId(), tab.getTabId(), tab.getPageId(), frameId, WebPacketFlags.EVENT);
}
/**
* Creates a header for a document apply request.
*
* @param tab tab context
* @param frameId frame id
* @return header
*/
public WebPacketHeader documentApply(WebTabContext tab, long frameId) {
Objects.requireNonNull(tab, "tab");
return header(nextRequestId(), tab.getTabId(), tab.getPageId(), frameId, WebPacketFlags.RESOURCE);
}
/**
* Checks whether an incoming packet is stale for a given tab context.
*
* <p>Stale means: the packet refers to an older pageId than the current tab pageId.</p>
*
* @param tab tab context
* @param incoming incoming header
* @return true if stale, false otherwise
*/
public boolean isStale(WebTabContext tab, WebPacketHeader incoming) {
Objects.requireNonNull(tab, "tab");
Objects.requireNonNull(incoming, "incoming");
return incoming.getTabId() == tab.getTabId() && incoming.getPageId() != tab.getPageId();
}
private WebPacketHeader header(long requestId, long tabId, long pageId, long frameId, int flags) {
long ts = System.currentTimeMillis();
return new WebPacketHeader(requestId, tabId, pageId, frameId, flags, ts);
}
private long nextRequestId() {
long v = requestIdSeq.incrementAndGet();
return (v < MIN_ID) ? MIN_ID : v;
}
private long nextTabId() {
long v = tabIdSeq.incrementAndGet();
return (v < MIN_ID) ? MIN_ID : v;
}
private long nextPageId() {
long v = pageIdSeq.incrementAndGet();
return (v < MIN_ID) ? MIN_ID : v;
}
/**
* Represents per-tab state used for header creation and stale detection.
*/
public static final class WebTabContext {
private final long tabId;
private volatile long pageId;
/**
* Creates a tab context.
*
* @param tabId tab id
* @param pageId initial page id
*/
public WebTabContext(long tabId, long pageId) {
if (tabId < MIN_ID) throw new IllegalArgumentException("tabId must be >= 1");
if (pageId < MIN_ID) throw new IllegalArgumentException("pageId must be >= 1");
this.tabId = tabId;
this.pageId = pageId;
}
/**
* @return stable tab id
*/
public long getTabId() {
return tabId;
}
/**
* @return current page id
*/
public long getPageId() {
return pageId;
}
/**
* Sets the current page id.
*
* @param pageId new page id
*/
public synchronized void setPageId(long pageId) {
if (pageId < MIN_ID) throw new IllegalArgumentException("pageId must be >= 1");
this.pageId = pageId;
}
}
}

View File

@@ -0,0 +1,16 @@
package org.openautonomousconnection.protocol.versions.v1_0_1.beta;
/**
* Identifies the initiator of a resource request.
*/
public enum WebInitiatorType {
DOCUMENT,
SCRIPT,
STYLE,
IMAGE,
MEDIA,
FONT,
XHR,
FETCH,
OTHER
}

View File

@@ -0,0 +1,46 @@
package org.openautonomousconnection.protocol.versions.v1_0_1.beta;
/**
* Bitset flags used in WebPacketHeader.
*/
public final class WebPacketFlags {
/**
* Packet describes a top-level navigation action.
*/
public static final int NAVIGATION = 1 << 0;
/**
* Packet describes a resource request/response.
*/
public static final int RESOURCE = 1 << 1;
/**
* Packet is part of a streamed body transfer.
*/
public static final int STREAM = 1 << 2;
/**
* Packet is devtools-related.
*/
public static final int DEVTOOLS = 1 << 3;
/**
* Packet is an event (server->client / client->server).
*/
public static final int EVENT = 1 << 4;
/**
* Disable caching / do not store.
*/
public static final int NO_STORE = 1 << 5;
private WebPacketFlags() {
}
/**
* Checks if a flag is present.
*
* @param flags bitset
* @param flag flag constant
* @return true if present
*/
public static boolean has(int flags, int flag) {
return (flags & flag) == flag;
}
}

View File

@@ -0,0 +1,81 @@
package org.openautonomousconnection.protocol.versions.v1_0_1.beta;
import lombok.Getter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Shared header for all Web v1.0.1-BETA packets.
*
* <p>This header MUST be written/read first in every web packet.</p>
*/
@Getter
public final class WebPacketHeader {
private long requestId;
private long tabId;
private long pageId;
private long frameId;
private int flags;
private long timestampMs;
/**
* Empty constructor for decoding.
*/
public WebPacketHeader() {
}
/**
* Creates a new web header.
*
* @param requestId correlation id (request/response/stream/events)
* @param tabId stable tab id
* @param pageId navigation instance id
* @param frameId frame id (0 = main frame)
* @param flags bitset flags
* @param timestampMs unix epoch millis (0 allowed)
*/
public WebPacketHeader(long requestId, long tabId, long pageId, long frameId, int flags, long timestampMs) {
this.requestId = requestId;
this.tabId = tabId;
this.pageId = pageId;
this.frameId = frameId;
this.flags = flags;
this.timestampMs = timestampMs;
}
/**
* Reads a header from the stream.
*
* @param in stream
* @return decoded header
* @throws IOException on IO error
*/
public static WebPacketHeader read(DataInputStream in) throws IOException {
WebPacketHeader h = new WebPacketHeader();
h.requestId = in.readLong();
h.tabId = in.readLong();
h.pageId = in.readLong();
h.frameId = in.readLong();
h.flags = in.readInt();
h.timestampMs = in.readLong();
return h;
}
/**
* Writes the header to the stream.
*
* @param out stream
* @throws IOException on IO error
*/
public void write(DataOutputStream out) throws IOException {
out.writeLong(requestId);
out.writeLong(tabId);
out.writeLong(pageId);
out.writeLong(frameId);
out.writeInt(flags);
out.writeLong(timestampMs);
}
}

View File

@@ -0,0 +1,12 @@
package org.openautonomousconnection.protocol.versions.v1_0_1.beta;
/**
* Describes how a navigation was triggered.
*/
public enum WebTransitionType {
LINK,
TYPED,
RELOAD,
BACK_FORWARD
}

View File

@@ -0,0 +1,281 @@
package org.openautonomousconnection.protocol.versions.v1_0_1.beta.compat;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.stream.WebStreamChunkPacket_v1_0_0_B;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.stream.WebStreamEndPacket_v1_0_0_B;
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.stream.WebStreamStartPacket_v1_0_0_B;
import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.resource.WebResourceRequestPacket;
import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.resource.WebResourceResponsePacket;
import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.stream.WebStreamChunkPacket_v1_0_1_B;
import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.stream.WebStreamEndPacket_v1_0_1_B;
import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.stream.WebStreamStartPacket_v1_0_1_B;
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.WebRequestMethod;
import org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebCacheMode;
import org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebInitiatorType;
import org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketFlags;
import org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketHeader;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
/**
* Compatibility mapper between Web protocol v1.0.0
* and Web protocol v1.0.1 (beta).
*
* <p>This class provides pure mapping logic and contains no networking code.</p>
*
* <p>Usage:
* <ul>
* <li>Server-side: map 1.0.0 {@link WebRequestPacket} to {@link WebResourceRequestPacket}</li>
* <li>Server-side: map {@link WebResourceResponsePacket} back to {@link WebResponsePacket}</li>
* <li>Client-side: map 1.0.0 responses/streams to v1.0.1 packets so v1.0.1 hooks can be reused</li>
* </ul>
* </p>
*/
public final class WebCompatMapper {
/**
* Synthetic request id generator for 1.0.0 requests.
*/
private static final AtomicLong COMPAT_REQUEST_ID = new AtomicLong(1L);
private WebCompatMapper() {
}
/**
* Generates a monotonic synthetic request id.
*
* @return next request id
*/
public static long nextCompatRequestId() {
return COMPAT_REQUEST_ID.getAndIncrement();
}
/**
* Maps a v1.0.0 {@link WebRequestPacket} to a v1.0.1 {@link WebResourceRequestPacket}.
*
* <p>Because v1.0.0 has no tab/page/frame/request correlation model,
* synthetic identifiers must be provided.</p>
*
* @param requestId synthetic request id
* @param tabId synthetic tab id
* @param pageId synthetic page id
* @param requestPacket 1.0.0 request
* @return mapped v1.0.1 resource request
*/
public static WebResourceRequestPacket toResourceRequest(
long requestId,
long tabId,
long pageId,
WebRequestPacket requestPacket
) {
Objects.requireNonNull(requestPacket, "requestPacket");
String path = requestPacket.getPath();
String method = mapMethod(requestPacket.getMethod());
Map<String, String> headers = requestPacket.getHeaders() != null ? requestPacket.getHeaders() : Collections.emptyMap();
byte[] body = requestPacket.getBody() != null ? requestPacket.getBody() : new byte[0];
WebPacketHeader header = new WebPacketHeader(
requestId,
tabId,
pageId,
0L,
WebPacketFlags.RESOURCE,
System.currentTimeMillis()
);
return new WebResourceRequestPacket(
header,
path,
method,
headers,
body,
null,
WebInitiatorType.OTHER,
WebCacheMode.DEFAULT
);
}
/**
* Maps a v1.0.1 {@link WebResourceResponsePacket} back to a 1.0.0 {@link WebResponsePacket}.
*
* <p>Correlation information is lost because v1.0.0 does not support it.</p>
*
* @param response v1.0.1 resource response
* @return 1.0.0 response packet
*/
public static WebResponsePacket to100BResponse(WebResourceResponsePacket response) {
Objects.requireNonNull(response, "response");
return new WebResponsePacket(
response.getStatusCode(),
response.getContentType(),
response.getHeaders(),
response.getBody()
);
}
/**
* Maps v1.0.1 resource response to 1.0.0 response with overridden body.
*
* <p>Useful when buffering streamed responses for 1.0.0 clients.</p>
*
* @param response original v1.0.1 response
* @param body buffered full body
* @return 1.0.0 response
*/
public static WebResponsePacket to100BResponse(WebResourceResponsePacket response, byte[] body) {
Objects.requireNonNull(response, "response");
return new WebResponsePacket(
response.getStatusCode(),
response.getContentType(),
response.getHeaders(),
body != null ? body : new byte[0]
);
}
/**
* Maps a v1.0.0 {@link WebResponsePacket} to a v1.0.1 {@link WebResourceResponsePacket}
* using the provided synthetic correlation header.
*
* @param correlationHeader synthetic correlation header (requestId/tabId/pageId/frameId)
* @param responsePacket 1.0.0 response packet
* @return v1.0.1 resource response packet
*/
public static WebResourceResponsePacket toV101ResourceResponse(WebPacketHeader correlationHeader, WebResponsePacket responsePacket) {
Objects.requireNonNull(correlationHeader, "correlationHeader");
Objects.requireNonNull(responsePacket, "responsePacket");
WebPacketHeader header = mirrorCorrelation(correlationHeader, WebPacketFlags.RESOURCE);
return new WebResourceResponsePacket(
header,
responsePacket.getStatusCode(),
responsePacket.getContentType(),
responsePacket.getHeaders(),
responsePacket.getBody(),
null
);
}
/**
* Maps a v1.0.0 {@link WebStreamStartPacket_v1_0_0_B} to a v1.0.1 {@link WebStreamStartPacket_v1_0_1_B}
* using the provided synthetic correlation header.
*
* @param correlationHeader synthetic correlation header
* @param streamPacket 1.0.0 stream start
* @return v1.0.1 stream start
*/
public static WebStreamStartPacket_v1_0_1_B toV101StreamStart(WebPacketHeader correlationHeader, WebStreamStartPacket_v1_0_0_B streamPacket) {
Objects.requireNonNull(correlationHeader, "correlationHeader");
Objects.requireNonNull(streamPacket, "streamPacket");
WebPacketHeader header = mirrorCorrelation(correlationHeader, WebPacketFlags.RESOURCE);
return new WebStreamStartPacket_v1_0_1_B(
header,
streamPacket.getStatusCode(),
streamPacket.getContentType(),
streamPacket.getHeaders(),
streamPacket.getTotalLength()
);
}
/**
* Maps a v1.0.0 {@link WebStreamChunkPacket_v1_0_0_B} to a v1.0.1 {@link WebStreamChunkPacket_v1_0_1_B}
* using the provided synthetic correlation header.
*
* @param correlationHeader synthetic correlation header
* @param streamPacket 1.0.0 stream chunk
* @return v1.0.1 stream chunk
*/
public static WebStreamChunkPacket_v1_0_1_B toV101StreamChunk(WebPacketHeader correlationHeader, WebStreamChunkPacket_v1_0_0_B streamPacket) {
Objects.requireNonNull(correlationHeader, "correlationHeader");
Objects.requireNonNull(streamPacket, "streamPacket");
WebPacketHeader header = mirrorCorrelation(correlationHeader, WebPacketFlags.RESOURCE);
return new WebStreamChunkPacket_v1_0_1_B(
header,
streamPacket.getSeq(),
streamPacket.getData()
);
}
/**
* Maps a v1.0.0 {@link WebStreamEndPacket_v1_0_0_B} to a v1.0.1 {@link WebStreamEndPacket_v1_0_1_B}
* using the provided synthetic correlation header.
*
* @param correlationHeader synthetic correlation header
* @param streamPacket v1.0.0 stream end packet
* @return v1.0.1 stream end packet
*/
public static WebStreamEndPacket_v1_0_1_B toV101StreamEnd(
WebPacketHeader correlationHeader,
WebStreamEndPacket_v1_0_0_B streamPacket
) {
Objects.requireNonNull(correlationHeader, "correlationHeader");
Objects.requireNonNull(streamPacket, "streamPacket");
WebPacketHeader header = mirrorCorrelation(correlationHeader, WebPacketFlags.RESOURCE);
// v1.0.0 has no error string -> null
return new WebStreamEndPacket_v1_0_1_B(
header,
streamPacket.isOk(),
null
);
}
/**
* Creates a header that mirrors correlation fields from the provided header and updates timestamp/flags.
*
* @param correlationHeader correlation header to mirror
* @param extraFlags flags to OR
* @return mirrored header
*/
public static WebPacketHeader mirrorCorrelation(WebPacketHeader correlationHeader, int extraFlags) {
Objects.requireNonNull(correlationHeader, "correlationHeader");
return new WebPacketHeader(
correlationHeader.getRequestId(),
correlationHeader.getTabId(),
correlationHeader.getPageId(),
correlationHeader.getFrameId(),
correlationHeader.getFlags() | extraFlags,
System.currentTimeMillis()
);
}
/**
* Maps 1.0.0 {@link WebRequestMethod}.
*
* @param method 1.0.0 method
* @return method string
*/
public static String mapMethod(WebRequestMethod method) {
if (method == null) return "GET";
return switch (method) {
case GET -> "GET";
case POST, EXECUTE, SCRIPT -> "POST";
};
}
/**
* Maps 1.0.1 to 1.0.0 {@link WebRequestMethod}.
*
* @param method 1.0.0 method
* @return method string
*/
public static WebRequestMethod map100BMethod(String method) {
if (method == null) return WebRequestMethod.GET;
return switch (method.toUpperCase()) {
case "POST" -> WebRequestMethod.POST;
default -> WebRequestMethod.GET;
};
}
}