wordpress-mobile / wordpress-mobile/GutenbergKit

iOS: OutputStream.write return value 0 treated as fatal in bound stream writers

Open
#437 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug iOS
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

  1. RequestBody.makePipedFileSliceStreamios/Sources/GutenbergKitHTTP/RequestBody.swift (~line 236)
  2. DefaultMediaUploader.writeAllios/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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.