Browse Source

Removed old stream.go

Viktor Sokolov 1 month ago
parent
commit
aeed1eef55
2 changed files with 0 additions and 605 deletions
  1. 0 138
      stream.go
  2. 0 467
      stream_test.go

+ 0 - 138
stream.go

@@ -1,138 +0,0 @@
-package main
-
-// import (
-// 	"context"
-// 	"io"
-// 	"net/http"
-// 	"strconv"
-// 	"sync"
-
-// 	log "github.com/sirupsen/logrus"
-
-// 	"github.com/imgproxy/imgproxy/v3/config"
-// 	"github.com/imgproxy/imgproxy/v3/cookies"
-// 	"github.com/imgproxy/imgproxy/v3/httpheaders"
-// 	"github.com/imgproxy/imgproxy/v3/ierrors"
-// 	"github.com/imgproxy/imgproxy/v3/imagedata"
-// 	"github.com/imgproxy/imgproxy/v3/monitoring"
-// 	"github.com/imgproxy/imgproxy/v3/monitoring/stats"
-// 	"github.com/imgproxy/imgproxy/v3/options"
-// 	"github.com/imgproxy/imgproxy/v3/server"
-// )
-
-// var (
-// 	streamReqHeaders = []string{
-// 		"If-None-Match",
-// 		"If-Modified-Since",
-// 		"Accept-Encoding",
-// 		"Range",
-// 	}
-
-// 	streamRespHeaders = []string{
-// 		"ETag",
-// 		"Content-Type",
-// 		"Content-Encoding",
-// 		"Content-Range",
-// 		"Accept-Ranges",
-// 		"Last-Modified",
-// 	}
-
-// 	streamBufPool = sync.Pool{
-// 		New: func() interface{} {
-// 			buf := make([]byte, 4096)
-// 			return &buf
-// 		},
-// 	}
-// )
-
-// func streamOriginImage(ctx context.Context, reqID string, r *http.Request, rw http.ResponseWriter, po *options.ProcessingOptions, imageURL string) error {
-// 	stats.IncImagesInProgress()
-// 	defer stats.DecImagesInProgress()
-// 	defer monitoring.StartStreamingSegment(ctx)()
-
-// 	var (
-// 		cookieJar http.CookieJar
-// 		err       error
-// 	)
-
-// 	imgRequestHeader := make(http.Header)
-
-// 	for _, k := range streamReqHeaders {
-// 		if v := r.Header.Get(k); len(v) != 0 {
-// 			imgRequestHeader.Set(k, v)
-// 		}
-// 	}
-
-// 	if config.CookiePassthrough {
-// 		cookieJar, err = cookies.JarFromRequest(r)
-// 		if err != nil {
-// 			return ierrors.Wrap(err, 0, ierrors.WithCategory(categoryStreaming))
-// 		}
-// 	}
-
-// 	req, err := imagedata.Fetcher.BuildRequest(r.Context(), imageURL, imgRequestHeader, cookieJar)
-// 	defer req.Cancel()
-// 	if err != nil {
-// 		return ierrors.Wrap(err, 0, ierrors.WithCategory(categoryStreaming))
-// 	}
-
-// 	res, err := req.Send()
-// 	if res != nil {
-// 		defer res.Body.Close()
-// 	}
-// 	if err != nil {
-// 		return ierrors.Wrap(err, 0, ierrors.WithCategory(categoryStreaming))
-// 	}
-
-// 	for _, k := range streamRespHeaders {
-// 		vv := res.Header.Values(k)
-// 		for _, v := range vv {
-// 			rw.Header().Set(k, v)
-// 		}
-// 	}
-
-// 	if res.ContentLength >= 0 {
-// 		rw.Header().Set("Content-Length", strconv.Itoa(int(res.ContentLength)))
-// 	}
-
-// 	if res.StatusCode < 300 {
-// 		contentDisposition := httpheaders.ContentDispositionValue(
-// 			req.URL().Path,
-// 			po.Filename,
-// 			"",
-// 			rw.Header().Get(httpheaders.ContentType),
-// 			po.ReturnAttachment,
-// 		)
-// 		rw.Header().Set("Content-Disposition", contentDisposition)
-// 	}
-
-// 	setCacheControl(rw, po.Expires, res.Header)
-// 	setCanonical(rw, imageURL)
-// 	rw.Header().Set("Content-Security-Policy", "script-src 'none'")
-
-// 	rw.WriteHeader(res.StatusCode)
-
-// 	buf := streamBufPool.Get().(*[]byte)
-// 	defer streamBufPool.Put(buf)
-
-// 	_, copyerr := io.CopyBuffer(rw, res.Body, *buf)
-// 	if copyerr == http.ErrBodyNotAllowed {
-// 		// We can hit this for some statuses like 304 Not Modified.
-// 		// We can ignore this error.
-// 		copyerr = nil
-// 	}
-
-// 	server.LogResponse(
-// 		reqID, r, res.StatusCode, nil,
-// 		log.Fields{
-// 			"image_url":          imageURL,
-// 			"processing_options": po,
-// 		},
-// 	)
-
-// 	if copyerr != nil {
-// 		panic(http.ErrAbortHandler)
-// 	}
-
-// 	return nil
-// }

+ 0 - 467
stream_test.go

@@ -1,467 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"io"
-	"net/http"
-	"net/http/httptest"
-	"os"
-	"path/filepath"
-	"strconv"
-	"testing"
-	"time"
-
-	"github.com/sirupsen/logrus"
-	"github.com/stretchr/testify/suite"
-
-	"github.com/imgproxy/imgproxy/v3/config"
-	"github.com/imgproxy/imgproxy/v3/server"
-)
-
-type StreamTestSuite struct {
-	suite.Suite
-
-	router *server.Router
-}
-
-func (s *StreamTestSuite) SetupSuite() {
-	config.Reset()
-
-	wd, err := os.Getwd()
-	s.Require().NoError(err)
-
-	s.T().Setenv("IMGPROXY_LOCAL_FILESYSTEM_ROOT", filepath.Join(wd, "/testdata"))
-	s.T().Setenv("IMGPROXY_CLIENT_KEEP_ALIVE_TIMEOUT", "0")
-
-	err = initialize()
-	s.Require().NoError(err)
-
-	logrus.SetOutput(io.Discard)
-
-	s.router = buildRouter(server.NewRouter(server.NewConfigFromEnv()))
-}
-
-func (s *StreamTestSuite) TeardownSuite() {
-	shutdown()
-	logrus.SetOutput(os.Stdout)
-}
-
-func (s *StreamTestSuite) SetupTest() {
-	config.Reset()
-	config.AllowLoopbackSourceAddresses = true
-}
-
-func (s *StreamTestSuite) send(path string, header http.Header) *httptest.ResponseRecorder {
-	req := httptest.NewRequest(http.MethodGet, path, nil)
-	rw := httptest.NewRecorder()
-
-	req.Header = header
-
-	s.router.ServeHTTP(rw, req)
-
-	return rw
-}
-
-func (s *StreamTestSuite) readTestFile(name string) []byte {
-	wd, err := os.Getwd()
-	s.Require().NoError(err)
-
-	data, err := os.ReadFile(filepath.Join(wd, "testdata", name))
-	s.Require().NoError(err)
-
-	return data
-}
-
-// TestStreamBasicRequest checks basic streaming request
-func (s *StreamTestSuite) TestStreamBasicRequest() {
-	rw := s.send("/unsafe/raw:1/plain/local:///test1.png", nil)
-	res := rw.Result()
-
-	s.Require().Equal(200, res.StatusCode)
-	s.Require().Equal("image/png", res.Header.Get("Content-Type"))
-
-	// Verify we get the original image data without processing
-	expected := s.readTestFile("test1.png")
-	actual := rw.Body.Bytes()
-	s.Require().Equal(expected, actual)
-}
-
-// TestStreamResponseHeadersPassthrough checks that original response headers are
-// passed through to the client
-func (s *StreamTestSuite) TestStreamResponseHeadersPassthrough() {
-	data := s.readTestFile("test1.png")
-	contentLength := len(data)
-
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.Header().Set("Content-Type", "image/png")
-		rw.Header().Set("Content-Length", strconv.Itoa(contentLength))
-		rw.Header().Set("Accept-Ranges", "bytes")
-		rw.Header().Set("ETag", "etag")
-		rw.WriteHeader(200)
-		rw.Write(data)
-	}))
-	defer ts.Close()
-
-	rw := s.send("/unsafe/raw:1/plain/"+ts.URL, nil)
-	res := rw.Result()
-
-	s.Require().Equal(200, res.StatusCode)
-	s.Require().Equal("image/png", res.Header.Get("Content-Type"))
-	s.Require().Equal(strconv.Itoa(contentLength), res.Header.Get("Content-Length"))
-	s.Require().Equal("bytes", res.Header.Get("Accept-Ranges"))
-	s.Require().Equal("etag", res.Header.Get("ETag"))
-}
-
-// TestStreamLastModifiedPassthrough checks that Last-Modified header is passed through from the
-// server to the response regardless of config.LastModifiedEnabled setting
-func (s *StreamTestSuite) TestStreamLastModifiedPassthrough() {
-	config.LastModifiedEnabled = false
-	data := s.readTestFile("test1.png")
-	lastModified := "Wed, 21 Oct 2015 07:28:00 GMT"
-
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.Header().Set("Last-Modified", lastModified)
-		rw.Header().Set("Content-Type", "image/png")
-		rw.WriteHeader(200)
-		rw.Write(data)
-	}))
-	defer ts.Close()
-
-	rw := s.send("/unsafe/raw:1/plain/"+ts.URL, nil)
-	res := rw.Result()
-
-	s.Require().Equal(200, res.StatusCode)
-	s.Require().Equal(lastModified, res.Header.Get("Last-Modified"))
-}
-
-// TestStreamRequestHeadersPassthrough checks that original request headers are passed through
-// to the server
-func (s *StreamTestSuite) TestStreamRequestHeadersPassthrough() {
-	etag := `"test-etag-123"`
-	data := s.readTestFile("test1.png")
-
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		// Verify that If-None-Match header is passed through
-		s.Equal(etag, r.Header.Get("If-None-Match"))
-		s.Equal("test", r.Header.Get("If-Modified-Since"))
-		s.Equal("gzip", r.Header.Get("Accept-Encoding"))
-		s.Equal("bytes=*", r.Header.Get("Range"))
-
-		rw.Header().Set("ETag", etag)
-		rw.WriteHeader(200)
-		rw.Write(data)
-	}))
-	defer ts.Close()
-
-	header := make(http.Header)
-	header.Set("If-None-Match", etag)
-	header.Set("If-Modified-Since", "test")
-	header.Set("Accept-Encoding", "gzip")
-	header.Set("Range", "bytes=*")
-
-	rw := s.send("/unsafe/raw:1/plain/"+ts.URL, header)
-	res := rw.Result()
-
-	s.Require().Equal(200, res.StatusCode)
-	s.Require().Equal(etag, res.Header.Get("ETag"))
-}
-
-// TestStreamContentDisposition checks that Content-Disposition header is set correctly
-func (s *StreamTestSuite) TestStreamContentDisposition() {
-	data := s.readTestFile("test1.png")
-
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.Header().Set("Content-Type", "image/png")
-		rw.WriteHeader(200)
-		rw.Write(data)
-	}))
-	defer ts.Close()
-
-	// Test with attachment
-	rw := s.send("/unsafe/raw:1/fn:custom_name/att:1/plain/"+ts.URL, nil)
-	res := rw.Result()
-
-	s.Require().Equal(200, res.StatusCode)
-	s.Require().Contains(res.Header.Get("Content-Disposition"), "custom_name.png")
-	s.Require().Contains(res.Header.Get("Content-Disposition"), "attachment")
-}
-
-// TestStreamCacheControl checks that Cache-Control header is set correctly in different cases
-func (s *StreamTestSuite) TestStreamCacheControl() {
-	type testCase struct {
-		name                    string
-		cacheControlPassthrough bool
-		setupOriginHeaders      func(http.ResponseWriter)
-		urlPath                 string
-		timestampOffset         *time.Duration // nil for no timestamp, otherwise the offset from now
-		expectedStatusCode      int
-		validate                func(*testing.T, *http.Response)
-	}
-
-	// Duration variables for test cases
-	var (
-		oneHour          = time.Hour
-		thirtyMinutes    = 30 * time.Minute
-		fortyFiveMinutes = 45 * time.Minute
-		twoHours         = time.Hour * 2
-		oneMinuteDelta   = float64(time.Minute)
-	)
-
-	// Set this explicitly for testing purposes
-	config.TTL = 4242
-
-	testCases := []testCase{
-		{
-			name:                    "Passthrough",
-			cacheControlPassthrough: true,
-			setupOriginHeaders: func(rw http.ResponseWriter) {
-				rw.Header().Set("Cache-Control", "max-age=3600, public")
-			},
-			urlPath:            "/unsafe/raw:1/plain/%s",
-			timestampOffset:    nil,
-			expectedStatusCode: 200,
-			validate: func(t *testing.T, res *http.Response) {
-				s.Require().Equal("max-age=3600, public", res.Header.Get("Cache-Control"))
-			},
-		},
-		// Checks that expires gets convert to cache-control
-		{
-			name:                    "ExpiresPassthrough",
-			cacheControlPassthrough: true,
-			setupOriginHeaders: func(rw http.ResponseWriter) {
-				rw.Header().Set("Expires", time.Now().Add(oneHour).UTC().Format(http.TimeFormat))
-			},
-			urlPath:            "/unsafe/raw:1/plain/%s",
-			timestampOffset:    nil,
-			expectedStatusCode: 200,
-			validate: func(t *testing.T, res *http.Response) {
-				// When expires is converted to cache-control, the expires header should be empty
-				s.Require().Empty(res.Header.Get("Expires"))
-				s.Require().InDelta(oneHour, s.maxAgeValue(res), oneMinuteDelta)
-			},
-		},
-		// It would be set to something like default ttl
-		{
-			name:                    "PassthroughDisabled",
-			cacheControlPassthrough: false,
-			setupOriginHeaders: func(rw http.ResponseWriter) {
-				rw.Header().Set("Cache-Control", "max-age=3600, public")
-			},
-			urlPath:            "/unsafe/raw:1/plain/%s",
-			timestampOffset:    nil,
-			expectedStatusCode: 200,
-			validate: func(t *testing.T, res *http.Response) {
-				s.Require().Equal(s.maxAgeValue(res), time.Duration(config.TTL)*time.Second)
-			},
-		},
-		// When expires is set in processing options, but not present in the response
-		{
-			name:                    "WithProcessingOptionsExpires",
-			cacheControlPassthrough: false,
-			setupOriginHeaders:      func(rw http.ResponseWriter) {}, // No origin headers
-			urlPath:                 "/unsafe/raw:1/exp:%d/plain/%s",
-			timestampOffset:         &oneHour,
-			expectedStatusCode:      200,
-			validate: func(t *testing.T, res *http.Response) {
-				s.Require().InDelta(oneHour, s.maxAgeValue(res), oneMinuteDelta)
-			},
-		},
-		// When expires is set in processing options, and is present in the response,
-		// and passthrough is enabled
-		{
-			name:                    "ProcessingOptionsOverridesOrigin",
-			cacheControlPassthrough: true,
-			setupOriginHeaders: func(rw http.ResponseWriter) {
-				// Origin has a longer cache time
-				rw.Header().Set("Cache-Control", "max-age=7200, public")
-			},
-			urlPath:            "/unsafe/raw:1/exp:%d/plain/%s",
-			timestampOffset:    &thirtyMinutes,
-			expectedStatusCode: 200,
-			validate: func(t *testing.T, res *http.Response) {
-				s.Require().InDelta(thirtyMinutes, s.maxAgeValue(res), oneMinuteDelta)
-			},
-		},
-		// When expires is not set in po, but both expires and cc are present in response,
-		// and passthrough is enabled
-		{
-			name:                    "BothHeadersPassthroughEnabled",
-			cacheControlPassthrough: true,
-			setupOriginHeaders: func(rw http.ResponseWriter) {
-				// Origin has both Cache-Control and Expires headers
-				rw.Header().Set("Cache-Control", "max-age=1800, public")
-				rw.Header().Set("Expires", time.Now().Add(oneHour).UTC().Format(http.TimeFormat))
-			},
-			urlPath:            "/unsafe/raw:1/plain/%s",
-			timestampOffset:    nil,
-			expectedStatusCode: 200,
-			validate: func(t *testing.T, res *http.Response) {
-				// Cache-Control should take precedence over Expires when both are present
-				s.Require().InDelta(thirtyMinutes, s.maxAgeValue(res), oneMinuteDelta)
-				s.Require().Empty(res.Header.Get("Expires"))
-			},
-		},
-		// When expires is set in PO AND both cache-control and expires are present in response,
-		// and passthrough is enabled
-		{
-			name:                    "ProcessingOptionsOverridesBothOriginHeaders",
-			cacheControlPassthrough: true,
-			setupOriginHeaders: func(rw http.ResponseWriter) {
-				// Origin has both Cache-Control and Expires headers with longer cache times
-				rw.Header().Set("Cache-Control", "max-age=7200, public")
-				rw.Header().Set("Expires", time.Now().Add(twoHours).UTC().Format(http.TimeFormat))
-			},
-			urlPath:            "/unsafe/raw:1/exp:%d/plain/%s",
-			timestampOffset:    &fortyFiveMinutes, // Shorter than origin headers
-			expectedStatusCode: 200,
-			validate: func(t *testing.T, res *http.Response) {
-				s.Require().InDelta(fortyFiveMinutes, s.maxAgeValue(res), oneMinuteDelta)
-				s.Require().Empty(res.Header.Get("Expires"))
-			},
-		},
-		// No headers set
-		{
-			name:                    "NoOriginHeaders",
-			cacheControlPassthrough: false,
-			setupOriginHeaders:      func(rw http.ResponseWriter) {}, // Origin has no cache headers
-			urlPath:                 "/unsafe/raw:1/plain/%s",
-			timestampOffset:         nil,
-			expectedStatusCode:      200,
-			validate: func(t *testing.T, res *http.Response) {
-				s.Require().Equal(s.maxAgeValue(res), time.Duration(config.TTL)*time.Second)
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		s.Run(tc.name, func() {
-			config.CacheControlPassthrough = tc.cacheControlPassthrough
-
-			data := s.readTestFile("test1.png")
-
-			ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-				tc.setupOriginHeaders(rw)
-				rw.Header().Set("Content-Type", "image/png")
-				rw.WriteHeader(200)
-				rw.Write(data)
-			}))
-			defer ts.Close()
-
-			var url string
-			if tc.timestampOffset != nil {
-				timestamp := time.Now().Add(*tc.timestampOffset).Unix()
-				url = fmt.Sprintf(tc.urlPath, timestamp, ts.URL)
-			} else {
-				url = fmt.Sprintf(tc.urlPath, ts.URL)
-			}
-
-			rw := s.send(url, nil)
-			res := rw.Result()
-
-			s.Require().Equal(tc.expectedStatusCode, res.StatusCode)
-			tc.validate(s.T(), res)
-		})
-	}
-}
-
-// maxAgeValue parses max-age from cache-control
-func (s *StreamTestSuite) maxAgeValue(res *http.Response) time.Duration {
-	cacheControl := res.Header.Get("Cache-Control")
-	if cacheControl == "" {
-		return 0
-	}
-	var maxAge int
-	fmt.Sscanf(cacheControl, "max-age=%d", &maxAge)
-	return time.Duration(maxAge) * time.Second
-}
-
-// TestStreamSecurityHeaders tests the security headers set by the streaming service.
-func (s *StreamTestSuite) TestStreamSecurityHeaders() {
-	data := s.readTestFile("test1.png")
-
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.Header().Set("Content-Type", "image/png")
-		rw.WriteHeader(200)
-		rw.Write(data)
-	}))
-	defer ts.Close()
-
-	rw := s.send("/unsafe/raw:1/plain/"+ts.URL, nil)
-	res := rw.Result()
-
-	s.Require().Equal(200, res.StatusCode)
-	s.Require().Equal("script-src 'none'", res.Header.Get("Content-Security-Policy"))
-}
-
-// TestStreamErrorResponse tests the error responses from the streaming service.
-func (s *StreamTestSuite) TestStreamErrorResponse() {
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.WriteHeader(404)
-		rw.Write([]byte("Not Found"))
-	}))
-	defer ts.Close()
-
-	rw := s.send("/unsafe/raw:1/plain/"+ts.URL, nil)
-	res := rw.Result()
-
-	s.Require().Equal(404, res.StatusCode)
-}
-
-// TestStreamCookiePassthrough tests the cookie passthrough behavior of the streaming service.
-func (s *StreamTestSuite) TestStreamCookiePassthrough() {
-	config.CookiePassthrough = true
-
-	data := s.readTestFile("test1.png")
-
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		// Verify cookies are passed through
-		cookie, err := r.Cookie("test_cookie")
-		if err == nil {
-			s.Equal("test_value", cookie.Value)
-		}
-
-		rw.Header().Set("Content-Type", "image/png")
-		rw.WriteHeader(200)
-		rw.Write(data)
-	}))
-	defer ts.Close()
-
-	header := make(http.Header)
-	header.Set("Cookie", "test_cookie=test_value")
-
-	rw := s.send("/unsafe/raw:1/plain/"+ts.URL, header)
-	res := rw.Result()
-
-	s.Require().Equal(200, res.StatusCode)
-}
-
-// TestStreamCanonicalHeader tests that the canonical header is set correctly
-func (s *StreamTestSuite) TestStreamCanonicalHeader() {
-	data := s.readTestFile("test1.png")
-
-	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.Header().Set("Content-Type", "image/png")
-		rw.WriteHeader(200)
-		rw.Write(data)
-	}))
-	defer ts.Close()
-
-	for _, sc := range []bool{true, false} {
-		config.SetCanonicalHeader = sc
-
-		rw := s.send("/unsafe/raw:1/plain/"+ts.URL, nil)
-		res := rw.Result()
-
-		s.Require().Equal(200, res.StatusCode)
-
-		if sc {
-			s.Require().Contains(res.Header.Get("Link"), fmt.Sprintf(`<%s>; rel="canonical"`, ts.URL))
-		} else {
-			s.Require().Empty(res.Header.Get("Link"))
-		}
-	}
-}
-
-func TestStream(t *testing.T) {
-	suite.Run(t, new(StreamTestSuite))
-}