Skip to content

Instantly share code, notes, and snippets.

@cryptix
Created June 22, 2014 11:09
Show Gist options
  • Save cryptix/9dd094008b6236f4fc57 to your computer and use it in GitHub Desktop.
Save cryptix/9dd094008b6236f4fc57 to your computer and use it in GitHub Desktop.
multipart upload with io.Pipe
package main
import (
"io"
"log"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"runtime"
"github.com/cheggaaa/pb"
)
func main() {
if len(os.Args) != 2 {
log.Println("Usage: pipeUp <filename>\n")
os.Exit(1)
}
input, err := os.Open(os.Args[1])
check(err)
defer input.Close()
stat, err := input.Stat()
check(err)
pipeOut, pipeIn := io.Pipe()
fsize := stat.Size()
bar := pb.New(int(fsize)).SetUnits(pb.U_BYTES)
bar.ShowSpeed = true
writer := multipart.NewWriter(pipeIn)
// do the request concurrently
var resp *http.Response
done := make(chan error)
go func() {
// prepare request
req, err := http.NewRequest("POST", "http://localhost:9000/upload", pipeOut)
if err != nil {
done <- err
return
}
req.ContentLength = fsize // filesize
req.ContentLength += 227 // multipart header exclouding filename
req.ContentLength += int64(len(os.Args[1]))
req.ContentLength += 19
req.Header.Set("Content-Type", writer.FormDataContentType())
log.Println("Created Request")
bar.Start()
resp, err = http.DefaultClient.Do(req)
if err != nil {
done <- err
return
}
done <- nil
}()
part, err := writer.CreateFormFile("file", filepath.Base(os.Args[1]))
check(err)
out := io.MultiWriter(part, bar)
_, err = io.Copy(out, input)
check(err)
check(writer.Close())
check(pipeIn.Close()) // need to close the pipe to
check(<-done)
bar.FinishPrint("Upload done!")
}
func check(err error) {
_, file, line, _ := runtime.Caller(1)
if err != nil {
log.Fatalf("Fatal from <%s:%d>\nError:%s", file, line, err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment