diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2783673a13..df574bbbd8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,25 @@
## [Unreleased](https://github.com/aklivity/zilla/tree/HEAD)
-[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.99...HEAD)
+[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.100...HEAD)
+
+**Fixed bugs:**
+
+- Running emqtt\_bench triggers exception in KafkaCacheCursorFactory [\#752](https://github.com/aklivity/zilla/issues/752)
+
+**Closed issues:**
+
+- Support `ALTER STREAM` and `ALTER TABLE` transformation [\#1319](https://github.com/aklivity/zilla/issues/1319)
+
+**Merged pull requests:**
+
+- Support instrumentation via Java agent [\#1321](https://github.com/aklivity/zilla/pull/1321) ([jfallows](https://github.com/jfallows))
+- `number` -\> `integer` for `max-age` attribute [\#1316](https://github.com/aklivity/zilla/pull/1316) ([ankitk-me](https://github.com/ankitk-me))
+- support file write in binding-filesystem & binding-http-filesystem [\#1300](https://github.com/aklivity/zilla/pull/1300) ([ankitk-me](https://github.com/ankitk-me))
+
+## [0.9.100](https://github.com/aklivity/zilla/tree/0.9.100) (2024-10-29)
+
+[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.99...0.9.100)
**Implemented enhancements:**
@@ -1768,7 +1786,6 @@
**Implemented enhancements:**
-- Feature request: Reqeust limiter [\#86](https://github.com/aklivity/zilla/issues/86)
- Configurable isolation level for kafka binding [\#85](https://github.com/aklivity/zilla/issues/85)
- Configurable acknowledgement mode for kafka binding [\#84](https://github.com/aklivity/zilla/issues/84)
diff --git a/build/flyweight-maven-plugin/pom.xml b/build/flyweight-maven-plugin/pom.xml
index 4f4600dbd9..33e6ee3ae4 100644
--- a/build/flyweight-maven-plugin/pom.xml
+++ b/build/flyweight-maven-plugin/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
build
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/build/pom.xml b/build/pom.xml
index 1f797637a0..be4b7c6231 100644
--- a/build/pom.xml
+++ b/build/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/cloud/docker-image/pom.xml b/cloud/docker-image/pom.xml
index d72740841c..2f105e44e5 100644
--- a/cloud/docker-image/pom.xml
+++ b/cloud/docker-image/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
cloud
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/cloud/docker-image/src/main/docker/Dockerfile b/cloud/docker-image/src/main/docker/Dockerfile
index 48231d2ba3..1a50cf2782 100644
--- a/cloud/docker-image/src/main/docker/Dockerfile
+++ b/cloud/docker-image/src/main/docker/Dockerfile
@@ -22,7 +22,7 @@ COPY zpm.json.template zpm.json.template
RUN cat zpm.json.template | sed "s/\${VERSION}/${project.version}/g" | tee zpm.json
-RUN ./zpmw install --debug --exclude-remote-repositories
+RUN ./zpmw install --debug --instrument --exclude-remote-repositories
RUN ./zpmw clean --keep-image
FROM ubuntu:jammy-20240530
diff --git a/cloud/helm-chart/pom.xml b/cloud/helm-chart/pom.xml
index 13e56c8dd2..efd38eb699 100644
--- a/cloud/helm-chart/pom.xml
+++ b/cloud/helm-chart/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
cloud
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/cloud/pom.xml b/cloud/pom.xml
index 689b45a5e8..882b7910a8 100644
--- a/cloud/pom.xml
+++ b/cloud/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/conf/pom.xml b/conf/pom.xml
index b26e85b098..f783fc0107 100644
--- a/conf/pom.xml
+++ b/conf/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-amqp.spec/pom.xml b/incubator/binding-amqp.spec/pom.xml
index 901cf76be6..d6340db2ef 100644
--- a/incubator/binding-amqp.spec/pom.xml
+++ b/incubator/binding-amqp.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-amqp/pom.xml b/incubator/binding-amqp/pom.xml
index 3317604640..47a4304ec3 100644
--- a/incubator/binding-amqp/pom.xml
+++ b/incubator/binding-amqp/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-pgsql-kafka.spec/pom.xml b/incubator/binding-pgsql-kafka.spec/pom.xml
index 9b390548a2..649f0cb698 100644
--- a/incubator/binding-pgsql-kafka.spec/pom.xml
+++ b/incubator/binding-pgsql-kafka.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-pgsql-kafka/pom.xml b/incubator/binding-pgsql-kafka/pom.xml
index c862bce6b7..f07b380163 100644
--- a/incubator/binding-pgsql-kafka/pom.xml
+++ b/incubator/binding-pgsql-kafka/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-pgsql.spec/pom.xml b/incubator/binding-pgsql.spec/pom.xml
index 6880810b40..6a78fcdecb 100644
--- a/incubator/binding-pgsql.spec/pom.xml
+++ b/incubator/binding-pgsql.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-pgsql/pom.xml b/incubator/binding-pgsql/pom.xml
index 0aa69d10ce..ec024cc0e6 100644
--- a/incubator/binding-pgsql/pom.xml
+++ b/incubator/binding-pgsql/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-risingwave.spec/pom.xml b/incubator/binding-risingwave.spec/pom.xml
index 14466d53e4..25270feaf4 100644
--- a/incubator/binding-risingwave.spec/pom.xml
+++ b/incubator/binding-risingwave.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/binding-risingwave/pom.xml b/incubator/binding-risingwave/pom.xml
index 28566b37ec..f184f1f9aa 100644
--- a/incubator/binding-risingwave/pom.xml
+++ b/incubator/binding-risingwave/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/command-dump/pom.xml b/incubator/command-dump/pom.xml
index 12be22dc75..c57bd4e037 100644
--- a/incubator/command-dump/pom.xml
+++ b/incubator/command-dump/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/command-log/pom.xml b/incubator/command-log/pom.xml
index caf5a5b81f..5c4c5df727 100644
--- a/incubator/command-log/pom.xml
+++ b/incubator/command-log/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/command-tune/pom.xml b/incubator/command-tune/pom.xml
index cfa688f36a..8edaeb6ce4 100644
--- a/incubator/command-tune/pom.xml
+++ b/incubator/command-tune/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
incubator
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/incubator/pom.xml b/incubator/pom.xml
index 5d62dea9ab..1ddd896552 100644
--- a/incubator/pom.xml
+++ b/incubator/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/manager/pom.xml b/manager/pom.xml
index 023c0cb66b..05b495c5a8 100644
--- a/manager/pom.xml
+++ b/manager/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/pom.xml b/pom.xml
index f7754b749b..f650ae57c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
4.0.0
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
pom
zilla
https://github.com/aklivity/zilla
diff --git a/runtime/binding-asyncapi/pom.xml b/runtime/binding-asyncapi/pom.xml
index 227b9bf4b4..2dd5ee58b0 100644
--- a/runtime/binding-asyncapi/pom.xml
+++ b/runtime/binding-asyncapi/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-echo/pom.xml b/runtime/binding-echo/pom.xml
index a923a2269d..d025b27f11 100644
--- a/runtime/binding-echo/pom.xml
+++ b/runtime/binding-echo/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-fan/pom.xml b/runtime/binding-fan/pom.xml
index 3681383be7..25f56664f4 100644
--- a/runtime/binding-fan/pom.xml
+++ b/runtime/binding-fan/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-filesystem/pom.xml b/runtime/binding-filesystem/pom.xml
index a9a8ec5c6e..2125cdb8b9 100644
--- a/runtime/binding-filesystem/pom.xml
+++ b/runtime/binding-filesystem/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java b/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java
index 182e53b36b..62c5ca3663 100644
--- a/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java
+++ b/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java
@@ -15,14 +15,23 @@
package io.aklivity.zilla.runtime.binding.filesystem.internal.stream;
import static io.aklivity.zilla.runtime.binding.filesystem.config.FileSystemSymbolicLinksConfig.IGNORE;
+import static io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemError.FILE_ALREADY_EXISTS;
+import static io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemError.FILE_MODIFIED;
+import static io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemError.FILE_NOT_FOUND;
+import static io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemError.FILE_TAG_MISSING;
import static io.aklivity.zilla.runtime.engine.budget.BudgetDebitor.NO_DEBITOR_INDEX;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
+import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.WRITE;
import static java.time.Instant.now;
import static org.agrona.LangUtil.rethrowUnchecked;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
+import java.nio.channels.ByteChannel;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.LinkOption;
@@ -55,6 +64,9 @@
import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.DataFW;
import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.EndFW;
import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemBeginExFW;
+import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemError;
+import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemErrorFW;
+import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.FileSystemResetExFW;
import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.ResetFW;
import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.SignalFW;
import io.aklivity.zilla.runtime.binding.filesystem.internal.types.stream.WindowFW;
@@ -73,11 +85,17 @@ public final class FileSystemServerFactory implements FileSystemStreamFactory
private static final OctetsFW EMPTY_EXTENSION = new OctetsFW().wrap(new UnsafeBuffer(new byte[0]), 0, 0);
private static final int READ_PAYLOAD_MASK = 1 << FileSystemCapabilities.READ_PAYLOAD.ordinal();
+ private static final int WRITE_PAYLOAD_MASK = 1 << FileSystemCapabilities.WRITE_PAYLOAD.ordinal();
+ private static final int CREATE_PAYLOAD_MASK = 1 << FileSystemCapabilities.CREATE_PAYLOAD.ordinal();
+ private static final int DELETE_PAYLOAD_MASK = 1 << FileSystemCapabilities.DELETE_PAYLOAD.ordinal();
private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
private static final int TIMEOUT_EXPIRED_SIGNAL_ID = 0;
public static final int FILE_CHANGED_SIGNAL_ID = 1;
+ private static final int FLAG_FIN = 0x01;
+ private static final int FLAG_INIT = 0x02;
private final BeginFW beginRO = new BeginFW();
+ private final DataFW dataRO = new DataFW();
private final EndFW endRO = new EndFW();
private final AbortFW abortRO = new AbortFW();
private final WindowFW windowRO = new WindowFW();
@@ -94,12 +112,15 @@ public final class FileSystemServerFactory implements FileSystemStreamFactory
private final WindowFW.Builder windowRW = new WindowFW.Builder();
private final FileSystemBeginExFW.Builder beginExRW = new FileSystemBeginExFW.Builder();
+ private final FileSystemResetExFW.Builder resetExRW = new FileSystemResetExFW.Builder();
+ private final FileSystemErrorFW.Builder errorExRW = new FileSystemErrorFW.Builder();
private final OctetsFW payloadRO = new OctetsFW();
private final Long2ObjectHashMap bindings;
private final BufferPool bufferPool;
private final MutableDirectBuffer writeBuffer;
private final MutableDirectBuffer extBuffer;
+ private final MutableDirectBuffer errorBuffer;
private final MutableDirectBuffer readBuffer;
private final LongFunction supplyDebitor;
private final LongUnaryOperator supplyReplyId;
@@ -109,6 +130,8 @@ public final class FileSystemServerFactory implements FileSystemStreamFactory
private final Signaler signaler;
private final Supplier supplyWatcher;
+ private final int decodeMax;
+
private FileSystemWatcher fileSystemWatcher;
public FileSystemServerFactory(
@@ -121,6 +144,7 @@ public FileSystemServerFactory(
this.writeBuffer = context.writeBuffer();
this.extBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]);
this.readBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]);
+ this.errorBuffer = new UnsafeBuffer(new byte[1]);
this.supplyDebitor = context::supplyDebitor;
this.supplyReplyId = context::supplyReplyId;
this.fileSystemTypeId = context.supplyTypeId(FileSystemBinding.NAME);
@@ -128,6 +152,7 @@ public FileSystemServerFactory(
this.signaler = context.signaler();
this.md5 = initMessageDigest("MD5");
this.supplyWatcher = supplyWatcher;
+ this.decodeMax = bufferPool.slotCapacity();
}
@Override
@@ -181,10 +206,10 @@ public MessageConsumer newStream(
final String tag = beginEx.tag().asString();
try
{
- if (Files.exists(Paths.get(resolvedPath), symlinks))
+ if (writeOperation(capabilities))
{
String type = probeContentTypeOrDefault(path);
- newStream = new FileSystemServer(
+ newStream = new FileSystemServerWriter(
app,
originId,
routedId,
@@ -196,6 +221,25 @@ public MessageConsumer newStream(
capabilities,
tag)::onAppMessage;
}
+ else
+ {
+ if (Files.exists(Paths.get(resolvedPath), symlinks))
+ {
+ String type = probeContentTypeOrDefault(path);
+ newStream = new FileSystemServerReader(
+ app,
+ originId,
+ routedId,
+ initialId,
+ type,
+ symlinks,
+ relativePath,
+ resolvedPath,
+ capabilities,
+ tag)::onAppMessage;
+ }
+ }
+
}
catch (IOException ex)
{
@@ -228,7 +272,7 @@ private String probeContentTypeOrDefault(
return contentType != null ? contentType : DEFAULT_CONTENT_TYPE;
}
- private final class FileSystemServer
+ private final class FileSystemServerReader
{
private final MessageConsumer app;
private final long originId;
@@ -260,7 +304,7 @@ private final class FileSystemServer
private int state;
- private FileSystemServer(
+ private FileSystemServerReader(
MessageConsumer app,
long originId,
long routedId,
@@ -602,7 +646,8 @@ private void doAppReset(
{
state = FileSystemState.closeInitial(state);
- doReset(app, originId, routedId, initialId, initialSeq, initialAck, initialMax, traceId, 0L);
+ doReset(app, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, 0L, EMPTY_EXTENSION);
}
}
@@ -687,6 +732,490 @@ private void flushAppData(
}
}
+ private final class FileSystemServerWriter
+ {
+ private final MessageConsumer app;
+ private final long originId;
+ private final long routedId;
+ private final long initialId;
+ private final long replyId;
+ private final String type;
+ private final String relativePath;
+ private final Path resolvedPath;
+ private final int capabilities;
+ private final String tag;
+ private final LinkOption[] symlinks;
+ private long initialSeq;
+ private long initialAck;
+ private int initialMax;
+
+ private long replySeq;
+ private long replyAck;
+ private int replyMax;
+ private int replyPad;
+ private long replyBud;
+
+ private int state;
+
+ private ByteChannel out;
+ private Path tmpPath;
+
+ private FileSystemServerWriter(
+ MessageConsumer app,
+ long originId,
+ long routedId,
+ long initialId,
+ String type,
+ LinkOption[] symlinks,
+ String relativePath,
+ String resolvedPath,
+ int capabilities,
+ String tag)
+ {
+ this.app = app;
+ this.originId = originId;
+ this.routedId = routedId;
+ this.initialId = initialId;
+ this.replyId = supplyReplyId.applyAsLong(initialId);
+ this.type = type;
+ this.symlinks = symlinks;
+ this.relativePath = relativePath;
+ this.resolvedPath = Paths.get(resolvedPath);
+ this.capabilities = capabilities;
+ this.tag = tag != null && !tag.isEmpty() ? tag : null;
+ this.initialMax = decodeMax;
+ }
+
+ private void onAppMessage(
+ int msgTypeId,
+ DirectBuffer buffer,
+ int index,
+ int length)
+ {
+ switch (msgTypeId)
+ {
+ case BeginFW.TYPE_ID:
+ final BeginFW begin = beginRO.wrap(buffer, index, index + length);
+ onAppBegin(begin);
+ break;
+ case DataFW.TYPE_ID:
+ final DataFW data = dataRO.wrap(buffer, index, index + length);
+ onAppData(data);
+ break;
+ case EndFW.TYPE_ID:
+ final EndFW end = endRO.wrap(buffer, index, index + length);
+ onAppEnd(end);
+ break;
+ case AbortFW.TYPE_ID:
+ final AbortFW abort = abortRO.wrap(buffer, index, index + length);
+ onAppAbort(abort);
+ break;
+ case WindowFW.TYPE_ID:
+ final WindowFW window = windowRO.wrap(buffer, index, index + length);
+ onAppWindow(window);
+ break;
+ case ResetFW.TYPE_ID:
+ final ResetFW reset = resetRO.wrap(buffer, index, index + length);
+ onAppReset(reset);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void onAppBegin(
+ BeginFW begin)
+ {
+ final long sequence = begin.sequence();
+ final long acknowledge = begin.acknowledge();
+ final long traceId = begin.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+ assert acknowledge >= initialAck;
+
+ initialSeq = sequence;
+ initialAck = acknowledge;
+
+ assert initialAck <= initialSeq;
+
+ state = FileSystemState.openingInitial(state);
+
+ FileSystemError error = null;
+
+ if ((capabilities & CREATE_PAYLOAD_MASK) != 0 && Files.exists(resolvedPath))
+ {
+ error = FILE_ALREADY_EXISTS;
+ }
+ else if ((capabilities & WRITE_PAYLOAD_MASK) != 0)
+ {
+ if (Files.notExists(resolvedPath))
+ {
+ error = FILE_NOT_FOUND;
+ }
+ else if (tag == null)
+ {
+ error = FILE_TAG_MISSING;
+ }
+ else if (!validateTag())
+ {
+ error = FILE_MODIFIED;
+ }
+ }
+ else if ((capabilities & DELETE_PAYLOAD_MASK) != 0)
+ {
+ if (Files.notExists(resolvedPath))
+ {
+ error = FILE_NOT_FOUND;
+
+ }
+ else if (tag != null && !validateTag())
+ {
+ error = FILE_MODIFIED;
+ }
+ else
+ {
+ delete(traceId);
+ }
+ }
+
+ if (error != null)
+ {
+ errorExRW.wrap(errorBuffer, 0, errorBuffer.capacity()).set(error);
+
+ FileSystemResetExFW extension = resetExRW
+ .wrap(extBuffer, 0, extBuffer.capacity())
+ .typeId(fileSystemTypeId)
+ .error(errorExRW.build())
+ .build();
+
+ doAppReset(traceId, extension);
+ }
+
+ doAppWindow(traceId);
+ }
+
+ private void onAppData(
+ DataFW data)
+ {
+ final long sequence = data.sequence();
+ final long acknowledge = data.acknowledge();
+ final long traceId = data.traceId();
+ final int flags = data.flags();
+ final int reserved = data.reserved();
+ final OctetsFW payload = data.payload();
+
+ int offset = payload.offset();
+ int length = payload.sizeof();
+
+ assert acknowledge <= sequence;
+ assert sequence >= replySeq;
+
+ initialSeq = sequence + reserved;
+
+ assert initialAck <= initialSeq;
+
+ if (initialSeq > initialAck + initialMax)
+ {
+ cleanup(traceId);
+ }
+ else
+ {
+ try
+ {
+ if ((flags & FLAG_INIT) != 0x00)
+ {
+ out = getOutputStream();
+ }
+
+ assert out != null;
+
+ out.write(payload.buffer().byteBuffer().slice(offset, length));
+
+ if ((flags & FLAG_FIN) != 0x00)
+ {
+ out.close();
+
+ if ((capabilities & WRITE_PAYLOAD_MASK) != 0)
+ {
+ Files.move(tmpPath, resolvedPath, REPLACE_EXISTING, ATOMIC_MOVE);
+ }
+
+ String currentTag = calculateTag();
+ doAppBegin(traceId, currentTag);
+ doAppEnd(traceId);
+ }
+ doAppWindow(traceId);
+ }
+ catch (Exception ex)
+ {
+ cleanup(traceId);
+ }
+ }
+ }
+
+ private void onAppEnd(
+ EndFW end)
+ {
+ final long sequence = end.sequence();
+ final long acknowledge = end.acknowledge();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+
+ assert initialAck <= initialSeq;
+
+ state = FileSystemState.closeInitial(state);
+ }
+
+ private void onAppAbort(
+ AbortFW abort)
+ {
+ final long sequence = abort.sequence();
+ final long acknowledge = abort.acknowledge();
+ final long traceId = abort.traceId();
+
+ assert acknowledge <= sequence;
+ assert sequence >= initialSeq;
+
+ initialSeq = sequence;
+
+ assert initialAck <= initialSeq;
+
+ state = FileSystemState.closeInitial(state);
+
+ cleanupTmpFileIfExists();
+
+ doAppAbort(traceId);
+ }
+
+ private void onAppWindow(
+ WindowFW window)
+ {
+ final long sequence = window.sequence();
+ final long acknowledge = window.acknowledge();
+ final int maximum = window.maximum();
+ final int padding = window.padding();
+ final long budgetId = window.budgetId();
+ final long traceId = window.traceId();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= replyAck;
+ assert maximum >= replyMax;
+
+ replyAck = acknowledge;
+ replyMax = maximum;
+ replyPad = padding;
+ replyBud = budgetId;
+
+ assert replyAck <= replySeq;
+
+ if (FileSystemState.replyOpening(state) && !FileSystemState.replyClosed(state))
+ {
+ state = FileSystemState.openReply(state);
+ }
+ }
+
+ private void onAppReset(
+ ResetFW reset)
+ {
+ final long sequence = reset.sequence();
+ final long acknowledge = reset.acknowledge();
+ final long traceId = reset.traceId();
+
+ assert acknowledge <= sequence;
+ assert acknowledge >= replyAck;
+
+ replyAck = acknowledge;
+
+ assert replyAck <= replySeq;
+
+ state = FileSystemState.closeReply(state);
+
+ cleanupTmpFileIfExists();
+
+ doAppReset(traceId, EMPTY_EXTENSION);
+ }
+
+ private void doAppBegin(
+ long traceId,
+ String tag)
+ {
+ doAppBegin(traceId, tag, capabilities);
+ }
+
+ private void doAppBegin(
+ long traceId,
+ String tag,
+ int capabilities)
+ {
+ state = FileSystemState.openingReply(state);
+ Flyweight extension = beginExRW
+ .wrap(extBuffer, 0, extBuffer.capacity())
+ .typeId(fileSystemTypeId)
+ .capabilities(capabilities)
+ .path(relativePath)
+ .tag(tag)
+ .build();
+ doBegin(app, originId, routedId, replyId, replySeq, replyAck, replyMax, traceId, 0L, 0L, extension);
+ }
+
+ private void doAppEnd(
+ long traceId)
+ {
+ if (FileSystemState.replyOpening(state) && !FileSystemState.replyClosed(state))
+ {
+ state = FileSystemState.closeReply(state);
+ doEnd(app, originId, routedId, replyId, replySeq, replyAck, replyMax, traceId, 0L, EMPTY_EXTENSION);
+ }
+ }
+
+ private void doAppAbort(
+ long traceId)
+ {
+ if (FileSystemState.replyOpening(state) && !FileSystemState.replyClosed(state))
+ {
+ state = FileSystemState.closeReply(state);
+ doAbort(app, originId, routedId, replyId, replySeq, replyAck,
+ replyMax, traceId, 0L, EMPTY_EXTENSION);
+ }
+ }
+
+ private void doAppReset(
+ long traceId,
+ Flyweight extension)
+ {
+ if (FileSystemState.initialOpening(state) && !FileSystemState.initialClosed(state))
+ {
+ state = FileSystemState.closeInitial(state);
+
+ doReset(app, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, 0L, extension);
+ }
+ }
+
+ private void doAppWindow(
+ long traceId)
+ {
+ if (!FileSystemState.initialClosed(state))
+ {
+ state = FileSystemState.openInitial(state);
+
+ doWindow(app, originId, routedId, initialId, initialSeq, initialAck, initialMax, traceId,
+ 0L, 0L, 0);
+ }
+ }
+
+ private void cleanup(
+ long traceId)
+ {
+ cleanupTmpFileIfExists();
+
+ doAppAbort(traceId);
+ doAppReset(traceId, EMPTY_EXTENSION);
+ }
+
+ private void cleanupTmpFileIfExists()
+ {
+ if (tmpPath != null)
+ {
+ try
+ {
+ Files.deleteIfExists(tmpPath);
+ }
+ catch (IOException ex)
+ {
+ rethrowUnchecked(ex);
+ }
+ }
+ }
+
+ private String calculateTag()
+ {
+ String newTag = null;
+ try
+ {
+ InputStream input = getInputStream();
+ if (input != null)
+ {
+ md5.reset();
+ while (input.available() > 0)
+ {
+ final byte[] readArray = readBuffer.byteArray();
+ int bytesRead = input.read(readArray, 0, readArray.length);
+ md5.update(readArray, 0, Math.max(bytesRead, 0));
+ }
+ byte[] hash = md5.digest();
+ newTag = BitUtil.toHex(hash);
+ }
+ }
+ catch (IOException ex)
+ {
+ // reject
+ }
+ return newTag;
+ }
+
+ private boolean validateTag()
+ {
+ return tag.equals(calculateTag());
+ }
+
+ private InputStream getInputStream()
+ {
+ InputStream input = null;
+ try
+ {
+ input = Files.newInputStream(resolvedPath, symlinks);
+ }
+ catch (IOException ex)
+ {
+ // reject
+ }
+ return input;
+ }
+
+ private ByteChannel getOutputStream()
+ {
+ ByteChannel output = null;
+ try
+ {
+ if (canCreatePayload(capabilities, resolvedPath))
+ {
+ output = Files.newByteChannel(resolvedPath, CREATE, WRITE);
+ }
+ else if (canWritePayload(capabilities, resolvedPath))
+ {
+ tmpPath = Files.createTempFile(resolvedPath.getParent(), "temp-", ".tmp");
+ output = Files.newByteChannel(tmpPath, WRITE);
+ }
+ }
+ catch (IOException ex)
+ {
+ // reject
+ }
+ return output;
+ }
+
+ private void delete(
+ long traceId)
+ {
+ try
+ {
+ Files.delete(resolvedPath);
+ doAppWindow(traceId);
+ doAppBegin(traceId, null);
+ doAppEnd(traceId);
+ }
+ catch (IOException ex)
+ {
+ cleanup(traceId);
+ }
+ }
+ }
+
private void doBegin(
MessageConsumer receiver,
long originId,
@@ -812,7 +1341,8 @@ private void doReset(
long acknowledge,
int maximum,
long traceId,
- long authorization)
+ long authorization,
+ Flyweight extension)
{
final ResetFW reset = resetRW.wrap(writeBuffer, 0, writeBuffer.capacity())
.originId(originId)
@@ -823,6 +1353,7 @@ private void doReset(
.maximum(maximum)
.traceId(traceId)
.authorization(authorization)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
.build();
receiver.accept(reset.typeId(), reset.buffer(), reset.offset(), reset.sizeof());
@@ -862,4 +1393,33 @@ private boolean canReadPayload(
{
return (capabilities & READ_PAYLOAD_MASK) != 0;
}
+
+ private boolean canWritePayload(
+ int capabilities,
+ Path path)
+ {
+ return (capabilities & WRITE_PAYLOAD_MASK) != 0 && Files.exists(path);
+ }
+
+ private boolean canCreatePayload(
+ int capabilities,
+ Path path)
+ {
+ return (capabilities & CREATE_PAYLOAD_MASK) != 0 && Files.notExists(path);
+ }
+
+ private boolean canDeletePayload(
+ int capabilities,
+ Path path)
+ {
+ return (capabilities & DELETE_PAYLOAD_MASK) != 0 && Files.exists(path);
+ }
+
+ private boolean writeOperation(
+ int capabilities)
+ {
+ return (capabilities & CREATE_PAYLOAD_MASK) != 0 ||
+ (capabilities & WRITE_PAYLOAD_MASK) != 0 ||
+ (capabilities & DELETE_PAYLOAD_MASK) != 0;
+ }
}
diff --git a/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java b/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java
index 2b20400986..f9e47e6cd7 100644
--- a/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java
+++ b/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java
@@ -137,9 +137,9 @@ public void shouldReadFilePayloadModifiedMultiClient() throws Exception
@Test
@Configuration("server.yaml")
@Specification({
- "${app}/read.file.payload.etag.not.matched/client"
+ "${app}/read.file.payload.tag.not.matched/client"
})
- public void shouldReadFilePayloadEtagNotMatched() throws Exception
+ public void shouldReadFilePayloadTagNotMatched() throws Exception
{
k3po.finish();
}
@@ -252,4 +252,105 @@ public void shouldReceiveClientReadAbort() throws Exception
{
k3po.finish();
}
+
+ @Test
+ @Configuration("server.yaml")
+ @Specification({
+ "${app}/create.file.payload/client",
+ })
+ public void shouldCreateFilePayloadOnly() throws Exception
+ {
+ Path targetDirectory = Paths.get("target/files").toAbsolutePath();
+ Path indexFile = targetDirectory.resolve("index_write.html");
+
+ Files.deleteIfExists(indexFile);
+
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("server.yaml")
+ @Specification({
+ "${app}/write.file.payload.modified/client",
+ })
+ public void shouldWriteFilePayloadModified() throws Exception
+ {
+ Path targetDirectory = Paths.get("target/files").toAbsolutePath();
+ Path indexFile = targetDirectory.resolve("index_write.html");
+
+ Files.createDirectories(targetDirectory);
+
+ Files.write(indexFile, """
+
+ Welcome
+ Hello, world
+
+ """.getBytes());
+
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("server.yaml")
+ @Specification({
+ "${app}/write.file.payload.modified.abort/client",
+ })
+ public void shouldWriteFilePayloadModifiedAbort() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("server.yaml")
+ @Specification({
+ "${app}/write.file.payload.interrupt/client",
+ })
+ public void shouldWriteFilePayloadInterrupt() throws Exception
+ {
+ Path targetDirectory = Paths.get("target/files").toAbsolutePath();
+ Path indexFile = targetDirectory.resolve("index_write.html");
+
+ Files.createDirectories(targetDirectory);
+
+ Files.write(indexFile, """
+
+ Welcome
+ Hello, world
+
+ """.getBytes());
+
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("server.yaml")
+ @Specification({
+ "${app}/delete.file.payload/client",
+ })
+ public void shouldDeleteFilePayload() throws Exception
+ {
+ Path targetDirectory = Paths.get("target/files").toAbsolutePath();
+ Path indexFile = targetDirectory.resolve("error.html");
+
+ Files.createDirectories(targetDirectory);
+
+ Files.write(indexFile, """
+
+ Welcome
+ Hello, world
+
+ """.getBytes());
+
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("server.yaml")
+ @Specification({
+ "${app}/delete.file.payload.failed/client",
+ })
+ public void shouldRejectDeleteFilePayload() throws Exception
+ {
+ k3po.finish();
+ }
}
diff --git a/runtime/binding-grpc-kafka/pom.xml b/runtime/binding-grpc-kafka/pom.xml
index 0d4a8bcf96..508293d35c 100644
--- a/runtime/binding-grpc-kafka/pom.xml
+++ b/runtime/binding-grpc-kafka/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-grpc/pom.xml b/runtime/binding-grpc/pom.xml
index f3b86e927b..eb9d0e67cd 100644
--- a/runtime/binding-grpc/pom.xml
+++ b/runtime/binding-grpc/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-http-filesystem/pom.xml b/runtime/binding-http-filesystem/pom.xml
index 4b942ae3e8..c9c2fd94d3 100644
--- a/runtime/binding-http-filesystem/pom.xml
+++ b/runtime/binding-http-filesystem/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/config/HttpFileSystemWithResolver.java b/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/config/HttpFileSystemWithResolver.java
index 41f518b026..e765c96b94 100644
--- a/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/config/HttpFileSystemWithResolver.java
+++ b/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/config/HttpFileSystemWithResolver.java
@@ -14,8 +14,11 @@
*/
package io.aklivity.zilla.runtime.binding.http.filesystem.internal.config;
+import static io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.FileSystemCapabilities.CREATE_PAYLOAD;
+import static io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.FileSystemCapabilities.DELETE_PAYLOAD;
import static io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.FileSystemCapabilities.READ_EXTENSION;
import static io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.FileSystemCapabilities.READ_PAYLOAD;
+import static io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.FileSystemCapabilities.WRITE_PAYLOAD;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@@ -32,14 +35,21 @@ public final class HttpFileSystemWithResolver
{
public static final int HEADER_METHOD_MASK_HEAD = 1 << READ_EXTENSION.ordinal();
private static final int HEADER_METHOD_MASK_GET = 1 << READ_PAYLOAD.ordinal() | 1 << READ_EXTENSION.ordinal();
+ public static final int HEADER_METHOD_MASK_POST = 1 << CREATE_PAYLOAD.ordinal();
+ public static final int HEADER_METHOD_MASK_PUT = 1 << WRITE_PAYLOAD.ordinal();
+ public static final int HEADER_METHOD_MASK_DELETE = 1 << DELETE_PAYLOAD.ordinal();
private static final Pattern PARAMS_PATTERN = Pattern.compile("\\$\\{params\\.([a-zA-Z_]+)\\}");
private static final Pattern PREFER_WAIT_PATTERN = Pattern.compile("wait=(\\d+)");
private static final String8FW HEADER_METHOD_NAME = new String8FW(":method");
private static final String8FW HEADER_IF_NONE_MATCH_NAME = new String8FW("if-none-match");
+ private static final String8FW HEADER_IF_MATCH_NAME = new String8FW("if-match");
private static final String8FW HEADER_PREFER_NAME = new String8FW("prefer");
private static final String16FW HEADER_METHOD_VALUE_GET = new String16FW("GET");
private static final String16FW HEADER_METHOD_VALUE_HEAD = new String16FW("HEAD");
+ private static final String16FW HEADER_METHOD_VALUE_POST = new String16FW("POST");
+ private static final String16FW HEADER_METHOD_VALUE_PUT = new String16FW("PUT");
+ private static final String16FW HEADER_METHOD_VALUE_DELETE = new String16FW("DELETE");
private final String16FW etagRO = new String16FW();
private final HttpFileSystemWithConfig with;
@@ -73,6 +83,7 @@ public HttpFileSystemWithResult resolve(
path0 = pathMatcher.replaceAll(replacer);
}
String16FW path = new String16FW(path0);
+ String16FW etag = new String16FW("");
HttpHeaderFW method = httpBeginEx.headers().matchFirst(h -> HEADER_METHOD_NAME.equals(h.name()));
int capabilities = 0;
@@ -86,14 +97,27 @@ else if (HEADER_METHOD_VALUE_GET.equals(method.value()))
{
capabilities = HEADER_METHOD_MASK_GET;
}
+ else if (HEADER_METHOD_VALUE_POST.equals(method.value()))
+ {
+ capabilities = HEADER_METHOD_MASK_POST;
+ }
+ else if (HEADER_METHOD_VALUE_PUT.equals(method.value()))
+ {
+ capabilities = HEADER_METHOD_MASK_PUT;
+ }
+ else if (HEADER_METHOD_VALUE_DELETE.equals(method.value()))
+ {
+ capabilities = HEADER_METHOD_MASK_DELETE;
+ }
}
- HttpHeaderFW ifNotMatched = httpBeginEx.headers().matchFirst(h -> HEADER_IF_NONE_MATCH_NAME.equals(h.name()));
- String16FW etag = new String16FW("");
- if (ifNotMatched != null)
+ HttpHeaderFW tag = httpBeginEx.headers().matchFirst(h ->
+ HEADER_IF_MATCH_NAME.equals(h.name()) || HEADER_IF_NONE_MATCH_NAME.equals(h.name()));
+ if (tag != null)
{
- String16FW value = ifNotMatched.value();
+ String16FW value = tag.value();
etag = etagRO.wrap(value.buffer(), value.offset(), value.limit());
}
+
HttpHeaderFW prefer = httpBeginEx.headers().matchFirst(h -> HEADER_PREFER_NAME.equals(h.name()));
int wait = 0;
if (prefer != null)
diff --git a/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyFactory.java b/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyFactory.java
index 96711fb556..b10ad0dcc6 100644
--- a/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyFactory.java
+++ b/runtime/binding-http-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyFactory.java
@@ -38,8 +38,12 @@
import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.EndFW;
import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.ExtensionFW;
import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.FileSystemBeginExFW;
+import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.FileSystemError;
+import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.FileSystemErrorFW;
+import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.FileSystemResetExFW;
import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.FlushFW;
import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.HttpBeginExFW;
+import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.HttpResetExFW;
import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.ResetFW;
import io.aklivity.zilla.runtime.binding.http.filesystem.internal.types.stream.WindowFW;
import io.aklivity.zilla.runtime.engine.EngineContext;
@@ -54,13 +58,22 @@ public final class HttpFileSystemProxyFactory implements HttpFileSystemStreamFac
private static final String8FW HEADER_STATUS_NAME = new String8FW(":status");
private static final String16FW HEADER_STATUS_VALUE_200 = new String16FW("200");
+ private static final String16FW HEADER_STATUS_VALUE_204 = new String16FW("204");
private static final String16FW HEADER_STATUS_VALUE_304 = new String16FW("304");
+ private static final String16FW HEADER_STATUS_VALUE_404 = new String16FW("404");
+ private static final String16FW HEADER_STATUS_VALUE_409 = new String16FW("409");
+ private static final String16FW HEADER_STATUS_VALUE_428 = new String16FW("428");
+ private static final String16FW HEADER_STATUS_VALUE_412 = new String16FW("412");
private static final String8FW HEADER_ETAG_NAME = new String8FW("etag");
private static final String8FW HEADER_CONTENT_TYPE_NAME = new String8FW("content-type");
private static final String8FW HEADER_CONTENT_LENGTH_NAME = new String8FW("content-length");
+ private static final OctetsFW EMPTY_EXTENSION = new OctetsFW().wrap(new UnsafeBuffer(new byte[0]), 0, 0);
private static final int READ_PAYLOAD_MASK = 1 << FileSystemCapabilities.READ_PAYLOAD.ordinal();
+ private static final int WRITE_PAYLOAD_MASK = 1 << FileSystemCapabilities.WRITE_PAYLOAD.ordinal();
+ private static final int CREATE_PAYLOAD_MASK = 1 << FileSystemCapabilities.CREATE_PAYLOAD.ordinal();
+ private static final int DELETE_PAYLOAD_MASK = 1 << FileSystemCapabilities.DELETE_PAYLOAD.ordinal();
- private static final Predicate HEADER_METHOD_GET_OR_HEAD;
+ private static final Predicate SUPPORTED_HTTP_METHOD;
static
{
@@ -76,9 +89,30 @@ public final class HttpFileSystemProxyFactory implements HttpFileSystemStreamFac
.value("HEAD")
.build();
+ HttpHeaderFW headerMethodPost = new HttpHeaderFW.Builder()
+ .wrap(new UnsafeBuffer(new byte[512]), 0, 512)
+ .name(":method")
+ .value("POST")
+ .build();
+
+ HttpHeaderFW headerMethodPut = new HttpHeaderFW.Builder()
+ .wrap(new UnsafeBuffer(new byte[512]), 0, 512)
+ .name(":method")
+ .value("PUT")
+ .build();
+
+ HttpHeaderFW headerMethodDelete = new HttpHeaderFW.Builder()
+ .wrap(new UnsafeBuffer(new byte[512]), 0, 512)
+ .name(":method")
+ .value("DELETE")
+ .build();
+
Predicate test = headerMethodGet::equals;
test = test.or(headerMethodHead::equals);
- HEADER_METHOD_GET_OR_HEAD = test;
+ test = test.or(headerMethodPost::equals);
+ test = test.or(headerMethodPut::equals);
+ test = test.or(headerMethodDelete::equals);
+ SUPPORTED_HTTP_METHOD = test;
}
private final OctetsFW emptyExRO = new OctetsFW().wrap(new UnsafeBuffer(0L, 0), 0, 0);
@@ -104,8 +138,10 @@ public final class HttpFileSystemProxyFactory implements HttpFileSystemStreamFac
private final HttpBeginExFW httpBeginExRO = new HttpBeginExFW();
private final FileSystemBeginExFW fsBeginExRO = new FileSystemBeginExFW();
+ private final FileSystemResetExFW fsResetExRO = new FileSystemResetExFW();
private final HttpBeginExFW.Builder httpBeginExRW = new HttpBeginExFW.Builder();
+ private final HttpResetExFW.Builder httpResetExRW = new HttpResetExFW.Builder();
private final FileSystemBeginExFW.Builder fsBeginExRW = new FileSystemBeginExFW.Builder();
private final MutableDirectBuffer writeBuffer;
@@ -173,7 +209,7 @@ public MessageConsumer newStream(
HttpFileSystemRouteConfig route = null;
- if (binding != null && beginEx.headers().anyMatch(HEADER_METHOD_GET_OR_HEAD))
+ if (binding != null && beginEx.headers().anyMatch(SUPPORTED_HTTP_METHOD))
{
route = binding.resolve(authorization, beginEx);
}
@@ -300,6 +336,10 @@ private void onHttpData(
final long acknowledge = data.acknowledge();
final long traceId = data.traceId();
final long authorization = data.authorization();
+ final long budgetId = data.budgetId();
+ final int reserved = data.reserved();
+ final int flags = data.flags();
+ final OctetsFW payload = data.payload();
assert acknowledge <= sequence;
assert sequence >= initialSeq;
@@ -308,8 +348,15 @@ private void onHttpData(
assert initialAck <= initialSeq;
- doHttpReset(traceId);
- delegate.doFileSystemAbort(traceId, authorization);
+ if (delegate.createOrWritePayload(resolved.capabilities()))
+ {
+ delegate.doFileSystemData(traceId, authorization, budgetId, reserved, flags, payload);
+ }
+ else
+ {
+ doHttpReset(traceId, null);
+ delegate.doFileSystemAbort(traceId, authorization);
+ }
}
private void onHttpEnd(
@@ -484,13 +531,46 @@ private void doHttpWindow(
}
private void doHttpReset(
- long traceId)
+ long traceId,
+ FileSystemErrorFW error)
{
if (!HttpFileSystemState.initialClosed(state))
{
state = HttpFileSystemState.closeInitial(state);
- doReset(http, originId, routedId, initialId, initialSeq, initialAck, initialMax, traceId);
+ String16FW httpStatus;
+
+ if (error != null)
+ {
+ FileSystemError errorMessage = error.get();
+ switch (errorMessage)
+ {
+ case FILE_ALREADY_EXISTS:
+ httpStatus = HEADER_STATUS_VALUE_409;
+ break;
+ case FILE_MODIFIED:
+ httpStatus = HEADER_STATUS_VALUE_412;
+ break;
+ case FILE_TAG_MISSING:
+ httpStatus = HEADER_STATUS_VALUE_428;
+ break;
+ default:
+ httpStatus = HEADER_STATUS_VALUE_404;
+ break;
+ }
+ }
+ else
+ {
+ httpStatus = HEADER_STATUS_VALUE_404;
+ }
+
+ HttpResetExFW resetEx = httpResetExRW.wrap(extBuffer, 0, extBuffer.capacity())
+ .typeId(httpTypeId)
+ .headersItem(h -> h.name(HEADER_STATUS_NAME).value(httpStatus))
+ .headersItem(h -> h.name(HEADER_CONTENT_LENGTH_NAME).value("0"))
+ .build();
+
+ doReset(http, originId, routedId, initialId, initialSeq, initialAck, initialMax, traceId, resetEx);
}
}
}
@@ -542,6 +622,18 @@ private void doFileSystemBegin(
traceId, authorization, affinity, resolved);
}
+ private void doFileSystemData(
+ long traceId,
+ long authorization,
+ long budgetId,
+ int reserved,
+ int flags,
+ Flyweight payload)
+ {
+ doData(filesystem, originId, routedId, initialId, initialSeq, initialAck, initialMax,
+ traceId, authorization, budgetId, flags, reserved, payload);
+ }
+
private void doFileSystemEnd(
long traceId,
long sequence,
@@ -645,13 +737,31 @@ private void onFileSystemBegin(
{
final HttpBeginExFW.Builder httpBeginExBuilder =
httpBeginExRW.wrap(extBuffer, 0, extBuffer.capacity())
- .typeId(httpTypeId)
- .headersItem(h -> h.name(HEADER_STATUS_NAME).value(getStatus(fsBeginEx)))
+ .typeId(httpTypeId);
+ final boolean validTag = tag != null ? tag.length() != -1 && tag.asString() != null : false;
+
+ int capabilities = fsBeginEx.capabilities();
+ if (createOrWritePayload(capabilities) && validTag)
+ {
+ httpBeginExBuilder.headersItem(h -> h.name(HEADER_STATUS_NAME).value(HEADER_STATUS_VALUE_204))
+ .headersItem(h -> h.name(HEADER_ETAG_NAME).value(tag))
+ .headersItem(h -> h.name(HEADER_CONTENT_LENGTH_NAME).value("0"));
+ }
+ else if ((capabilities & DELETE_PAYLOAD_MASK) != 0)
+ {
+ httpBeginExBuilder.headersItem(h -> h.name(HEADER_STATUS_NAME).value(HEADER_STATUS_VALUE_204))
+ .headersItem(h -> h.name(HEADER_CONTENT_LENGTH_NAME).value("0"));
+ }
+ else
+ {
+ httpBeginExBuilder.headersItem(h -> h.name(HEADER_STATUS_NAME).value(getStatus(fsBeginEx)))
.headersItem(h -> h.name(HEADER_CONTENT_TYPE_NAME).value(type))
.headersItem(h -> h.name(HEADER_CONTENT_LENGTH_NAME).value(length));
- if (tag.length() != -1 && tag.asString() != null)
- {
- httpBeginExBuilder.headersItem(h -> h.name(HEADER_ETAG_NAME).value(tag));
+
+ if (validTag)
+ {
+ httpBeginExBuilder.headersItem(h -> h.name(HEADER_ETAG_NAME).value(tag));
+ }
}
httpBeginEx = httpBeginExBuilder.build();
}
@@ -675,6 +785,12 @@ private boolean canReadPayload(
return (capabilities & READ_PAYLOAD_MASK) != 0;
}
+ private boolean createOrWritePayload(
+ int capabilities)
+ {
+ return (capabilities & CREATE_PAYLOAD_MASK) != 0 || (capabilities & WRITE_PAYLOAD_MASK) != 0;
+ }
+
private void onFileSystemData(
DataFW data)
{
@@ -794,6 +910,9 @@ private void onFileSystemReset(
final long sequence = reset.sequence();
final long acknowledge = reset.acknowledge();
final long traceId = reset.traceId();
+ final OctetsFW extension = reset.extension();
+ final FileSystemResetExFW resetEx = extension.get(fsResetExRO::tryWrap);
+ final FileSystemErrorFW error = resetEx != null ? resetEx.error() : null;
assert acknowledge <= sequence;
assert acknowledge >= delegate.initialAck;
@@ -802,7 +921,7 @@ private void onFileSystemReset(
assert delegate.initialAck <= delegate.initialSeq;
- delegate.doHttpReset(traceId);
+ delegate.doHttpReset(traceId, error);
}
private void doFileSystemReset(
@@ -813,7 +932,7 @@ private void doFileSystemReset(
state = HttpFileSystemState.closeReply(state);
doReset(filesystem, originId, routedId, replyId, replySeq, replyAck, replyMax,
- traceId);
+ traceId, EMPTY_EXTENSION);
}
}
@@ -1055,7 +1174,8 @@ private void doReset(
long sequence,
long acknowledge,
int maximum,
- long traceId)
+ long traceId,
+ Flyweight extension)
{
final ResetFW reset = resetRW.wrap(writeBuffer, 0, writeBuffer.capacity())
.originId(originId)
@@ -1065,6 +1185,7 @@ private void doReset(
.acknowledge(acknowledge)
.maximum(maximum)
.traceId(traceId)
+ .extension(extension.buffer(), extension.offset(), extension.sizeof())
.build();
sender.accept(reset.typeId(), reset.buffer(), reset.offset(), reset.sizeof());
diff --git a/runtime/binding-http-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyIT.java b/runtime/binding-http-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyIT.java
index a6eb5bea95..ae8ca7ba1d 100644
--- a/runtime/binding-http-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyIT.java
+++ b/runtime/binding-http-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/http/filesystem/internal/stream/HttpFileSystemProxyIT.java
@@ -127,15 +127,6 @@ public void shouldRejectClientWithNoBinding() throws Exception
k3po.finish();
}
- @Test
- @Configuration("proxy.with.path.yaml")
- @Specification({
- "${http}/client.write.file.rejected/client"})
- public void shouldRejectClientWriteFile() throws Exception
- {
- k3po.finish();
- }
-
@Test
@Specification({
"${http}/client.rejected/client"})
@@ -203,4 +194,64 @@ public void shouldReceiveClientSentAbort() throws Exception
{
k3po.finish();
}
+
+ @Test
+ @Configuration("proxy.with.path.yaml")
+ @Specification({
+ "${http}/client.create.file/client",
+ "${filesystem}/client.create.file/server"})
+ public void shouldReceiveClientCreateFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("proxy.with.path.yaml")
+ @Specification({
+ "${http}/client.create.existing.file.failed/client",
+ "${filesystem}/client.create.existing.file.failed/server"})
+ public void shouldRejectClientCreateExistingFileFailed() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("proxy.with.path.yaml")
+ @Specification({
+ "${http}/client.write.file/client",
+ "${filesystem}/client.write.file/server"})
+ public void shouldReceiveClientWriteFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("proxy.with.path.yaml")
+ @Specification({
+ "${http}/client.write.file.failed/client",
+ "${filesystem}/client.write.file.failed/server"})
+ public void shouldRejectClientWriteFileFailed() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("proxy.with.path.yaml")
+ @Specification({
+ "${http}/client.delete.file/client",
+ "${filesystem}/client.delete.file/server"})
+ public void shouldReceiveClientDeleteFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Configuration("proxy.with.path.yaml")
+ @Specification({
+ "${http}/client.delete.non.existent.file/client",
+ "${filesystem}/client.delete.non.existent.file/server"})
+ public void shouldRejectClientDeleteNonExistentFile() throws Exception
+ {
+ k3po.finish();
+ }
}
diff --git a/runtime/binding-http-kafka/pom.xml b/runtime/binding-http-kafka/pom.xml
index be1324a96d..74c9b142ff 100644
--- a/runtime/binding-http-kafka/pom.xml
+++ b/runtime/binding-http-kafka/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-http/pom.xml b/runtime/binding-http/pom.xml
index b9c5d5afb1..98653f951c 100644
--- a/runtime/binding-http/pom.xml
+++ b/runtime/binding-http/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java
index df9f1e66b2..a555b65e25 100644
--- a/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java
+++ b/runtime/binding-http/src/main/java/io/aklivity/zilla/runtime/binding/http/internal/stream/HttpServerFactory.java
@@ -2946,7 +2946,13 @@ private void onRequestReset(
else
{
responseState = HttpExchangeState.CLOSED;
- doEncodeHeaders(this, traceId, authorization, 0L, headers404);
+
+ OctetsFW extension = reset.extension();
+ HttpResetExFW httpResetEx = extension.get(resetExRO::tryWrap);
+ Array32FW headers = httpResetEx != null && !httpResetEx.headers().isEmpty() ?
+ httpResetEx.headers() : headers404;
+
+ doEncodeHeaders(this, traceId, authorization, 0L, headers);
}
requestState = HttpExchangeState.CLOSED;
diff --git a/runtime/binding-kafka-grpc/pom.xml b/runtime/binding-kafka-grpc/pom.xml
index 61dd5406d6..c7cbdf322c 100644
--- a/runtime/binding-kafka-grpc/pom.xml
+++ b/runtime/binding-kafka-grpc/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-kafka/pom.xml b/runtime/binding-kafka/pom.xml
index 4f946a3f28..09cc06a7da 100644
--- a/runtime/binding-kafka/pom.xml
+++ b/runtime/binding-kafka/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-mqtt-kafka/pom.xml b/runtime/binding-mqtt-kafka/pom.xml
index 24934a373b..7e95d0a6bd 100644
--- a/runtime/binding-mqtt-kafka/pom.xml
+++ b/runtime/binding-mqtt-kafka/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-mqtt/pom.xml b/runtime/binding-mqtt/pom.xml
index 7cac568b0d..9640c30464 100644
--- a/runtime/binding-mqtt/pom.xml
+++ b/runtime/binding-mqtt/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-openapi-asyncapi/pom.xml b/runtime/binding-openapi-asyncapi/pom.xml
index cb40fbe4aa..9ad02a63aa 100644
--- a/runtime/binding-openapi-asyncapi/pom.xml
+++ b/runtime/binding-openapi-asyncapi/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-openapi/pom.xml b/runtime/binding-openapi/pom.xml
index 4287677ad8..144105af04 100644
--- a/runtime/binding-openapi/pom.xml
+++ b/runtime/binding-openapi/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-proxy/pom.xml b/runtime/binding-proxy/pom.xml
index acd03897c5..2e9805495e 100644
--- a/runtime/binding-proxy/pom.xml
+++ b/runtime/binding-proxy/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-sse-kafka/pom.xml b/runtime/binding-sse-kafka/pom.xml
index f46d9ed0f6..a911873e88 100644
--- a/runtime/binding-sse-kafka/pom.xml
+++ b/runtime/binding-sse-kafka/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-sse/pom.xml b/runtime/binding-sse/pom.xml
index 3a92903cdc..2093d8e466 100644
--- a/runtime/binding-sse/pom.xml
+++ b/runtime/binding-sse/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-tcp/pom.xml b/runtime/binding-tcp/pom.xml
index cdfc9955a1..5ed5df3ecc 100644
--- a/runtime/binding-tcp/pom.xml
+++ b/runtime/binding-tcp/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-tls/pom.xml b/runtime/binding-tls/pom.xml
index bb3362daa0..cf941f57c4 100644
--- a/runtime/binding-tls/pom.xml
+++ b/runtime/binding-tls/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/binding-ws/pom.xml b/runtime/binding-ws/pom.xml
index 8bfcb7b0b2..435347d3eb 100644
--- a/runtime/binding-ws/pom.xml
+++ b/runtime/binding-ws/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/catalog-apicurio/pom.xml b/runtime/catalog-apicurio/pom.xml
index d1c8da4dbf..12b4fff986 100644
--- a/runtime/catalog-apicurio/pom.xml
+++ b/runtime/catalog-apicurio/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/catalog-filesystem/pom.xml b/runtime/catalog-filesystem/pom.xml
index 86394f1eed..5ea8177679 100644
--- a/runtime/catalog-filesystem/pom.xml
+++ b/runtime/catalog-filesystem/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/catalog-inline/pom.xml b/runtime/catalog-inline/pom.xml
index 57ddeabb2f..657f18ecdb 100644
--- a/runtime/catalog-inline/pom.xml
+++ b/runtime/catalog-inline/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/catalog-karapace/pom.xml b/runtime/catalog-karapace/pom.xml
index a23271f8ef..c90f0121fc 100644
--- a/runtime/catalog-karapace/pom.xml
+++ b/runtime/catalog-karapace/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/catalog-schema-registry/pom.xml b/runtime/catalog-schema-registry/pom.xml
index 4c0eab0ee8..2e76bf1510 100644
--- a/runtime/catalog-schema-registry/pom.xml
+++ b/runtime/catalog-schema-registry/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/command-metrics/pom.xml b/runtime/command-metrics/pom.xml
index 8a2ec96b92..39016d0658 100644
--- a/runtime/command-metrics/pom.xml
+++ b/runtime/command-metrics/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/command-start/pom.xml b/runtime/command-start/pom.xml
index cdca72e6b2..2a2d45e3ef 100644
--- a/runtime/command-start/pom.xml
+++ b/runtime/command-start/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/command-stop/pom.xml b/runtime/command-stop/pom.xml
index 09d2fa861d..575cfa711b 100644
--- a/runtime/command-stop/pom.xml
+++ b/runtime/command-stop/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/command-version/pom.xml b/runtime/command-version/pom.xml
index e70500d099..3c33c6171f 100644
--- a/runtime/command-version/pom.xml
+++ b/runtime/command-version/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/command/pom.xml b/runtime/command/pom.xml
index 4b42d8b3ee..2ef2183558 100644
--- a/runtime/command/pom.xml
+++ b/runtime/command/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/command/src/main/moditect/module-info.java b/runtime/command/src/main/moditect/module-info.java
index 7da848a3f1..ba2fd89714 100644
--- a/runtime/command/src/main/moditect/module-info.java
+++ b/runtime/command/src/main/moditect/module-info.java
@@ -20,5 +20,8 @@
exports io.aklivity.zilla.runtime.command;
+ opens io.aklivity.zilla.runtime.command
+ to com.github.rvesse.airline;
+
uses io.aklivity.zilla.runtime.command.ZillaCommandSpi;
}
diff --git a/runtime/common/pom.xml b/runtime/common/pom.xml
index ad0396d521..201b875dc3 100644
--- a/runtime/common/pom.xml
+++ b/runtime/common/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/engine/pom.xml b/runtime/engine/pom.xml
index edb47c4d1a..88c2d69d71 100644
--- a/runtime/engine/pom.xml
+++ b/runtime/engine/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/exporter-otlp/pom.xml b/runtime/exporter-otlp/pom.xml
index 318bec06e4..574921afcb 100644
--- a/runtime/exporter-otlp/pom.xml
+++ b/runtime/exporter-otlp/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/exporter-prometheus/pom.xml b/runtime/exporter-prometheus/pom.xml
index 7c27a32a0e..1172dc1784 100644
--- a/runtime/exporter-prometheus/pom.xml
+++ b/runtime/exporter-prometheus/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/exporter-stdout/pom.xml b/runtime/exporter-stdout/pom.xml
index 5405382631..0627149712 100644
--- a/runtime/exporter-stdout/pom.xml
+++ b/runtime/exporter-stdout/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/filesystem-http/pom.xml b/runtime/filesystem-http/pom.xml
index 4c670f2a61..4afb5073c1 100644
--- a/runtime/filesystem-http/pom.xml
+++ b/runtime/filesystem-http/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/guard-jwt/pom.xml b/runtime/guard-jwt/pom.xml
index 4b1f4b4af1..c939d76ba7 100644
--- a/runtime/guard-jwt/pom.xml
+++ b/runtime/guard-jwt/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/metrics-grpc/pom.xml b/runtime/metrics-grpc/pom.xml
index ba15b1119c..267b1f2cd9 100644
--- a/runtime/metrics-grpc/pom.xml
+++ b/runtime/metrics-grpc/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/metrics-http/pom.xml b/runtime/metrics-http/pom.xml
index d825f3cf03..d27d037715 100644
--- a/runtime/metrics-http/pom.xml
+++ b/runtime/metrics-http/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/metrics-stream/pom.xml b/runtime/metrics-stream/pom.xml
index 2026e8d9ae..1faf5f1710 100644
--- a/runtime/metrics-stream/pom.xml
+++ b/runtime/metrics-stream/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/model-avro/pom.xml b/runtime/model-avro/pom.xml
index 9b73efa81d..d0a22df000 100644
--- a/runtime/model-avro/pom.xml
+++ b/runtime/model-avro/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/model-core/pom.xml b/runtime/model-core/pom.xml
index b6916157df..b621f17131 100644
--- a/runtime/model-core/pom.xml
+++ b/runtime/model-core/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/model-json/pom.xml b/runtime/model-json/pom.xml
index 5e4a51de5d..8249584133 100644
--- a/runtime/model-json/pom.xml
+++ b/runtime/model-json/pom.xml
@@ -6,7 +6,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/model-protobuf/pom.xml b/runtime/model-protobuf/pom.xml
index ee5050fa8b..2e653a6270 100644
--- a/runtime/model-protobuf/pom.xml
+++ b/runtime/model-protobuf/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/pom.xml b/runtime/pom.xml
index 3d0198b1ba..d5195973b3 100644
--- a/runtime/pom.xml
+++ b/runtime/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/resolver-env/pom.xml b/runtime/resolver-env/pom.xml
index c661e89137..2b47442cb5 100644
--- a/runtime/resolver-env/pom.xml
+++ b/runtime/resolver-env/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/runtime/vault-filesystem/pom.xml b/runtime/vault-filesystem/pom.xml
index bdc30fed1b..4ca9794fea 100644
--- a/runtime/vault-filesystem/pom.xml
+++ b/runtime/vault-filesystem/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
runtime
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-asyncapi.spec/pom.xml b/specs/binding-asyncapi.spec/pom.xml
index 2d216204a2..ff15eeb666 100644
--- a/specs/binding-asyncapi.spec/pom.xml
+++ b/specs/binding-asyncapi.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-echo.spec/pom.xml b/specs/binding-echo.spec/pom.xml
index 349641c90a..7ed9f4dee7 100644
--- a/specs/binding-echo.spec/pom.xml
+++ b/specs/binding-echo.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-fan.spec/pom.xml b/specs/binding-fan.spec/pom.xml
index 19947e144a..255f3356c9 100644
--- a/specs/binding-fan.spec/pom.xml
+++ b/specs/binding-fan.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-filesystem.spec/pom.xml b/specs/binding-filesystem.spec/pom.xml
index 4a2a6b0f7a..ad76c39ad4 100644
--- a/specs/binding-filesystem.spec/pom.xml
+++ b/specs/binding-filesystem.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
@@ -24,7 +24,7 @@
- 1.00
+ 0.99
0
diff --git a/specs/binding-filesystem.spec/src/main/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctions.java b/specs/binding-filesystem.spec/src/main/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctions.java
index a3aefda2bb..0aefa37ac4 100644
--- a/specs/binding-filesystem.spec/src/main/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctions.java
+++ b/specs/binding-filesystem.spec/src/main/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctions.java
@@ -26,6 +26,9 @@
import io.aklivity.k3po.runtime.lang.el.spi.FunctionMapperSpi;
import io.aklivity.zilla.specs.binding.filesystem.internal.types.FileSystemCapabilities;
import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemBeginExFW;
+import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemError;
+import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemErrorFW;
+import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemResetExFW;
public final class FileSystemFunctions
{
@@ -35,12 +38,24 @@ public static FileSystemBeginExBuilder beginEx()
return new FileSystemBeginExBuilder();
}
+ @Function
+ public static FileSystemResetExBuilder resetEx()
+ {
+ return new FileSystemResetExBuilder();
+ }
+
@Function
public static FileSystemBeginExMatcherBuilder matchBeginEx()
{
return new FileSystemBeginExMatcherBuilder();
}
+ @Function
+ public static FileSystemResetExMatcherBuilder matchResetEx()
+ {
+ return new FileSystemResetExMatcherBuilder();
+ }
+
public static final class FileSystemBeginExBuilder
{
private final FileSystemBeginExFW.Builder beginExRW;
@@ -256,6 +271,105 @@ private boolean matchTimeout(
}
}
+ public static final class FileSystemResetExBuilder
+ {
+ private final FileSystemResetExFW.Builder resetExRW;
+ private final FileSystemErrorFW.Builder errorExRW;
+
+ private FileSystemResetExBuilder()
+ {
+ MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[1024 * 8]);
+ this.resetExRW = new FileSystemResetExFW.Builder().wrap(writeBuffer, 0, writeBuffer.capacity());
+ MutableDirectBuffer errorBuffer = new UnsafeBuffer(new byte[1]);
+ this.errorExRW = new FileSystemErrorFW.Builder().wrap(errorBuffer, 0, errorBuffer.capacity());
+ }
+
+ public FileSystemResetExBuilder typeId(
+ int typeId)
+ {
+ resetExRW.typeId(typeId);
+ return this;
+ }
+
+ public FileSystemResetExBuilder error(
+ String error)
+ {
+ resetExRW.error(errorExRW.set(FileSystemError.valueOf(error)).build());
+ return this;
+ }
+
+ public byte[] build()
+ {
+ final FileSystemResetExFW resetEx = resetExRW.build();
+ final byte[] array = new byte[resetEx.sizeof()];
+ resetEx.buffer().getBytes(resetEx.offset(), array);
+ return array;
+ }
+ }
+
+ public static final class FileSystemResetExMatcherBuilder
+ {
+ private final DirectBuffer bufferRO = new UnsafeBuffer();
+
+ private final FileSystemResetExFW resetExRO = new FileSystemResetExFW();
+
+ private Integer typeId;
+ private String error;
+
+ public FileSystemResetExMatcherBuilder typeId(
+ int typeId)
+ {
+ this.typeId = typeId;
+ return this;
+ }
+
+ public FileSystemResetExMatcherBuilder error(
+ String error)
+ {
+ this.error = error;
+ return this;
+ }
+
+ public BytesMatcher build()
+ {
+ return typeId != null ? this::match : buf -> null;
+ }
+
+ private FileSystemResetExFW match(
+ ByteBuffer byteBuf) throws Exception
+ {
+ if (!byteBuf.hasRemaining())
+ {
+ return null;
+ }
+
+ bufferRO.wrap(byteBuf);
+ final FileSystemResetExFW resetEx = resetExRO.tryWrap(bufferRO, byteBuf.position(), byteBuf.capacity());
+
+ if (resetEx != null &&
+ matchTypeId(resetEx) &&
+ matchError(resetEx))
+ {
+ byteBuf.position(byteBuf.position() + resetEx.sizeof());
+ return resetEx;
+ }
+
+ throw new Exception(resetEx.toString());
+ }
+
+ private boolean matchTypeId(
+ FileSystemResetExFW resetEx)
+ {
+ return typeId == resetEx.typeId();
+ }
+
+ private boolean matchError(
+ FileSystemResetExFW resetEx)
+ {
+ return error == null || error.equals(resetEx.error().get().name());
+ }
+ }
+
public static class Mapper extends FunctionMapperSpi.Reflective
{
public Mapper()
diff --git a/specs/binding-filesystem.spec/src/main/resources/META-INF/zilla/filesystem.idl b/specs/binding-filesystem.spec/src/main/resources/META-INF/zilla/filesystem.idl
index a63c84e4ee..92552c2e5a 100644
--- a/specs/binding-filesystem.spec/src/main/resources/META-INF/zilla/filesystem.idl
+++ b/specs/binding-filesystem.spec/src/main/resources/META-INF/zilla/filesystem.idl
@@ -18,11 +18,22 @@ scope filesystem
{
READ_PAYLOAD,
READ_EXTENSION,
- READ_CHANGES
+ READ_CHANGES,
+ CREATE_PAYLOAD,
+ WRITE_PAYLOAD,
+ DELETE_PAYLOAD
}
scope stream
{
+ enum FileSystemError
+ {
+ FILE_NOT_FOUND,
+ FILE_ALREADY_EXISTS,
+ FILE_MODIFIED,
+ FILE_TAG_MISSING
+ }
+
struct FileSystemBeginEx extends core::stream::Extension
{
int32 capabilities = 3;
@@ -32,5 +43,10 @@ scope filesystem
string16 tag = null;
int64 timeout = 0;
}
+
+ struct FileSystemResetEx extends core::stream::Extension
+ {
+ FileSystemError error;
+ }
}
}
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/create.file.payload/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/create.file.payload/client.rpt
new file mode 100644
index 0000000000..d89504515a
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/create.file.payload/client.rpt
@@ -0,0 +1,44 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index_write.html")
+ .type("text/html")
+ .payloadSize(77)
+ .build()}
+connected
+
+write "\n"
+ "Welcome\n"
+ "Hello, world\n"
+ "\n"
+write flush
+
+write close
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index_write.html")
+ .tag("f2c912a30f38a124c3249f8e802e0d90")
+ .build()}
+
+read closed
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/create.file.payload/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/create.file.payload/server.rpt
new file mode 100644
index 0000000000..dcde111481
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/create.file.payload/server.rpt
@@ -0,0 +1,46 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index_write.html")
+ .type("text/html")
+ .payloadSize(77)
+ .build()}
+connected
+
+read "\n"
+ "Welcome\n"
+ "Hello, world\n"
+ "\n"
+
+read closed
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index_write.html")
+ .tag("f2c912a30f38a124c3249f8e802e0d90")
+ .build()}
+
+write flush
+
+write close
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload.failed/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload.failed/client.rpt
new file mode 100644
index 0000000000..bdcba4d477
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload.failed/client.rpt
@@ -0,0 +1,25 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("error.html")
+ .build()}
+connect aborted
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.rejected/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload.failed/server.rpt
similarity index 95%
rename from specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.rejected/server.rpt
rename to specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload.failed/server.rpt
index 2d35ef0843..67d4f2732e 100644
--- a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.rejected/server.rpt
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload.failed/server.rpt
@@ -13,8 +13,7 @@
# specific language governing permissions and limitations under the License.
#
-accept "zilla://streams/http0"
+accept "zilla://streams/app0"
option zilla:window 8192
option zilla:transmission "half-duplex"
-
rejected
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload/client.rpt
new file mode 100644
index 0000000000..cb15ded6c1
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload/client.rpt
@@ -0,0 +1,35 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("error.html")
+ .build()}
+connected
+
+write close
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("error.html")
+ .build()}
+
+read closed
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload/server.rpt
new file mode 100644
index 0000000000..4e68418642
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/delete.file.payload/server.rpt
@@ -0,0 +1,38 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("error.html")
+ .build()}
+connected
+
+read closed
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("error.html")
+ .build()}
+
+write flush
+
+write close
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.etag.not.matched/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.tag.not.matched/client.rpt
similarity index 100%
rename from specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.etag.not.matched/client.rpt
rename to specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.tag.not.matched/client.rpt
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.etag.not.matched/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.tag.not.matched/server.rpt
similarity index 100%
rename from specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.etag.not.matched/server.rpt
rename to specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.tag.not.matched/server.rpt
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.interrupt/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.interrupt/client.rpt
new file mode 100644
index 0000000000..4ec9492625
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.interrupt/client.rpt
@@ -0,0 +1,40 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index_write.html")
+ .type("text/html")
+ .payloadSize(77)
+ .tag("f2c912a30f38a124c3249f8e802e0d90")
+ .build()}
+connected
+
+write option zilla:flags "init"
+write "\n"
+ "Welcome\n"
+write flush
+
+write option zilla:flags "none"
+write "Hello, user\n"
+ "\n"
+write flush
+
+write abort
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.interrupt/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.interrupt/server.rpt
new file mode 100644
index 0000000000..bb4fc7a573
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.interrupt/server.rpt
@@ -0,0 +1,39 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index_write.html")
+ .type("text/html")
+ .payloadSize(77)
+ .tag("f2c912a30f38a124c3249f8e802e0d90")
+ .build()}
+connected
+
+read option zilla:flags "init"
+read "\n"
+ "Welcome\n"
+
+read option zilla:flags "none"
+read "Hello, user\n"
+ "\n"
+
+read aborted
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified.abort/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified.abort/client.rpt
new file mode 100644
index 0000000000..5629cebb52
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified.abort/client.rpt
@@ -0,0 +1,29 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index_write.html")
+ .type("text/html")
+ .payloadSize(77)
+ .tag("INIT")
+ .build()}
+
+connect aborted
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified.abort/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified.abort/server.rpt
new file mode 100644
index 0000000000..67d4f2732e
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified.abort/server.rpt
@@ -0,0 +1,19 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+rejected
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified/client.rpt
new file mode 100644
index 0000000000..23def1fa23
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified/client.rpt
@@ -0,0 +1,45 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index_write.html")
+ .type("text/html")
+ .payloadSize(77)
+ .tag("f2c912a30f38a124c3249f8e802e0d90")
+ .build()}
+connected
+
+write "\n"
+ "Welcome\n"
+ "Hello, Zilla\n"
+ "\n"
+write flush
+
+write close
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index_write.html")
+ .tag("c3ce2fda552e43985939a773852f45d1")
+ .build()}
+
+read closed
diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified/server.rpt
new file mode 100644
index 0000000000..d849c8305e
--- /dev/null
+++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/write.file.payload.modified/server.rpt
@@ -0,0 +1,47 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/app0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index_write.html")
+ .type("text/html")
+ .payloadSize(77)
+ .tag("f2c912a30f38a124c3249f8e802e0d90")
+ .build()}
+connected
+
+read "\n"
+ "Welcome\n"
+ "Hello, Zilla\n"
+ "\n"
+
+read closed
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index_write.html")
+ .tag("c3ce2fda552e43985939a773852f45d1")
+ .build()}
+
+write flush
+
+write close
diff --git a/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctionsTest.java b/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctionsTest.java
index aa194bc977..a983bdf236 100644
--- a/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctionsTest.java
+++ b/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/internal/FileSystemFunctionsTest.java
@@ -34,6 +34,9 @@
import io.aklivity.k3po.runtime.lang.el.BytesMatcher;
import io.aklivity.k3po.runtime.lang.internal.el.ExpressionContext;
import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemBeginExFW;
+import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemError;
+import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemErrorFW;
+import io.aklivity.zilla.specs.binding.filesystem.internal.types.stream.FileSystemResetExFW;
public class FileSystemFunctionsTest
{
@@ -354,4 +357,89 @@ public void shouldNotMatchBeginExtensionWhenBufferOverflow() throws Exception
assertNull(matcher.match(byteBuf));
}
+
+ @Test
+ public void shouldGenerateResetExtension()
+ {
+ byte[] build = FileSystemFunctions.resetEx()
+ .typeId(0x01)
+ .error("FILE_MODIFIED")
+ .build();
+
+ DirectBuffer buffer = new UnsafeBuffer(build);
+ FileSystemResetExFW resetEx = new FileSystemResetExFW().wrap(buffer, 0, buffer.capacity());
+
+ assertEquals(0x01, resetEx.typeId());
+ assertEquals(FileSystemError.FILE_MODIFIED, resetEx.error().get());
+ }
+
+ @Test
+ public void shouldMatchResetExtension() throws Exception
+ {
+ BytesMatcher matcher = FileSystemFunctions.matchResetEx()
+ .typeId(0x01)
+ .error("FILE_MODIFIED")
+ .build();
+
+ ByteBuffer byteBuf = ByteBuffer.allocate(1024);
+
+ new FileSystemResetExFW.Builder().wrap(new UnsafeBuffer(byteBuf), 0, byteBuf.capacity())
+ .typeId(0x01)
+ .error(new FileSystemErrorFW.Builder().wrap(new UnsafeBuffer(new byte[1]), 0, 1)
+ .set(FileSystemError.FILE_MODIFIED).build())
+ .build();
+
+ assertNotNull(matcher.match(byteBuf));
+ }
+
+ @Test(expected = Exception.class)
+ public void shouldNotMatchResetExtensionWhenErrorDiffers() throws Exception
+ {
+ BytesMatcher matcher = FileSystemFunctions.matchResetEx()
+ .typeId(0x01)
+ .error("FILE_MODIFIED")
+ .build();
+
+ ByteBuffer byteBuf = ByteBuffer.allocate(1024);
+
+ new FileSystemResetExFW.Builder().wrap(new UnsafeBuffer(byteBuf), 0, byteBuf.capacity())
+ .typeId(0x01)
+ .error(new FileSystemErrorFW.Builder().wrap(new UnsafeBuffer(new byte[1]), 0, 1)
+ .set(FileSystemError.FILE_NOT_FOUND).build())
+ .build();
+
+ assertNotNull(matcher.match(byteBuf));
+ }
+
+ @Test(expected = Exception.class)
+ public void shouldNotMatchResetExtensionWhenTypeIdDiffers() throws Exception
+ {
+ BytesMatcher matcher = FileSystemFunctions.matchResetEx()
+ .typeId(0x01)
+ .error("FILE_MODIFIED")
+ .build();
+
+ ByteBuffer byteBuf = ByteBuffer.allocate(1024);
+
+ new FileSystemResetExFW.Builder().wrap(new UnsafeBuffer(byteBuf), 0, byteBuf.capacity())
+ .typeId(0x02)
+ .error(new FileSystemErrorFW.Builder().wrap(new UnsafeBuffer(new byte[1]), 0, 1)
+ .set(FileSystemError.FILE_NOT_FOUND).build())
+ .build();
+
+ assertNotNull(matcher.match(byteBuf));
+ }
+
+ @Test
+ public void shouldNotMatchResetExtensionWhenBufferOverflow() throws Exception
+ {
+ BytesMatcher matcher = FileSystemFunctions.matchResetEx()
+ .typeId(0x01)
+ .error("FILE_MODIFIED")
+ .build();
+
+ ByteBuffer byteBuf = ByteBuffer.allocate(0);
+
+ assertNull(matcher.match(byteBuf));
+ }
}
diff --git a/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java b/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java
index cec8c92bca..93e9443973 100644
--- a/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java
+++ b/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java
@@ -98,10 +98,10 @@ public void shouldReadFilePayloadModifiedMultiClient() throws Exception
@Test
@Specification({
- "${app}/read.file.payload.etag.not.matched/client",
- "${app}/read.file.payload.etag.not.matched/server"
+ "${app}/read.file.payload.tag.not.matched/client",
+ "${app}/read.file.payload.tag.not.matched/server"
})
- public void shouldReadFilePayloadEtagNotMatched() throws Exception
+ public void shouldReadFilePayloadTagNotMatched() throws Exception
{
k3po.finish();
}
@@ -165,4 +165,64 @@ public void shouldReceiveClientReadAbort() throws Exception
{
k3po.finish();
}
+
+ @Test
+ @Specification({
+ "${app}/create.file.payload/client",
+ "${app}/create.file.payload/server",
+ })
+ public void shouldCreateFilePayloadOnly() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${app}/write.file.payload.modified/client",
+ "${app}/write.file.payload.modified/server",
+ })
+ public void shouldWriteFilePayloadModified() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${app}/write.file.payload.modified.abort/client",
+ "${app}/write.file.payload.modified.abort/server",
+ })
+ public void shouldWriteFilePayloadModifiedAbort() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${app}/write.file.payload.interrupt/client",
+ "${app}/write.file.payload.interrupt/server",
+ })
+ public void shouldWriteFilePayloadInterrupt() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${app}/delete.file.payload/client",
+ "${app}/delete.file.payload/server",
+ })
+ public void shouldDeleteFilePayloadOnly() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${app}/delete.file.payload.failed/client",
+ "${app}/delete.file.payload.failed/server",
+ })
+ public void shouldDeleteFilePayloadFailed() throws Exception
+ {
+ k3po.finish();
+ }
}
diff --git a/specs/binding-grpc-kafka.spec/pom.xml b/specs/binding-grpc-kafka.spec/pom.xml
index ccb12bcd6d..ebdda97608 100644
--- a/specs/binding-grpc-kafka.spec/pom.xml
+++ b/specs/binding-grpc-kafka.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-grpc.spec/pom.xml b/specs/binding-grpc.spec/pom.xml
index fa8f79c323..7537b3b94d 100644
--- a/specs/binding-grpc.spec/pom.xml
+++ b/specs/binding-grpc.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-http-filesystem.spec/pom.xml b/specs/binding-http-filesystem.spec/pom.xml
index d14482003d..c8a4ba1ce3 100644
--- a/specs/binding-http-filesystem.spec/pom.xml
+++ b/specs/binding-http-filesystem.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.existing.file.failed/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.existing.file.failed/client.rpt
new file mode 100644
index 0000000000..00ecd03acf
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.existing.file.failed/client.rpt
@@ -0,0 +1,32 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+read zilla:reset.ext ${filesystem:resetEx()
+ .typeId(zilla:id("filesystem"))
+ .error("FILE_ALREADY_EXISTS")
+ .build()}
+
+write aborted
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.existing.file.failed/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.existing.file.failed/server.rpt
new file mode 100644
index 0000000000..788bbdfa6f
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.existing.file.failed/server.rpt
@@ -0,0 +1,33 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+write zilla:reset.ext ${filesystem:resetEx()
+ .typeId(zilla:id("filesystem"))
+ .error("FILE_ALREADY_EXISTS")
+ .build()}
+
+read abort
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.file/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.file/client.rpt
new file mode 100644
index 0000000000..c1010cdb66
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.file/client.rpt
@@ -0,0 +1,42 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+write "\n"
+ "Welcome\n"
+ "Hello, world\n"
+ "\n"
+write flush
+
+write close
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index.html")
+ .tag("c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+
+read closed
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.file/server.rpt
new file mode 100644
index 0000000000..097d446b9d
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.create.file/server.rpt
@@ -0,0 +1,43 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+read "\n"
+ "Welcome\n"
+ "Hello, world\n"
+ "\n"
+
+read closed
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("CREATE_PAYLOAD")
+ .path("index.html")
+ .tag("c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+write flush
+
+write close
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.file/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.file/client.rpt
new file mode 100644
index 0000000000..29c8d68272
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.file/client.rpt
@@ -0,0 +1,35 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+write close
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("index.html")
+ .build()}
+
+read closed
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.file/server.rpt
new file mode 100644
index 0000000000..b76b292bcd
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.file/server.rpt
@@ -0,0 +1,37 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+read closed
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("index.html")
+ .build()}
+write flush
+
+write close
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.non.existent.file/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.non.existent.file/client.rpt
new file mode 100644
index 0000000000..6f801aeeb9
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.non.existent.file/client.rpt
@@ -0,0 +1,32 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+read zilla:reset.ext ${filesystem:resetEx()
+ .typeId(zilla:id("filesystem"))
+ .error("FILE_NOT_FOUND")
+ .build()}
+
+write aborted
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.non.existent.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.non.existent.file/server.rpt
new file mode 100644
index 0000000000..7a0da09e1c
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.delete.non.existent.file/server.rpt
@@ -0,0 +1,33 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("DELETE_PAYLOAD")
+ .path("index.html")
+ .build()}
+connected
+
+write zilla:reset.ext ${filesystem:resetEx()
+ .typeId(zilla:id("filesystem"))
+ .error("FILE_NOT_FOUND")
+ .build()}
+
+read abort
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file.failed/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file.failed/client.rpt
new file mode 100644
index 0000000000..35c3b0c8ca
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file.failed/client.rpt
@@ -0,0 +1,33 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index.html")
+ .tag("c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+connected
+
+read zilla:reset.ext ${filesystem:resetEx()
+ .typeId(zilla:id("filesystem"))
+ .error("FILE_MODIFIED")
+ .build()}
+
+write aborted
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file.failed/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file.failed/server.rpt
new file mode 100644
index 0000000000..ffa9df505d
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file.failed/server.rpt
@@ -0,0 +1,34 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index.html")
+ .tag("c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+connected
+
+write zilla:reset.ext ${filesystem:resetEx()
+ .typeId(zilla:id("filesystem"))
+ .error("FILE_MODIFIED")
+ .build()}
+
+read abort
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file/client.rpt
new file mode 100644
index 0000000000..36860eb001
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file/client.rpt
@@ -0,0 +1,43 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index.html")
+ .tag("c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+connected
+
+write "\n"
+ "Welcome\n"
+ "Hello, zilla\n"
+ "\n"
+write flush
+
+write close
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index.html")
+ .tag("c3ce2fda552e43985939a773852f45d1")
+ .build()}
+
+read closed
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file/server.rpt
new file mode 100644
index 0000000000..c6844cf4dc
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/filesystem/client.write.file/server.rpt
@@ -0,0 +1,44 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/filesystem0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${filesystem:matchBeginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index.html")
+ .tag("c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+connected
+
+read "\n"
+ "Welcome\n"
+ "Hello, zilla\n"
+ "\n"
+
+read closed
+
+write zilla:begin.ext ${filesystem:beginEx()
+ .typeId(zilla:id("filesystem"))
+ .capabilities("WRITE_PAYLOAD")
+ .path("index.html")
+ .tag("c3ce2fda552e43985939a773852f45d1")
+ .build()}
+write flush
+
+write close
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.existing.file.failed/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.existing.file.failed/client.rpt
new file mode 100644
index 0000000000..715d592d5d
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.existing.file.failed/client.rpt
@@ -0,0 +1,36 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .build()}
+
+connected
+
+read zilla:reset.ext ${http:resetEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "409")
+ .header("content-length", "0")
+ .build()}
+
+write aborted
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.existing.file.failed/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.existing.file.failed/server.rpt
new file mode 100644
index 0000000000..3d6fc6c537
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.existing.file.failed/server.rpt
@@ -0,0 +1,37 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .build()}
+
+connected
+
+write zilla:reset.ext ${http:resetEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "409")
+ .header("content-length", "0")
+ .build()}
+
+read abort
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.file/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.file/client.rpt
new file mode 100644
index 0000000000..4fe70d3200
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.file/client.rpt
@@ -0,0 +1,45 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .build()}
+
+connected
+
+write "\n"
+ "Welcome\n"
+ "Hello, world\n"
+ "\n"
+
+write flush
+
+write close
+
+read zilla:begin.ext ${http:matchBeginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "204")
+ .header("etag", "c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+
+read closed
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.file/server.rpt
new file mode 100644
index 0000000000..015c0251d8
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.create.file/server.rpt
@@ -0,0 +1,46 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "POST")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .build()}
+
+connected
+
+read "\n"
+ "Welcome\n"
+ "Hello, world\n"
+ "\n"
+
+read closed
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "204")
+ .header("etag", "c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+
+write flush
+
+write close
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.rejected/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.file/client.rpt
similarity index 78%
rename from specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.rejected/client.rpt
rename to specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.file/client.rpt
index 7812934074..23ed0c6862 100644
--- a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.rejected/client.rpt
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.file/client.rpt
@@ -19,10 +19,19 @@ connect "zilla://streams/http0"
write zilla:begin.ext ${http:beginEx()
.typeId(zilla:id("http"))
- .header(":method", "PUT")
+ .header(":method", "DELETE")
.header(":scheme", "https")
.header(":authority", "example.com:9090")
.header(":path", "/index.html")
.build()}
-connect aborted
+connected
+
+write close
+
+read zilla:begin.ext ${http:matchBeginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "204")
+ .build()}
+
+read closed
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.file/server.rpt
new file mode 100644
index 0000000000..1b92656275
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.file/server.rpt
@@ -0,0 +1,40 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "DELETE")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .build()}
+
+connected
+
+read closed
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "204")
+ .build()}
+
+write flush
+
+write close
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.non.existent.file/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.non.existent.file/client.rpt
new file mode 100644
index 0000000000..af83c5ffdd
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.non.existent.file/client.rpt
@@ -0,0 +1,36 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "DELETE")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .build()}
+
+connected
+
+read zilla:reset.ext ${http:resetEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "404")
+ .header("content-length", "0")
+ .build()}
+
+write aborted
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.non.existent.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.non.existent.file/server.rpt
new file mode 100644
index 0000000000..07e32869aa
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.delete.non.existent.file/server.rpt
@@ -0,0 +1,37 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "DELETE")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .build()}
+
+connected
+
+write zilla:reset.ext ${http:resetEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "404")
+ .header("content-length", "0")
+ .build()}
+
+read abort
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.failed/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.failed/client.rpt
new file mode 100644
index 0000000000..60e407af96
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.failed/client.rpt
@@ -0,0 +1,37 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "PUT")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .header("if-match", "c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+
+connected
+
+read zilla:reset.ext ${http:resetEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "412")
+ .header("content-length", "0")
+ .build()}
+
+write aborted
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.failed/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.failed/server.rpt
new file mode 100644
index 0000000000..7d924c7f8d
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file.failed/server.rpt
@@ -0,0 +1,38 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "PUT")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .header("if-match", "c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+
+connected
+
+write zilla:reset.ext ${http:resetEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "412")
+ .header("content-length", "0")
+ .build()}
+
+read abort
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file/client.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file/client.rpt
new file mode 100644
index 0000000000..3363f7374d
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file/client.rpt
@@ -0,0 +1,46 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+connect "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "PUT")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .header("if-match", "c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+
+connected
+
+write "\n"
+ "Welcome\n"
+ "Hello, zilla\n"
+ "\n"
+
+write flush
+
+write close
+
+read zilla:begin.ext ${http:matchBeginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "204")
+ .header("etag", "c3ce2fda552e43985939a773852f45d1")
+ .build()}
+
+read closed
diff --git a/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file/server.rpt b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file/server.rpt
new file mode 100644
index 0000000000..bdb232346a
--- /dev/null
+++ b/specs/binding-http-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/filesystem/streams/http/client.write.file/server.rpt
@@ -0,0 +1,47 @@
+#
+# Copyright 2021-2024 Aklivity Inc
+#
+# Licensed under the Aklivity Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# https://www.aklivity.io/aklivity-community-license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+accept "zilla://streams/http0"
+ option zilla:window 8192
+ option zilla:transmission "half-duplex"
+accepted
+
+read zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":method", "PUT")
+ .header(":scheme", "https")
+ .header(":authority", "example.com:9090")
+ .header(":path", "/index.html")
+ .header("if-match", "c7183509522eb56e5cf927a3b2e8c15a")
+ .build()}
+
+connected
+
+read "\n"
+ "Welcome\n"
+ "Hello, zilla\n"
+ "\n"
+
+read closed
+
+write zilla:begin.ext ${http:beginEx()
+ .typeId(zilla:id("http"))
+ .header(":status", "204")
+ .header("etag", "c3ce2fda552e43985939a773852f45d1")
+ .build()}
+
+write flush
+
+write close
diff --git a/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/FileSystemIT.java b/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/FileSystemIT.java
index 53fd4faa3d..fc5b9b4b3f 100644
--- a/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/FileSystemIT.java
+++ b/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/FileSystemIT.java
@@ -116,4 +116,58 @@ public void shouldReceiveClientSentAbort() throws Exception
{
k3po.finish();
}
+
+ @Test
+ @Specification({
+ "${filesystem}/client.create.file/client",
+ "${filesystem}/client.create.file/server"})
+ public void shouldReceiveClientCreateFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${filesystem}/client.create.existing.file.failed/client",
+ "${filesystem}/client.create.existing.file.failed/server"})
+ public void shouldRejectClientCreateExistingFileFailed() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${filesystem}/client.write.file/client",
+ "${filesystem}/client.write.file/server"})
+ public void shouldReceiveClientWriteFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${filesystem}/client.write.file.failed/client",
+ "${filesystem}/client.write.file.failed/server"})
+ public void shouldRejectClientWriteFileFailed() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${filesystem}/client.delete.file/client",
+ "${filesystem}/client.delete.file/server"})
+ public void shouldReceiveClientDeleteFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${filesystem}/client.delete.non.existent.file/client",
+ "${filesystem}/client.delete.non.existent.file/server"})
+ public void shouldRejectClientDeleteNonExistentFile() throws Exception
+ {
+ k3po.finish();
+ }
}
diff --git a/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/HttpIT.java b/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/HttpIT.java
index 321d2d9fa7..173d9892c1 100644
--- a/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/HttpIT.java
+++ b/specs/binding-http-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/http/filesystem/streams/HttpIT.java
@@ -91,15 +91,6 @@ public void shouldRejectClient() throws Exception
k3po.finish();
}
- @Test
- @Specification({
- "${http}/client.write.file.rejected/client",
- "${http}/client.write.file.rejected/server"})
- public void shouldRejectClientWriteFile() throws Exception
- {
- k3po.finish();
- }
-
@Test
@Specification({
"${http}/client.sent.message/client",
@@ -153,4 +144,58 @@ public void shouldReceiveServerSentFlush() throws Exception
{
k3po.finish();
}
+
+ @Test
+ @Specification({
+ "${http}/client.create.file/client",
+ "${http}/client.create.file/server"})
+ public void shouldReceiveClientCreateFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${http}/client.create.existing.file.failed/client",
+ "${http}/client.create.existing.file.failed/server"})
+ public void shouldRejectClientCreateExistingFileFailed() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${http}/client.write.file/client",
+ "${http}/client.write.file/server"})
+ public void shouldReceiveClientWriteFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${http}/client.write.file.failed/client",
+ "${http}/client.write.file.failed/server"})
+ public void shouldRejectClientWriteFileFailed() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${http}/client.delete.file/client",
+ "${http}/client.delete.file/server"})
+ public void shouldReceiveClientDeleteFile() throws Exception
+ {
+ k3po.finish();
+ }
+
+ @Test
+ @Specification({
+ "${http}/client.delete.non.existent.file/client",
+ "${http}/client.delete.non.existent.file/server"})
+ public void shouldRejectClientDeleteNonExistentFile() throws Exception
+ {
+ k3po.finish();
+ }
}
diff --git a/specs/binding-http-kafka.spec/pom.xml b/specs/binding-http-kafka.spec/pom.xml
index 4d4cd176b1..c28ccc70eb 100644
--- a/specs/binding-http-kafka.spec/pom.xml
+++ b/specs/binding-http-kafka.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-http.spec/pom.xml b/specs/binding-http.spec/pom.xml
index 7f6f2d2194..e245e0384b 100644
--- a/specs/binding-http.spec/pom.xml
+++ b/specs/binding-http.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json
index eeea350d26..f6e0ab13ee 100644
--- a/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json
+++ b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json
@@ -125,7 +125,7 @@
"max-age":
{
"title": "Max Age",
- "type": "number"
+ "type": "integer"
},
"expose":
{
diff --git a/specs/binding-kafka-grpc.spec/pom.xml b/specs/binding-kafka-grpc.spec/pom.xml
index 23b867f4cf..12535eb1be 100644
--- a/specs/binding-kafka-grpc.spec/pom.xml
+++ b/specs/binding-kafka-grpc.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-kafka.spec/pom.xml b/specs/binding-kafka.spec/pom.xml
index 65ae4e7d2f..cf2f892ef7 100644
--- a/specs/binding-kafka.spec/pom.xml
+++ b/specs/binding-kafka.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-mqtt-kafka.spec/pom.xml b/specs/binding-mqtt-kafka.spec/pom.xml
index e26b35f6f5..d8324acb85 100644
--- a/specs/binding-mqtt-kafka.spec/pom.xml
+++ b/specs/binding-mqtt-kafka.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-mqtt.spec/pom.xml b/specs/binding-mqtt.spec/pom.xml
index ed3a438415..a90e0e509a 100644
--- a/specs/binding-mqtt.spec/pom.xml
+++ b/specs/binding-mqtt.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-openapi-asyncapi.spec/pom.xml b/specs/binding-openapi-asyncapi.spec/pom.xml
index 14dd0bcd87..49e673d360 100644
--- a/specs/binding-openapi-asyncapi.spec/pom.xml
+++ b/specs/binding-openapi-asyncapi.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-openapi.spec/pom.xml b/specs/binding-openapi.spec/pom.xml
index ec2fe1fd09..be8232669a 100644
--- a/specs/binding-openapi.spec/pom.xml
+++ b/specs/binding-openapi.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-proxy.spec/pom.xml b/specs/binding-proxy.spec/pom.xml
index 49042e963c..1b8f815623 100644
--- a/specs/binding-proxy.spec/pom.xml
+++ b/specs/binding-proxy.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-sse-kafka.spec/pom.xml b/specs/binding-sse-kafka.spec/pom.xml
index b8ea1c998a..9601407f3a 100644
--- a/specs/binding-sse-kafka.spec/pom.xml
+++ b/specs/binding-sse-kafka.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-sse.spec/pom.xml b/specs/binding-sse.spec/pom.xml
index 2258a02e6f..aad98861fe 100644
--- a/specs/binding-sse.spec/pom.xml
+++ b/specs/binding-sse.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-tcp.spec/pom.xml b/specs/binding-tcp.spec/pom.xml
index 3699f8bad4..5c7ca49557 100644
--- a/specs/binding-tcp.spec/pom.xml
+++ b/specs/binding-tcp.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-tls.spec/pom.xml b/specs/binding-tls.spec/pom.xml
index 772bf77710..5e21e375d3 100644
--- a/specs/binding-tls.spec/pom.xml
+++ b/specs/binding-tls.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/binding-ws.spec/pom.xml b/specs/binding-ws.spec/pom.xml
index 3d966c07b5..e702d44da6 100644
--- a/specs/binding-ws.spec/pom.xml
+++ b/specs/binding-ws.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/catalog-apicurio.spec/pom.xml b/specs/catalog-apicurio.spec/pom.xml
index aba69d357c..118c11cb77 100644
--- a/specs/catalog-apicurio.spec/pom.xml
+++ b/specs/catalog-apicurio.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/schema/apicurio.schema.patch.json b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/schema/apicurio.schema.patch.json
index 08c12003e4..bb818a4534 100644
--- a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/schema/apicurio.schema.patch.json
+++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/schema/apicurio.schema.patch.json
@@ -60,7 +60,7 @@
"max-age":
{
"title": "Max Age",
- "type": "number",
+ "type": "integer",
"default": 300
}
},
diff --git a/specs/catalog-filesystem.spec/pom.xml b/specs/catalog-filesystem.spec/pom.xml
index 7d994c0668..f5b0800be2 100644
--- a/specs/catalog-filesystem.spec/pom.xml
+++ b/specs/catalog-filesystem.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/catalog-inline.spec/pom.xml b/specs/catalog-inline.spec/pom.xml
index 505ae9c74c..62c5786978 100644
--- a/specs/catalog-inline.spec/pom.xml
+++ b/specs/catalog-inline.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/catalog-karapace.spec/pom.xml b/specs/catalog-karapace.spec/pom.xml
index f02148acca..e1ec9375ea 100644
--- a/specs/catalog-karapace.spec/pom.xml
+++ b/specs/catalog-karapace.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/catalog-schema-registry.spec/pom.xml b/specs/catalog-schema-registry.spec/pom.xml
index 8f6fc7edce..22f20330da 100644
--- a/specs/catalog-schema-registry.spec/pom.xml
+++ b/specs/catalog-schema-registry.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json b/specs/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json
index db1c8c1990..72d6557b3e 100644
--- a/specs/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json
+++ b/specs/catalog-schema-registry.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/schema/registry/schema/schema.registry.schema.patch.json
@@ -57,7 +57,7 @@
"max-age":
{
"title": "Max Age",
- "type": "number",
+ "type": "integer",
"default": 300
}
},
diff --git a/specs/engine.spec/pom.xml b/specs/engine.spec/pom.xml
index 7958b70e83..532cea667f 100644
--- a/specs/engine.spec/pom.xml
+++ b/specs/engine.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/exporter-otlp.spec/pom.xml b/specs/exporter-otlp.spec/pom.xml
index dafef1733e..ccddae2ea3 100644
--- a/specs/exporter-otlp.spec/pom.xml
+++ b/specs/exporter-otlp.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/exporter-prometheus.spec/pom.xml b/specs/exporter-prometheus.spec/pom.xml
index 8788912132..01c386985d 100644
--- a/specs/exporter-prometheus.spec/pom.xml
+++ b/specs/exporter-prometheus.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/exporter-stdout.spec/pom.xml b/specs/exporter-stdout.spec/pom.xml
index f657201c4a..6692fa331e 100644
--- a/specs/exporter-stdout.spec/pom.xml
+++ b/specs/exporter-stdout.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/filesystem-http.spec/pom.xml b/specs/filesystem-http.spec/pom.xml
index c9e21800d7..0ad611ae9f 100644
--- a/specs/filesystem-http.spec/pom.xml
+++ b/specs/filesystem-http.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/guard-jwt.spec/pom.xml b/specs/guard-jwt.spec/pom.xml
index eedc0ae028..016fb9d57a 100644
--- a/specs/guard-jwt.spec/pom.xml
+++ b/specs/guard-jwt.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/metrics-grpc.spec/pom.xml b/specs/metrics-grpc.spec/pom.xml
index 30ebd29c6f..bfdb7861a8 100644
--- a/specs/metrics-grpc.spec/pom.xml
+++ b/specs/metrics-grpc.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/metrics-http.spec/pom.xml b/specs/metrics-http.spec/pom.xml
index 6ae5a77e2a..811b1af52a 100644
--- a/specs/metrics-http.spec/pom.xml
+++ b/specs/metrics-http.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/metrics-stream.spec/pom.xml b/specs/metrics-stream.spec/pom.xml
index 9b0ada37f1..cdff74f2be 100644
--- a/specs/metrics-stream.spec/pom.xml
+++ b/specs/metrics-stream.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/model-avro.spec/pom.xml b/specs/model-avro.spec/pom.xml
index 402f25e3df..e9daccea39 100644
--- a/specs/model-avro.spec/pom.xml
+++ b/specs/model-avro.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/model-core.spec/pom.xml b/specs/model-core.spec/pom.xml
index b53c075ea2..5e7dc665d9 100644
--- a/specs/model-core.spec/pom.xml
+++ b/specs/model-core.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/model-json.spec/pom.xml b/specs/model-json.spec/pom.xml
index 6d8a93eb54..f6061229f2 100644
--- a/specs/model-json.spec/pom.xml
+++ b/specs/model-json.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/model-protobuf.spec/pom.xml b/specs/model-protobuf.spec/pom.xml
index 1adddb5f8f..906f30f3b4 100644
--- a/specs/model-protobuf.spec/pom.xml
+++ b/specs/model-protobuf.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/pom.xml b/specs/pom.xml
index 3da140f230..948eff683e 100644
--- a/specs/pom.xml
+++ b/specs/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
zilla
- 0.9.100
+ 0.9.101
../pom.xml
diff --git a/specs/vault-filesystem.spec/pom.xml b/specs/vault-filesystem.spec/pom.xml
index f7bbc74ffd..8c5c47e355 100644
--- a/specs/vault-filesystem.spec/pom.xml
+++ b/specs/vault-filesystem.spec/pom.xml
@@ -8,7 +8,7 @@
io.aklivity.zilla
specs
- 0.9.100
+ 0.9.101
../pom.xml