wordpress-mobile / wordpress-mobile/GutenbergKit
iOS: OutputStream.write return value 0 treated as fatal in bound stream writers
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 29
- Forks
- 6
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 41
Description
Summary
The writeAll pattern used in bound-stream-pair writers treats OutputStream.write(_:maxLength:) returning 0 as a fatal error. Apple's documentation defines a 0 return as "a fixed-length stream has reached its capacity." It is unclear whether a bound stream pair (from Stream.getBoundStreams(withBufferSize:)) qualifies as a "fixed-length stream," meaning write() could return 0 when the internal buffer is full rather than blocking.
If 0 is returned as a backpressure signal, the current code silently aborts the write, closes the stream, and leaves URLSession waiting for Content-Length bytes that never arrive — causing the upload to hang.
Locations
RequestBody.makePipedFileSliceStream—ios/Sources/GutenbergKitHTTP/RequestBody.swift(~line 236)DefaultMediaUploader.writeAll—ios/Sources/GutenbergKit/Sources/Media/MediaUploadServer.swift(introduced in #419, same pattern)
Both use:
let result = output.write(base.advanced(by: written), maxLength: ...)
if result <= 0 { return }
Apple documentation
OutputStream.write(_:maxLength:): returns 0 for "a fixed-length stream that has reached its capacity"CFWriteStreamWrite: "If the stream is not full, this call blocks until at least one byte is written"- Neither document explicitly states whether bound stream pairs block or return 0 when the buffer is full
Suggested fix
Distinguish 0 (retry) from -1 (error):
if result == -1 { return false }
if result == 0 {
Thread.sleep(forTimeInterval: 0.001)
continue
}
Risk
Low probability in practice — uploads would need to outpace URLSession's read rate long enough to fill the 65KB buffer. More likely with large files on slow connections.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with RequestBody.makePipedFileSliceStream in ios/Sources/GutenbergKitHTTP/RequestBody.swift and DefaultMediaUploader.writeAll in ios/Sources/GutenbergKit/Sources/Media/MediaUploadServer.swift. Read how each handles OutputStream.write(_:maxLength:) results, then verify that a zero return does not abort an upload while a negative return still does. Done means both bound-stream writers handle the documented return cases consistently without leaving URLSession waiting for bytes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100