Pass the spooled video file through instead of buffering it in RAM, and sign Spaces uploads as UNSIGNED-PAYLOAD so the client does not hash the body first. Reviewed-on: #23 Co-authored-by: codegirl-007 <s.raide@gmail.com>
This commit was merged in pull request #23.
This commit is contained in:
+22
-16
@@ -190,13 +190,14 @@ func (s *Server) uploadPostMedia(
|
||||
if err != nil {
|
||||
return store.PostImage{}, "", err
|
||||
}
|
||||
defer prepared.body.Close()
|
||||
mediaID := uuid.NewString()
|
||||
objectKey := path.Join("post-videos", postID, mediaID+prepared.extension)
|
||||
publicURL, err := s.cfg.Blob.Upload(ctx, blob.FileUpload{
|
||||
Key: objectKey,
|
||||
Body: bytes.NewReader(prepared.body),
|
||||
Body: prepared.body,
|
||||
ContentType: prepared.contentType,
|
||||
Size: int64(len(prepared.body)),
|
||||
Size: prepared.size,
|
||||
})
|
||||
if err != nil {
|
||||
return store.PostImage{}, "", &postImageRequestError{
|
||||
@@ -405,7 +406,8 @@ func isWebM(raw []byte) bool {
|
||||
}
|
||||
|
||||
type preparedPostVideo struct {
|
||||
body []byte
|
||||
body io.ReadCloser
|
||||
size int64
|
||||
extension string
|
||||
contentType string
|
||||
}
|
||||
@@ -414,6 +416,9 @@ func preparePostVideo(header *multipart.FileHeader) (preparedPostVideo, error) {
|
||||
if header == nil {
|
||||
return preparedPostVideo{}, invalidPostImage("Select a valid video.", nil)
|
||||
}
|
||||
if header.Size == 0 {
|
||||
return preparedPostVideo{}, invalidPostImage("Videos cannot be empty.", nil)
|
||||
}
|
||||
if header.Size > postVideoMaxFileBytes {
|
||||
return preparedPostVideo{}, &postImageRequestError{
|
||||
status: http.StatusRequestEntityTooLarge,
|
||||
@@ -424,27 +429,28 @@ func preparePostVideo(header *multipart.FileHeader) (preparedPostVideo, error) {
|
||||
if err != nil {
|
||||
return preparedPostVideo{}, invalidPostImage("Could not read video.", err)
|
||||
}
|
||||
defer file.Close()
|
||||
raw, err := io.ReadAll(io.LimitReader(file, postVideoMaxFileBytes+1))
|
||||
if err != nil {
|
||||
peek := make([]byte, 512)
|
||||
n, err := io.ReadFull(file, peek)
|
||||
if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) && !errors.Is(err, io.EOF) {
|
||||
file.Close()
|
||||
return preparedPostVideo{}, invalidPostImage("Could not read video.", err)
|
||||
}
|
||||
if len(raw) == 0 {
|
||||
if n == 0 {
|
||||
file.Close()
|
||||
return preparedPostVideo{}, invalidPostImage("Videos cannot be empty.", nil)
|
||||
}
|
||||
if int64(len(raw)) > postVideoMaxFileBytes {
|
||||
return preparedPostVideo{}, &postImageRequestError{
|
||||
status: http.StatusRequestEntityTooLarge,
|
||||
message: "Each video must be 25 MB or smaller.",
|
||||
}
|
||||
}
|
||||
switch mediaKindFromBytes(raw) {
|
||||
switch mediaKindFromBytes(peek[:n]) {
|
||||
case store.MediaKindVideo:
|
||||
default:
|
||||
file.Close()
|
||||
return preparedPostVideo{}, invalidPostImage("Videos must be MP4 or WebM.", nil)
|
||||
}
|
||||
result := preparedPostVideo{body: raw}
|
||||
if isWebM(raw) {
|
||||
if _, err := file.Seek(0, io.SeekStart); err != nil {
|
||||
file.Close()
|
||||
return preparedPostVideo{}, invalidPostImage("Could not read video.", err)
|
||||
}
|
||||
result := preparedPostVideo{body: file, size: header.Size}
|
||||
if isWebM(peek[:n]) {
|
||||
result.extension = ".webm"
|
||||
result.contentType = "video/webm"
|
||||
return result, nil
|
||||
|
||||
Reference in New Issue
Block a user