• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oxyno-zeta / s3-proxy / 10979626808

22 Sep 2024 08:24AM UTC coverage: 84.23% (-2.0%) from 86.185%
10979626808

push

github

oxyno-zeta
feat(wip): Add HEAD request support

Close #474

138 of 295 new or added lines in 6 files covered. (46.78%)

1 existing line in 1 file now uncovered.

5213 of 6189 relevant lines covered (84.23%)

38.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.55
/pkg/s3-proxy/response-handler/utils.go
1
package responsehandler
2

3
import (
4
        "io"
5
        "net/http"
6
        "reflect"
7
        "strconv"
8
        "strings"
9
        "time"
10

11
        "emperror.dev/errors"
12
        "github.com/oxyno-zeta/s3-proxy/pkg/s3-proxy/config"
13
        utils "github.com/oxyno-zeta/s3-proxy/pkg/s3-proxy/utils/generalutils"
14
        "github.com/oxyno-zeta/s3-proxy/pkg/s3-proxy/utils/templateutils"
15
)
16

17
func (*handler) manageStatus(
18
        helpersContent string,
19
        tplConfigItem *config.TargetTemplateConfigItem,
20
        defaultTpl string,
21
        data interface{},
22
) (int, error) {
71✔
23
        // Create main status content
71✔
24
        statusContent := helpersContent
71✔
25

71✔
26
        // Check if per target template is declared
71✔
27
        if tplConfigItem != nil && tplConfigItem.Status != "" {
75✔
28
                // Concat
4✔
29
                statusContent = statusContent + "\n" + tplConfigItem.Status
4✔
30
        } else {
71✔
31
                // Concat
67✔
32
                statusContent = statusContent + "\n" + defaultTpl
67✔
33
        }
67✔
34

35
        // Execute status main template
36
        buf, err := templateutils.ExecuteTemplate(statusContent, data)
71✔
37
        // Check error
71✔
38
        if err != nil {
71✔
39
                return 0, err
×
40
        }
×
41

42
        // Get string from buffer
43
        str := buf.String()
71✔
44
        // Remove all new lines
71✔
45
        str = utils.NewLineMatcherRegex.ReplaceAllString(str, "")
71✔
46

71✔
47
        // Try to parse int from string
71✔
48
        return strconv.Atoi(str)
71✔
49
}
50

51
func (*handler) manageHeaders(helpersContent string, headersTpl map[string]string, hData interface{}) (map[string]string, error) {
102✔
52
        // Store result
102✔
53
        res := map[string]string{}
102✔
54

102✔
55
        // Loop over all headers asked
102✔
56
        for k, htpl := range headersTpl {
202✔
57
                // Concat helpers to header template
100✔
58
                tpl := helpersContent + "\n" + htpl
100✔
59
                // Execute template
100✔
60
                buf, err := templateutils.ExecuteTemplate(tpl, hData)
100✔
61
                // Check error
100✔
62
                if err != nil {
104✔
63
                        return nil, err
4✔
64
                }
4✔
65
                // Get string from buffer
66
                str := buf.String()
96✔
67
                // Remove all new lines
96✔
68
                str = utils.NewLineMatcherRegex.ReplaceAllString(str, "")
96✔
69
                // Save data only if the header isn't empty
96✔
70
                if str != "" {
191✔
71
                        // Save
95✔
72
                        res[k] = str
95✔
73
                }
95✔
74
        }
75

76
        // Return
77
        return res, nil
98✔
78
}
79

80
// send will send the response.
81
func (h *handler) send(bodyBuf io.WriterTo, headers map[string]string, status int) error {
89✔
82
        // Loop over headers
89✔
83
        for k, v := range headers {
174✔
84
                // Set header
85✔
85
                h.res.Header().Set(k, v)
85✔
86
        }
85✔
87

88
        // Set status code
89
        h.res.WriteHeader(status)
89✔
90

89✔
91
        // Check if we aren't in head answer
89✔
92
        if !h.headAnswerMode {
178✔
93
                // Write to response
89✔
94
                _, err := bodyBuf.WriteTo(h.res)
89✔
95
                // Check if error exists
89✔
96
                if err != nil {
89✔
NEW
97
                        return errors.WithStack(err)
×
NEW
98
                }
×
99
        }
100

101
        return nil
89✔
102
}
103

104
func setHeadersFromObjectOutput(w http.ResponseWriter, obj *StreamInput) {
31✔
105
        setStrHeader(w, "Cache-Control", obj.CacheControl)
31✔
106
        setStrHeader(w, "Expires", obj.Expires)
31✔
107
        setStrHeader(w, "Content-Disposition", obj.ContentDisposition)
31✔
108
        setStrHeader(w, "Content-Encoding", obj.ContentEncoding)
31✔
109
        setStrHeader(w, "Content-Language", obj.ContentLanguage)
31✔
110
        setIntHeader(w, "Content-Length", obj.ContentLength)
31✔
111
        setStrHeader(w, "Content-Range", obj.ContentRange)
31✔
112
        setStrHeader(w, "Content-Type", obj.ContentType)
31✔
113
        setStrHeader(w, "ETag", obj.ETag)
31✔
114
        setStrHeader(w, "Accept-Ranges", "bytes")
31✔
115
        setTimeHeader(w, "Last-Modified", obj.LastModified)
31✔
116

31✔
117
        httpStatus := determineHTTPStatus(obj)
31✔
118
        w.WriteHeader(httpStatus)
31✔
119
}
31✔
120

121
func determineHTTPStatus(obj *StreamInput) int {
31✔
122
        contentRangeIsGiven := len(obj.ContentRange) > 0
31✔
123
        // Check if content will be partial
31✔
124
        if contentRangeIsGiven {
33✔
125
                if !totalFileSizeEqualToContentRange(obj) {
3✔
126
                        // Return partial content
1✔
127
                        return http.StatusPartialContent
1✔
128
                }
1✔
129
        }
130

131
        // Return ok
132
        return http.StatusOK
30✔
133
}
134

135
func totalFileSizeEqualToContentRange(obj *StreamInput) bool {
2✔
136
        totalSizeIsEqualToContentRange := false
2✔
137
        // Calculate total file size
2✔
138
        totalSize, err := strconv.ParseInt(getFileSizeAsString(obj), 10, 64)
2✔
139
        if err == nil {
4✔
140
                if totalSize == (obj.ContentLength) {
3✔
141
                        totalSizeIsEqualToContentRange = true
1✔
142
                }
1✔
143
        }
144
        // Return result
145
        return totalSizeIsEqualToContentRange
2✔
146
}
147

148
/*
149
*
150
See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
151
*/
152
func getFileSizeAsString(obj *StreamInput) string {
2✔
153
        s := strings.Split(obj.ContentRange, "/")
2✔
154
        totalSizeString := s[1]
2✔
155
        totalSizeString = strings.TrimSpace(totalSizeString)
2✔
156
        // Return result
2✔
157
        return totalSizeString
2✔
158
}
2✔
159

160
func setStrHeader(w http.ResponseWriter, key string, value string) {
279✔
161
        if len(value) > 0 {
382✔
162
                w.Header().Add(key, value)
103✔
163
        }
103✔
164
}
165

166
func setIntHeader(w http.ResponseWriter, key string, value int64) {
31✔
167
        if value > 0 {
61✔
168
                w.Header().Add(key, strconv.FormatInt(value, 10))
30✔
169
        }
30✔
170
}
171

172
func setTimeHeader(w http.ResponseWriter, key string, value time.Time) {
31✔
173
        if !reflect.DeepEqual(value, time.Time{}) {
61✔
174
                w.Header().Add(key, value.UTC().Format(http.TimeFormat))
30✔
175
        }
30✔
176
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc