Repository navigation
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Multipart boundary handling can advertise a stale boundary and permit injected MIME parts, while reader validation and size-limit defects can leak streams or reject valid input.
6 open issues
Remove inherited parameters when replacing media type parameters · New Reject content beginning with a MIME boundary delimiter · New Validate boundary and size limit before acquiring the stream · New Look up MIME boundary parameters case-insensitively · New Avoid overflow when applying the delimiter size allowance · New Exclude the opening delimiter from the preamble size limit · New
What changed in this PR
Adds protocol-neutral streaming multipart support to Restlet core, providing a foundation for GraphQL incremental delivery without depending on GraphQL.
Changes:
- Adds a multipart writer that flushes each part with its trailing delimiter.
- Adds an iterator-based reader with bounded part sizes and multipart framing support.
- Introduces
MediaType.MULTIPART_MIXED, tests, and a changelog entry.
| File | Description |
|---|---|
org.restlet/src/test/java/org/restlet/representation/MultipartStreamTestCase.java |
Tests framing, validation, size limits, and HTTP streaming. |
org.restlet/src/main/java/org/restlet/representation/MultipartStreamRepresentation.java |
Produces and flushes multipart responses over time. |
org.restlet/src/main/java/org/restlet/representation/MultipartStreamReader.java |
Reads arriving parts with configurable size limits. |
org.restlet/src/main/java/org/restlet/data/MediaType.java |
Adds the MULTIPART_MIXED constant. |
changes.md |
Documents the new streaming APIs and media type. |
Review effort: Balanced
1ecffee to
c76a762
Compare
c76a762 to
5bb754a
Compare
|
Rebased onto 3.0 to resolve the changes.md conflict: its three commits were already on 3.0 as 7593588, 4760183 and d91cd7e (landed with the GraphQL incremental delivery stack, #1581), so the rebase dropped them all and GitHub closed this PR with no changes left. Nothing from it is missing on 3.0, including the review fixes and the #1587 changes.md entry. |
|





Closes #1587. Part of #1581 (prerequisite of GraphQL incremental delivery), but protocol-neutral.
Summary
MultiPartRepresentationparses or generates a known list of parts. Protocols whose responses are made of parts produced over time, such as GraphQL incremental delivery (@defer), need whatEventStreamRepresentationandEventStreamReaderprovide for SSE:MultipartStreamRepresentation(multipart/mixedby default, anymultipart/*type): thePartWriterruns on the connector's call thread. Each part is written followed by the next delimiter (\r\n--boundary) and flushed, so readers can process it at once without waiting for the following part. This is the framing used by GraphQL incremental delivery implementations. The close delimiter is written when the writer returns. Boundaries are generated unless given; the other parameters of the media type are kept (unlikeMultiPartRepresentation.setBoundary, which replaces them).PartSink.sendthrowsIllegalArgumentExceptionwhen the content contains the delimiter. Protocols may use short fixed boundaries such as-, so data must not be able to forge parts.MultipartStreamReader: anIterator<MultiPartRepresentation.Part>andAutoCloseablethat returns each part once its closing delimiter arrives. The preamble, epilogue and transport padding are ignored, and a leading delimiter without line break is accepted. Delimiters are found with a Knuth-Morris-Pratt search, so content resembling the delimiter is preserved. Headers plus content are bounded bymaxPartSize(anIOException, never truncation), and so is the preamble. Part content is aByteArrayRepresentationtyped from the part'sContent-Type.MediaType.MULTIPART_MIXED.Validation
./mvnw -B verify -P default,test -pl org.restlet: 2,221 tests, 0 failures; 82.3% instruction coverage (gate 80%); SpotBugs at 8 findings (ratchet 9, unchanged); Spotless and Javadoc pass. Re-ran the static checks and the new test after the last change (media type parameters).MultipartStreamTestCase(6 tests): exact wire format of parts and of an empty stream; round trip of binary content and of content resembling the delimiter; preamble, epilogue and padding; malformed and oversized streams (no delimiter, bad delimiter line, truncated headers or content, invalid header, part, header line and preamble limits); validation (non-multipart type, invalid boundary, header injection, delimiter in content, send after close, media type parameters); an HTTP round trip where the first part is read while the server is still waiting to write the second.🤖 Generated with Claude Code