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

mendersoftware / mender-server / 1900805255

01 Jul 2025 05:31PM UTC coverage: 66.222% (+0.5%) from 65.694%
1900805255

Pull #774

gitlab-ci

web-flow
chore: bump pillow from 11.2.1 to 11.3.0 in /backend/tests

Bumps [pillow](https://github.com/python-pillow/Pillow) from 11.2.1 to 11.3.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/11.2.1...11.3.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-version: 11.3.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #774: chore: bump pillow from 11.2.1 to 11.3.0 in /backend/tests

29486 of 44526 relevant lines covered (66.22%)

1.44 hits per line

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

55.05
/backend/pkg/accesslog/middleware.go
1
// Copyright 2024 Northern.tech AS
2
//
3
//        Licensed under the Apache License, Version 2.0 (the "License");
4
//        you may not use this file except in compliance with the License.
5
//        You may obtain a copy of the License at
6
//
7
//            http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//        Unless required by applicable law or agreed to in writing, software
10
//        distributed under the License is distributed on an "AS IS" BASIS,
11
//        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//        See the License for the specific language governing permissions and
13
//        limitations under the License.
14
package accesslog
15

16
import (
17
        "context"
18
        "errors"
19
        "fmt"
20
        "net"
21
        "net/http"
22
        "os"
23
        "path"
24
        "runtime"
25
        "strconv"
26
        "strings"
27
        "time"
28

29
        "github.com/ant0ine/go-json-rest/rest"
30
        "github.com/sirupsen/logrus"
31

32
        "github.com/mendersoftware/mender-server/pkg/netutils"
33
        "github.com/mendersoftware/mender-server/pkg/requestlog"
34
)
35

36
const (
37
        StatusClientClosedConnection = 499
38

39
        // nolint:lll
40
        DefaultLogFormat = "%t %S\033[0m \033[36;1m%Dμs\033[0m \"%r\" \033[1;30m%u \"%{User-Agent}i\"\033[0m"
41
        SimpleLogFormat  = "%s %Dμs %r %u %{User-Agent}i"
42

43
        envProxyDepth = "ACCESSLOG_PROXY_DEPTH"
44
)
45

46
// AccesLogMiddleware uses logger from requestlog and adds a fixed set
47
// of fields to every accesslog records.
48
type AccessLogMiddleware struct {
49
        // Format is not used but kept for historical use.
50
        // FIXME(QA-673): Remove unused attributes and properties from package.
51
        Format AccessLogFormat // nolint:unused
52

53
        ClientIPHook func(req *http.Request) net.IP
54
        DisableLog   func(statusCode int, r *rest.Request) bool
55

56
        recorder *rest.RecorderMiddleware
57
}
58

59
func getClientIPFromEnv() func(r *http.Request) net.IP {
8✔
60
        if proxyDepthEnv, ok := os.LookupEnv(envProxyDepth); ok {
8✔
61
                proxyDepth, err := strconv.ParseUint(proxyDepthEnv, 10, 8)
×
62
                if err == nil {
×
63
                        return func(r *http.Request) net.IP {
×
64
                                return netutils.GetIPFromXFFDepth(r, int(proxyDepth))
×
65
                        }
×
66
                }
67
        }
68
        return nil
8✔
69
}
70

71
const MaxTraceback = 32
72

73
func collectTrace() string {
×
74
        var (
×
75
                trace     [MaxTraceback]uintptr
×
76
                traceback strings.Builder
×
77
        )
×
78
        // Skip 4
×
79
        // = accesslog.LogFunc
×
80
        // + accesslog.collectTrace
×
81
        // + runtime.Callers
×
82
        // + runtime.gopanic
×
83
        n := runtime.Callers(4, trace[:])
×
84
        frames := runtime.CallersFrames(trace[:n])
×
85
        for frame, more := frames.Next(); frame.PC != 0 &&
×
86
                n >= 0; frame, more = frames.Next() {
×
87
                funcName := frame.Function
×
88
                if funcName == "" {
×
89
                        fmt.Fprint(&traceback, "???\n")
×
90
                } else {
×
91
                        fmt.Fprintf(&traceback, "%s@%s:%d",
×
92
                                frame.Function,
×
93
                                path.Base(frame.File),
×
94
                                frame.Line,
×
95
                        )
×
96
                }
×
97
                if more {
×
98
                        fmt.Fprintln(&traceback)
×
99
                }
×
100
                n--
×
101
        }
102
        return traceback.String()
×
103
}
104

105
func (mw *AccessLogMiddleware) LogFunc(
106
        ctx context.Context, startTime time.Time,
107
        w rest.ResponseWriter, r *rest.Request) {
2✔
108
        fields := logrus.Fields{
2✔
109
                "type": r.Proto,
2✔
110
                "ts": startTime.
2✔
111
                        Truncate(time.Millisecond).
2✔
112
                        Format(time.RFC3339Nano),
2✔
113
                "method":    r.Method,
2✔
114
                "path":      r.URL.Path,
2✔
115
                "useragent": r.UserAgent(),
2✔
116
                "qs":        r.URL.RawQuery,
2✔
117
        }
2✔
118
        if mw.ClientIPHook != nil {
2✔
119
                fields["clientip"] = mw.ClientIPHook(r.Request)
×
120
        }
×
121
        lc := fromContext(ctx)
2✔
122
        if lc != nil {
4✔
123
                lc.addFields(fields)
2✔
124
        }
2✔
125
        statusCode, _ := r.Env["STATUS_CODE"].(int)
2✔
126
        select {
2✔
127
        case <-ctx.Done():
×
128
                if errors.Is(ctx.Err(), context.Canceled) {
×
129
                        statusCode = StatusClientClosedConnection
×
130
                }
×
131
        default:
2✔
132
        }
133

134
        if panic := recover(); panic != nil {
2✔
135
                trace := collectTrace()
×
136
                fields["panic"] = panic
×
137
                fields["trace"] = trace
×
138
                // Wrap in recorder middleware to make sure the response is recorded
×
139
                mw.recorder.MiddlewareFunc(func(w rest.ResponseWriter, r *rest.Request) {
×
140
                        rest.Error(w, "Internal Server Error", http.StatusInternalServerError)
×
141
                })(w, r)
×
142
                statusCode = http.StatusInternalServerError
×
143
        } else if mw.DisableLog != nil && mw.DisableLog(statusCode, r) {
3✔
144
                return
1✔
145
        }
1✔
146
        rspTime := time.Since(startTime)
2✔
147
        // We do not need more than 3 digit fraction
2✔
148
        if rspTime > time.Second {
2✔
149
                rspTime = rspTime.Round(time.Millisecond)
×
150
        } else if rspTime > time.Millisecond {
4✔
151
                rspTime = rspTime.Round(time.Microsecond)
2✔
152
        }
2✔
153
        fields["responsetime"] = rspTime.String()
2✔
154
        fields["byteswritten"], _ = r.Env["BYTES_WRITTEN"].(int64)
2✔
155
        fields["status"] = statusCode
2✔
156

2✔
157
        logger := requestlog.GetRequestLogger(r)
2✔
158
        var level logrus.Level = logrus.InfoLevel
2✔
159
        if statusCode >= 500 {
3✔
160
                level = logrus.ErrorLevel
1✔
161
        } else if statusCode >= 300 {
5✔
162
                level = logrus.WarnLevel
2✔
163
        }
2✔
164
        logger.WithFields(fields).
2✔
165
                Log(level)
2✔
166
}
167

168
// MiddlewareFunc makes AccessLogMiddleware implement the Middleware interface.
169
func (mw *AccessLogMiddleware) MiddlewareFunc(h rest.HandlerFunc) rest.HandlerFunc {
2✔
170
        if mw.ClientIPHook == nil {
4✔
171
                // If not set, try get it from env
2✔
172
                mw.ClientIPHook = getClientIPFromEnv()
2✔
173
        }
2✔
174

175
        // This middleware depends on RecorderMiddleware to work
176
        mw.recorder = new(rest.RecorderMiddleware)
2✔
177
        return func(w rest.ResponseWriter, r *rest.Request) {
4✔
178
                ctx := r.Request.Context()
2✔
179
                startTime := time.Now()
2✔
180
                ctx = withContext(ctx, &logContext{maxErrors: DefaultMaxErrors})
2✔
181
                r.Request = r.Request.WithContext(ctx)
2✔
182
                defer mw.LogFunc(ctx, startTime, w, r)
2✔
183
                // call the handler inside recorder context
2✔
184
                mw.recorder.MiddlewareFunc(h)(w, r)
2✔
185
        }
2✔
186
}
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

© 2025 Coveralls, Inc