@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 118 lines 3.22 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
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
15 package caddyhttp
16
17 import (
18 "errors"
19 "fmt"
20 weakrand "math/rand/v2"
21 "path"
22 "runtime"
23 "strings"
24
25 "github.com/caddyserver/caddy/v2"
26 )
27
28 // Error is a convenient way for a Handler to populate the
29 // essential fields of a HandlerError. If err is itself a
30 // HandlerError, then any essential fields that are not
31 // set will be populated.
32 func Error(statusCode int, err error) HandlerError {
33 const idLen = 9
34 if he, ok := errors.AsType[HandlerError](err); ok {
35 if he.ID == "" {
36 he.ID = randString(idLen, true)
37 }
38 if he.Trace == "" {
39 he.Trace = trace()
40 }
41 if he.StatusCode == 0 {
42 he.StatusCode = statusCode
43 }
44 return he
45 }
46 return HandlerError{
47 ID: randString(idLen, true),
48 StatusCode: statusCode,
49 Err: err,
50 Trace: trace(),
51 }
52 }
53
54 // HandlerError is a serializable representation of
55 // an error from within an HTTP handler.
56 type HandlerError struct {
57 Err error // the original error value and message
58 StatusCode int // the HTTP status code to associate with this error
59
60 ID string // generated; for identifying this error in logs
61 Trace string // produced from call stack
62 }
63
64 func (e HandlerError) Error() string {
65 var s string
66 if e.ID != "" {
67 s += fmt.Sprintf("{id=%s}", e.ID)
68 }
69 if e.Trace != "" {
70 s += " " + e.Trace
71 }
72 if e.StatusCode != 0 {
73 s += fmt.Sprintf(": HTTP %d", e.StatusCode)
74 }
75 if e.Err != nil {
76 s += ": " + e.Err.Error()
77 }
78 return strings.TrimSpace(s)
79 }
80
81 // Unwrap returns the underlying error value. See the `errors` package for info.
82 func (e HandlerError) Unwrap() error { return e.Err }
83
84 // randString returns a string of n random characters.
85 // It is not even remotely secure OR a proper distribution.
86 // But it's good enough for some things. It excludes certain
87 // confusing characters.
88 // If sameCase is false, then l, I, O, S, 1, and 0 are excluded.
89 // If sameCase is true, then uppercase letters are excluded in
90 // addition to l, o, 1, and 0.
91 func randString(n int, sameCase bool) string {
92 if n <= 0 {
93 return ""
94 }
95 dict := []byte("abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY23456789")
96 if sameCase {
97 dict = []byte("abcdefghijkmnpqrstuvwxyz23456789")
98 }
99 b := make([]byte, n)
100 for i := range b {
101 //nolint:gosec
102 b[i] = dict[weakrand.IntN(len(dict))]
103 }
104 return string(b)
105 }
106
107 func trace() string {
108 if pc, file, line, ok := runtime.Caller(2); ok {
109 filename := path.Base(file)
110 pkgAndFuncName := path.Base(runtime.FuncForPC(pc).Name())
111 return fmt.Sprintf("%s (%s:%d)", pkgAndFuncName, filename, line)
112 }
113 return ""
114 }
115
116 // ErrorCtxKey is the context key to use when storing
117 // an error (for use with context.Context).
118 const ErrorCtxKey = caddy.CtxKey("handler_chain_error")