I am building a blob storage system and i picked Go as the programming language. I create a stream to do a multipart file upload from client to the blob server.
The stream works fine, but i want to make a sha1 hash from the request body. I need to io.Copy the body twice. The sha1 gets created but the multipart streams 0 bytes after that.
any idea how i can do this?
the client upload
func (c *Client) Upload(h *UploadHandle) (*PutResult, error) {
body, bodySize, err := h.Read()
if err != nil {
return nil, err
}
// Creating a sha1 hash from the bytes of body
dropRef, err := drop.Sha1FromReader(body)
if err != nil {
return nil, err
}
bodyReader, bodyWriter := io.Pipe()
writer := multipart.NewWriter(bodyWriter)
errChan := make(chan error, 1)
go func() {
defer bodyWriter.Close()
part, err := writer.CreateFormFile(dropRef, dropRef)
if err != nil {
errChan <- err
return
}
if _, err := io.Copy(part, body); err != nil {
errChan <- err
return
}
if err = writer.Close(); err != nil {
errChan <- err
}
}()
req, err := http.NewRequest("POST", c.Server+"/drops/upload", bodyReader)
req.Header.Add("Content-Type", writer.FormDataContentType())
resp, err := c.Do(req)
if err != nil {
return nil, err
}
.....
}
the sha1 func
func Sha1FromReader(src io.Reader) (string, error) {
hash := sha1.New()
_, err := io.Copy(hash, src)
if err != nil {
return "", err
}
return hex.EncodeToString(hash.Sum(nil)), nil
}
upload handle
func (h *UploadHandle) Read() (io.Reader, int64, error) {
var b bytes.Buffer
hw := &Hasher{&b, sha1.New()}
n, err := io.Copy(hw, h.Contents)
if err != nil {
return nil, 0, err
}
return &b, n, nil
}
Press the reset button on the back for 30 seconds to reset the Touch io reader.
To read the body of the response, we need to access its Body property first. We can access the Body property of a response using the ioutil. ReadAll() method. This method returns a body and an error.
I would suggest using an io.TeeReader
if you want to push all reads from the blob through the sha1 concurrently.
bodyReader := io.TeeReader(body, hash)
Now as the bodyReader is consumed during upload, the hash is automatically updated.
You have two options.
The most direct way is to use io.MultiWriter
.
But if you need the hash to produce the multipart output, then you will have to copy to a bytes.Buffer
and then write the buffer back to each writer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With