gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 73e9cca7019c15a92cb4cd320034652590513198
parent 55ad6dee716112e1a6c95cd53af0680ab3e8679a
Author: tobi <31960611+tsmethurst@users.noreply.github.com>
Date:   Mon, 21 Mar 2022 13:41:44 +0100

[bugfix] Close ReadClosers properly in the media package (#434)

* defer lock reader

* close readers when finished with them

* close the reader in the teereader when finished
Diffstat:
Minternal/media/processingemoji.go | 17++++++++++-------
Minternal/media/processingmedia.go | 27+++++++++++++++++++--------
Minternal/processing/media/getfile.go | 12+++++++++---
Minternal/processing/media/util.go | 14++++++++++++++
4 files changed, 52 insertions(+), 18 deletions(-)

diff --git a/internal/media/processingemoji.go b/internal/media/processingemoji.go @@ -29,6 +29,7 @@ import ( "time" "codeberg.org/gruf/go-store/kv" + "github.com/sirupsen/logrus" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/uris" @@ -169,6 +170,15 @@ func (p *ProcessingEmoji) store(ctx context.Context) error { return fmt.Errorf("store: error executing data function: %s", err) } + // defer closing the reader when we're done with it + defer func() { + if rc, ok := reader.(io.ReadCloser); ok { + if err := rc.Close(); err != nil { + logrus.Errorf("store: error closing readcloser: %s", err) + } + } + }() + // extract no more than 261 bytes from the beginning of the file -- this is the header firstBytes := make([]byte, maxFileHeaderBytes) if _, err := reader.Read(firstBytes); err != nil { @@ -205,13 +215,6 @@ func (p *ProcessingEmoji) store(ctx context.Context) error { return fmt.Errorf("store: error storing stream: %s", err) } - // if the original reader is a readcloser, close it since we're done with it now - if rc, ok := reader.(io.ReadCloser); ok { - if err := rc.Close(); err != nil { - return fmt.Errorf("store: error closing readcloser: %s", err) - } - } - p.read = true if p.postData != nil { diff --git a/internal/media/processingmedia.go b/internal/media/processingmedia.go @@ -29,6 +29,7 @@ import ( "time" "codeberg.org/gruf/go-store/kv" + "github.com/sirupsen/logrus" terminator "github.com/superseriousbusiness/exif-terminator" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" @@ -260,6 +261,15 @@ func (p *ProcessingMedia) store(ctx context.Context) error { return fmt.Errorf("store: error executing data function: %s", err) } + // defer closing the reader when we're done with it + defer func() { + if rc, ok := reader.(io.ReadCloser); ok { + if err := rc.Close(); err != nil { + logrus.Errorf("store: error closing readcloser: %s", err) + } + } + }() + // extract no more than 261 bytes from the beginning of the file -- this is the header firstBytes := make([]byte, maxFileHeaderBytes) if _, err := reader.Read(firstBytes); err != nil { @@ -305,6 +315,15 @@ func (p *ProcessingMedia) store(ctx context.Context) error { return fmt.Errorf("store: couldn't process %s", extension) } + // defer closing the clean reader when we're done with it + defer func() { + if rc, ok := clean.(io.ReadCloser); ok { + if err := rc.Close(); err != nil { + logrus.Errorf("store: error closing clean readcloser: %s", err) + } + } + }() + // now set some additional fields on the attachment since // we know more about what the underlying media actually is p.attachment.URL = uris.GenerateURIForAttachment(p.attachment.AccountID, string(TypeAttachment), string(SizeOriginal), p.attachment.ID, extension) @@ -317,14 +336,6 @@ func (p *ProcessingMedia) store(ctx context.Context) error { return fmt.Errorf("store: error storing stream: %s", err) } p.attachment.Cached = true - - // if the original reader is a readcloser, close it since we're done with it now - if rc, ok := reader.(io.ReadCloser); ok { - if err := rc.Close(); err != nil { - return fmt.Errorf("store: error closing readcloser: %s", err) - } - } - p.read = true if p.postData != nil { diff --git a/internal/processing/media/getfile.go b/internal/processing/media/getfile.go @@ -180,9 +180,15 @@ func (p *processor) getAttachmentContent(ctx context.Context, requestingAccount return nil, 0, err } - // everything read from the readCloser by the media manager will be written into the bufferedWriter - teeReader := io.TeeReader(readCloser, bufferedWriter) - return teeReader, fileSize, nil + // Make a TeeReader so that everything read from the readCloser by the media manager will be written into the bufferedWriter. + // We wrap this in a teeReadCloser which implements io.ReadCloser, so that whoever uses the teeReader can close the readCloser + // when they're done with it. + trc := teeReadCloser{ + teeReader: io.TeeReader(readCloser, bufferedWriter), + close: readCloser.Close, + } + + return trc, fileSize, nil } // close the pipewriter after data has been piped into it, so the reader on the other side doesn't block; diff --git a/internal/processing/media/util.go b/internal/processing/media/util.go @@ -20,6 +20,7 @@ package media import ( "fmt" + "io" "strconv" "strings" ) @@ -61,3 +62,16 @@ func parseFocus(focus string) (focusx, focusy float32, err error) { focusy = float32(fy) return } + +type teeReadCloser struct { + teeReader io.Reader + close func() error +} + +func (t teeReadCloser) Read(p []byte) (n int, err error) { + return t.teeReader.Read(p) +} + +func (t teeReadCloser) Close() error { + return t.close() +}