Created
April 24, 2016 03:49
-
-
Save blixt/67eb81d7b6ff2f0b03470d536c9379e5 to your computer and use it in GitHub Desktop.
The multipart reader hangs instead of returning the available parts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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