[racket] "Streaming" gunzip-through-ports hangs?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Tue Jan 22 14:40:41 EST 2013

I'd like to take an input-port that I know has gzip encoded bytes, and
return a new input-port port that will return the decoded bytes. I
don't want to suck the entire bytes into memory. Instead I want to
"stream" them as-needed.

It _seems_ like I could do this is with a combination of `make-pipe`
and `gunzip-through-ports`.

But at the end, instead of getting `eof` the program hangs.

Does anyone see what I'm doing wrong?

#lang racket

(require file/gzip
         file/gunzip)

(provide gzip/bytes
         gunzip/bytes
         make-gzip-decoding-input-port
         make-gzip-encoding-input-port)

(define (gzip/bytes b)
  (define in (open-input-bytes b))
  (define out (open-output-bytes))
  (gzip-through-ports in out #f 0)
  (get-output-bytes out))

(define (gunzip/bytes b)
  (define in (open-input-bytes b))
  (define out (open-output-bytes))
  (gunzip-through-ports in out)
  (get-output-bytes out))

(module+ test
  (require rackunit)
  (let ([b #"0123456789"])
    (check-equal? (gunzip/bytes (gzip/bytes b)) b)))

(define (make-gzip-encoding-input-port in [limit #f])
  (define-values (pin pout) (make-pipe limit 'gzip-pipe 'gzip-pipe))
  (thread (lambda () (gzip-through-ports in pout)))
  pin)

(define (make-gzip-decoding-input-port in [limit #f])
  (define-values (pin pout) (make-pipe limit 'gunzip-pipe 'gunzip-pipe))
  (thread (lambda () (gunzip-through-ports in pout)))
  pin)

;; Try to use:
(define b (gzip/bytes #"abcde"))
(define in0 (open-input-bytes b))
(define in (make-gzip-decoding-input-port in0))
(read-bytes 5 in) ; => #"abcde"
(read-bytes 1 in) ; => hangs here (expected it to return `eof`)

Posted on the users mailing list.