mirror of
https://github.com/versity/versitygw.git
synced 2025-12-23 13:15:18 +00:00
102 lines
3.0 KiB
Go
102 lines
3.0 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
type PayloadChunked struct {
|
|
*Payload
|
|
chunkSize int64
|
|
getReaderFunc func() (io.Reader, error)
|
|
addSignatureFunc func(chunk []byte, outFile *os.File) error
|
|
addTrailerFunc func(outFile *os.File) error
|
|
}
|
|
|
|
func (c *PayloadChunked) getChunkedPayloadContentLength(additionalChunkHeaderSize, additionalTrailerSize int64) (int64, error) {
|
|
payloadSize, err := c.Payload.GetDataSize()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("error getting payload data size: %w", err)
|
|
}
|
|
var sizeIdx int64
|
|
var contentLength int64
|
|
for sizeIdx = 0; sizeIdx < payloadSize; sizeIdx += c.chunkSize {
|
|
var endIdx int64
|
|
if sizeIdx+c.chunkSize < payloadSize {
|
|
endIdx = sizeIdx + c.chunkSize
|
|
} else {
|
|
endIdx = payloadSize
|
|
}
|
|
hexSize := fmt.Sprintf("%x", endIdx-sizeIdx)
|
|
contentLength += int64(len(hexSize)) + additionalChunkHeaderSize + (endIdx - sizeIdx) + 2
|
|
}
|
|
contentLength += 1 + additionalTrailerSize
|
|
return contentLength, nil
|
|
}
|
|
|
|
func (c *PayloadChunked) writeChunkedPayload(filePath string) error {
|
|
defer func() {
|
|
c.dataSource.Close()
|
|
}()
|
|
outFile, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0600)
|
|
if err != nil {
|
|
return fmt.Errorf("error writing to file: %w", err)
|
|
}
|
|
br, err := c.getReaderFunc()
|
|
if err != nil {
|
|
return fmt.Errorf("error getting data reader: %w", err)
|
|
}
|
|
payloadBuffer := make([]byte, c.chunkSize)
|
|
for {
|
|
var bytesRead int
|
|
if bytesRead, err = c.addChunk(br, payloadBuffer, outFile); err != nil {
|
|
return fmt.Errorf("error adding chunk: %w", err)
|
|
}
|
|
if bytesRead == 0 {
|
|
break
|
|
}
|
|
}
|
|
if _, err = outFile.Write([]byte{'0'}); err != nil {
|
|
return fmt.Errorf("error writing \\r\\n: %w", err)
|
|
}
|
|
if err = c.addSignatureFunc(nil, outFile); err != nil {
|
|
return fmt.Errorf("error adding signature: %w", err)
|
|
}
|
|
if err = c.addTrailerFunc(outFile); err != nil {
|
|
return fmt.Errorf("error adding trailer: %w", err)
|
|
}
|
|
if _, err = outFile.Write([]byte{'\r', '\n', '\r', '\n'}); err != nil {
|
|
return fmt.Errorf("error writing \\r\\n: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *PayloadChunked) addChunk(reader io.Reader, payloadBuffer []byte, outFile *os.File) (int, error) {
|
|
var bytesRead int
|
|
bytesRead, err := reader.Read(payloadBuffer)
|
|
if err != nil && err != io.EOF {
|
|
return 0, fmt.Errorf("error reading bytes: %w", err)
|
|
}
|
|
if bytesRead == 0 {
|
|
return 0, nil
|
|
}
|
|
hexString := fmt.Sprintf("%x", bytesRead)
|
|
if _, err = outFile.Write([]byte(hexString)); err != nil {
|
|
return 0, fmt.Errorf("error writing hex string: %w", err)
|
|
}
|
|
if err = c.addSignatureFunc(payloadBuffer[:bytesRead], outFile); err != nil {
|
|
return 0, fmt.Errorf("error adding signature: %w", err)
|
|
}
|
|
if _, err = outFile.Write([]byte{'\r', '\n'}); err != nil {
|
|
return 0, fmt.Errorf("error writing \\r\\n: %w", err)
|
|
}
|
|
if _, err = outFile.Write(payloadBuffer[:bytesRead]); err != nil {
|
|
return 0, fmt.Errorf("error writing bytes to file: %w", err)
|
|
}
|
|
if _, err = outFile.Write([]byte{'\r', '\n'}); err != nil {
|
|
return 0, fmt.Errorf("error writing \\r\\n: %w", err)
|
|
}
|
|
return bytesRead, nil
|
|
}
|