Skip to content

Instantly share code, notes, and snippets.

@blixt
Created April 24, 2016 03:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blixt/67eb81d7b6ff2f0b03470d536c9379e5 to your computer and use it in GitHub Desktop.
Save blixt/67eb81d7b6ff2f0b03470d536c9379e5 to your computer and use it in GitHub Desktop.
The multipart reader hangs instead of returning the available parts.
package main
import (
"fmt"
"io"
"math"
"math/rand"
"mime/multipart"
"time"
)
// A reader class that replicates the behavior of a long-lived socket.
type DummyReader struct {
data []byte
offset int
funnel chan []byte
}
func NewDummyReader(data []byte) *DummyReader {
return &DummyReader{data: data, offset: 0, funnel: make(chan []byte)}
}
func (dr *DummyReader) flush(n int) {
time.Sleep(10 * time.Millisecond)
diff := len(dr.data) - dr.offset
if diff <= 0 {
return
}
pre := dr.offset
dr.offset += int(math.Min(float64(rand.Intn(n)+1), float64(diff)))
dr.funnel <- dr.data[pre:dr.offset]
}
func (dr *DummyReader) Read(p []byte) (n int, err error) {
go dr.flush(32)
data, ok := <-dr.funnel
if !ok {
return 0, io.EOF
}
copy(p, data)
return len(data), nil
}
const DATA = "\r\n--test123\r\nContent-Type: text/plain\r\n\r\nHello World\r\n--test123\r\n\r\nAnother one\r\n--test123--\r\n"
func main() {
fmt.Println("First, let's read normally:")
dr1 := NewDummyReader([]byte(DATA))
go func() {
// Quick hack to move on to the second example.
time.Sleep(1 * time.Second)
close(dr1.funnel)
}()
buf := make([]byte, 1024)
for {
n, err := dr1.Read(buf)
if err != nil {
break
}
fmt.Printf("Got %d byte(s): %#v\n", n, string(buf[:n]))
}
fmt.Println()
fmt.Println("Now hand the same to multipart.Reader:")
dr2 := NewDummyReader([]byte(DATA))
mr := multipart.NewReader(dr2, "test123")
fmt.Println("Created multipart reader")
for {
p, err := mr.NextPart()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Got a part, header:", p.Header)
for {
in := make([]byte, 1024)
n, err := p.Read(in)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Read something from the part:", n, string(in))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment