Skip to content

Commit 7466f24

Browse files
committed
add test
1 parent af7b92d commit 7466f24

File tree

8 files changed

+172
-31
lines changed

8 files changed

+172
-31
lines changed

modules/context/context_test.go

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,16 @@ import (
77
"net/http"
88
"testing"
99

10+
"code.gitea.io/gitea/modules/httplib"
1011
"code.gitea.io/gitea/modules/setting"
1112

1213
"github.com/stretchr/testify/assert"
1314
)
1415

15-
type mockResponseWriter struct {
16-
header http.Header
17-
}
18-
19-
func (m *mockResponseWriter) Header() http.Header {
20-
return m.header
21-
}
22-
23-
func (m *mockResponseWriter) Write(bytes []byte) (int, error) {
24-
panic("implement me")
25-
}
26-
27-
func (m *mockResponseWriter) WriteHeader(statusCode int) {
28-
panic("implement me")
29-
}
30-
3116
func TestRemoveSessionCookieHeader(t *testing.T) {
32-
w := &mockResponseWriter{}
33-
w.header = http.Header{}
34-
w.header.Add("Set-Cookie", (&http.Cookie{Name: setting.SessionConfig.CookieName, Value: "foo"}).String())
35-
w.header.Add("Set-Cookie", (&http.Cookie{Name: "other", Value: "bar"}).String())
17+
w := httplib.NewMockResponseWriter()
18+
w.Header().Add("Set-Cookie", (&http.Cookie{Name: setting.SessionConfig.CookieName, Value: "foo"}).String())
19+
w.Header().Add("Set-Cookie", (&http.Cookie{Name: "other", Value: "bar"}).String())
3620
assert.Len(t, w.Header().Values("Set-Cookie"), 2)
3721
removeSessionCookieHeader(w)
3822
assert.Len(t, w.Header().Values("Set-Cookie"), 1)

modules/httplib/mock.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package httplib
5+
6+
import (
7+
"bytes"
8+
"net/http"
9+
)
10+
11+
type MockResponseWriter struct {
12+
header http.Header
13+
14+
StatusCode int
15+
BodyBuffer bytes.Buffer
16+
}
17+
18+
func (m *MockResponseWriter) Header() http.Header {
19+
return m.header
20+
}
21+
22+
func (m *MockResponseWriter) Write(bytes []byte) (int, error) {
23+
if m.StatusCode == 0 {
24+
m.StatusCode = http.StatusOK
25+
}
26+
return m.BodyBuffer.Write(bytes)
27+
}
28+
29+
func (m *MockResponseWriter) WriteHeader(statusCode int) {
30+
m.StatusCode = statusCode
31+
}
32+
33+
func NewMockResponseWriter() *MockResponseWriter {
34+
return &MockResponseWriter{header: http.Header{}}
35+
}

modules/httplib/serve.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ func setServeHeadersByFile(r *http.Request, w http.ResponseWriter, filePath stri
8383
}
8484

8585
sniffedType := typesniffer.DetectContentType(mineBuf)
86+
87+
// the "render" parameter came from year 2016: 638dd24c, it doesn't have clear meaning, so I think it could be removed later
8688
isPlain := sniffedType.IsText() || r.FormValue("render") != ""
8789

8890
if setting.MimeTypeMap.Enabled {
@@ -171,18 +173,27 @@ func ServeContentByReader(r *http.Request, w http.ResponseWriter, filePath strin
171173
_, rangeParts, _ := strings.Cut(rangeHeader, "=")
172174
rangeBytesStart, rangeBytesEnd, found := strings.Cut(rangeParts, "-")
173175
start, err := strconv.ParseInt(rangeBytesStart, 10, 64)
174-
if err != nil || start < 0 || start >= size {
175-
http.Error(w, err.Error(), http.StatusBadRequest)
176-
return errors.New("invalid start range")
176+
if start < 0 || start >= size {
177+
err = errors.New("invalid start range")
178+
}
179+
if err != nil {
180+
http.Error(w, err.Error(), http.StatusRequestedRangeNotSatisfiable)
181+
return err
177182
}
178183
end, err := strconv.ParseInt(rangeBytesEnd, 10, 64)
179184
if rangeBytesEnd == "" && found {
180185
err = nil
181186
end = size - 1
182187
}
183-
if err != nil || end < start || end >= size {
188+
if end >= size {
189+
end = size - 1
190+
}
191+
if end < start {
192+
err = errors.New("invalid end range")
193+
}
194+
if err != nil {
184195
http.Error(w, err.Error(), http.StatusBadRequest)
185-
return errors.New("invalid end range")
196+
return err
186197
}
187198

188199
partialLength := end - start + 1
@@ -197,7 +208,7 @@ func ServeContentByReader(r *http.Request, w http.ResponseWriter, filePath strin
197208
return err
198209
}
199210

200-
func ServeContentByReadSeeker(r *http.Request, w http.ResponseWriter, filePath string, size int64, modTime time.Time, reader io.ReadSeeker) error {
211+
func ServeContentByReadSeeker(r *http.Request, w http.ResponseWriter, filePath string, modTime time.Time, reader io.ReadSeeker) error {
201212
buf := make([]byte, mimeDetectionBufferLen)
202213
n, err := util.ReadAtMost(reader, buf)
203214
if err != nil {

modules/httplib/serve_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package httplib
5+
6+
import (
7+
"fmt"
8+
"net/http"
9+
"net/url"
10+
"os"
11+
"strings"
12+
"testing"
13+
"time"
14+
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestServeContentByReader(t *testing.T) {
19+
data := "0123456789abcdef"
20+
21+
test := func(t *testing.T, expectedStatusCode int, expectedContent string) {
22+
_, rangeStr, _ := strings.Cut(t.Name(), "_range_")
23+
r := &http.Request{Header: http.Header{}, Form: url.Values{}}
24+
if rangeStr != "" {
25+
r.Header.Set("Range", fmt.Sprintf("bytes=%s", rangeStr))
26+
}
27+
reader := strings.NewReader(data)
28+
w := NewMockResponseWriter()
29+
err := ServeContentByReader(r, w, "test", int64(len(data)), reader)
30+
assert.Equal(t, expectedStatusCode, w.StatusCode)
31+
if expectedStatusCode == http.StatusPartialContent || expectedStatusCode == http.StatusOK {
32+
assert.Equal(t, fmt.Sprint(len(expectedContent)), w.Header().Get("Content-Length"))
33+
assert.Equal(t, expectedContent, w.BodyBuffer.String())
34+
} else {
35+
assert.Error(t, err)
36+
}
37+
}
38+
39+
t.Run("_range_", func(t *testing.T) {
40+
test(t, http.StatusOK, data)
41+
})
42+
t.Run("_range_0-", func(t *testing.T) {
43+
test(t, http.StatusPartialContent, data)
44+
})
45+
t.Run("_range_0-15", func(t *testing.T) {
46+
test(t, http.StatusPartialContent, data)
47+
})
48+
t.Run("_range_1-", func(t *testing.T) {
49+
test(t, http.StatusPartialContent, data[1:])
50+
})
51+
t.Run("_range_1-3", func(t *testing.T) {
52+
test(t, http.StatusPartialContent, data[1:3+1])
53+
})
54+
t.Run("_range_16-", func(t *testing.T) {
55+
test(t, http.StatusRequestedRangeNotSatisfiable, "")
56+
})
57+
t.Run("_range_1-99999", func(t *testing.T) {
58+
test(t, http.StatusPartialContent, data[1:])
59+
})
60+
}
61+
62+
func TestServeContentByReadSeeker(t *testing.T) {
63+
data := "0123456789abcdef"
64+
tmpFile := t.TempDir() + "/test"
65+
err := os.WriteFile(tmpFile, []byte(data), 0o644)
66+
assert.NoError(t, err)
67+
68+
test := func(t *testing.T, expectedStatusCode int, expectedContent string) {
69+
_, rangeStr, _ := strings.Cut(t.Name(), "_range_")
70+
r := &http.Request{Header: http.Header{}, Form: url.Values{}}
71+
if rangeStr != "" {
72+
r.Header.Set("Range", fmt.Sprintf("bytes=%s", rangeStr))
73+
}
74+
75+
seekReader, err := os.OpenFile(tmpFile, os.O_RDONLY, 0o644)
76+
if !assert.NoError(t, err) {
77+
return
78+
}
79+
defer seekReader.Close()
80+
81+
w := NewMockResponseWriter()
82+
_ = ServeContentByReadSeeker(r, w, "test", time.Time{}, seekReader)
83+
assert.Equal(t, expectedStatusCode, w.StatusCode)
84+
if expectedStatusCode == http.StatusPartialContent || expectedStatusCode == http.StatusOK {
85+
assert.Equal(t, fmt.Sprint(len(expectedContent)), w.Header().Get("Content-Length"))
86+
assert.Equal(t, expectedContent, w.BodyBuffer.String())
87+
}
88+
}
89+
90+
t.Run("_range_", func(t *testing.T) {
91+
test(t, http.StatusOK, data)
92+
})
93+
t.Run("_range_0-", func(t *testing.T) {
94+
test(t, http.StatusPartialContent, data)
95+
})
96+
t.Run("_range_0-15", func(t *testing.T) {
97+
test(t, http.StatusPartialContent, data)
98+
})
99+
t.Run("_range_1-", func(t *testing.T) {
100+
test(t, http.StatusPartialContent, data[1:])
101+
})
102+
t.Run("_range_1-3", func(t *testing.T) {
103+
test(t, http.StatusPartialContent, data[1:3+1])
104+
})
105+
t.Run("_range_16-", func(t *testing.T) {
106+
test(t, http.StatusRequestedRangeNotSatisfiable, "")
107+
})
108+
t.Run("_range_1-99999", func(t *testing.T) {
109+
test(t, http.StatusPartialContent, data[1:])
110+
})
111+
}

routers/api/v1/repo/file.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
219219
}
220220
defer lfsDataRc.Close()
221221

222-
if err := common.ServeContentByReadSeeker(ctx.Context, ctx.Repo.TreePath, meta.Size, lastModified, lfsDataRc); err != nil {
222+
if err := common.ServeContentByReadSeeker(ctx.Context, ctx.Repo.TreePath, lastModified, lfsDataRc); err != nil {
223223
ctx.ServerError("ServeData", err)
224224
}
225225
}

routers/common/serve.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ func ServeContentByReader(ctx *context.Context, filePath string, size int64, rea
3737
return httplib.ServeContentByReader(ctx.Req, ctx.Resp, filePath, size, reader)
3838
}
3939

40-
func ServeContentByReadSeeker(ctx *context.Context, filePath string, size int64, modTime time.Time, reader io.ReadSeeker) error {
41-
return httplib.ServeContentByReadSeeker(ctx.Req, ctx.Resp, filePath, size, modTime, reader)
40+
func ServeContentByReadSeeker(ctx *context.Context, filePath string, modTime time.Time, reader io.ReadSeeker) error {
41+
return httplib.ServeContentByReadSeeker(ctx.Req, ctx.Resp, filePath, modTime, reader)
4242
}

routers/web/repo/attachment.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func ServeAttachment(ctx *context.Context, uuid string) {
153153
}
154154
defer fr.Close()
155155

156-
if err = common.ServeContentByReadSeeker(ctx, attach.Name, attach.Size, attach.CreatedUnix.AsTime(), fr); err != nil {
156+
if err = common.ServeContentByReadSeeker(ctx, attach.Name, attach.CreatedUnix.AsTime(), fr); err != nil {
157157
ctx.ServerError("ServeData", err)
158158
return
159159
}

routers/web/repo/download.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified time.Time
7171
log.Error("ServeBlobOrLFS: Close: %v", err)
7272
}
7373
}()
74-
return common.ServeContentByReadSeeker(ctx, ctx.Repo.TreePath, meta.Size, lastModified, lfsDataRc)
74+
return common.ServeContentByReadSeeker(ctx, ctx.Repo.TreePath, lastModified, lfsDataRc)
7575
}
7676
if err = dataRc.Close(); err != nil {
7777
log.Error("ServeBlobOrLFS: Close: %v", err)

0 commit comments

Comments
 (0)