cubefs

Форк
0
175 строк · 3.7 Кб
1
// Copyright 2022 The CubeFS 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
12
// implied. See the License for the specific language governing
13
// permissions and limitations under the License.
14

15
package auditlog
16

17
import (
18
	"bytes"
19
	"encoding/json"
20
	"errors"
21
	"io"
22
	"net"
23
	"net/http"
24

25
	"github.com/cubefs/cubefs/blobstore/common/rpc"
26
	"github.com/cubefs/cubefs/blobstore/common/rpc/auth"
27
)
28

29
const maxSeekableBodyLength = 1 << 10
30

31
var DefaultRequestHeaderKeys = []string{
32
	"User-Agent",
33
	"Range",
34
	"Refer",
35
	"Referer",
36
	"Origin",
37
	"Content-Length",
38
	"Accept-Encoding",
39
	"If-None-Match",
40
	"If-Modified-Since",
41

42
	"Cdn",
43
	"Cdn-Src-Ip",
44
	"Cdn-Scheme",
45

46
	"X-Real-Ip",
47
	"X-Forwarded-For",
48
	"X-Scheme",
49
	"X-Remote-Ip",
50
	"X-From-Cdn",
51
	"X-Id",
52
	"X-From-Proxy-Getter",
53
	"X-From-Fsrcproxy",
54
	"X-Upload-Encoding",
55
	"X-Src",
56

57
	auth.TokenHeaderKey,
58
}
59

60
type DecodedReq struct {
61
	Path   string
62
	Header M
63
	Params []byte
64
}
65

66
type ReadCloser struct {
67
	io.Reader
68
	io.Closer
69
}
70

71
type M map[string]interface{}
72

73
func (m M) Encode() []byte {
74
	if len(m) > 0 {
75
		ret, _ := json.Marshal(m)
76
		return ret
77
	}
78
	return nil
79
}
80

81
type defaultDecoder struct{}
82

83
func (d *defaultDecoder) DecodeReq(req *http.Request) *DecodedReq {
84
	header := req.Header
85
	clientIP, _, err := net.SplitHostPort(req.RemoteAddr)
86
	if err != nil {
87
		clientIP = req.RemoteAddr
88
	}
89
	decodedReq := &DecodedReq{
90
		Header: M{"IP": clientIP, "Host": req.Host},
91
		Path:   req.URL.Path,
92
	}
93

94
	// decode header information
95
	if req.URL.RawQuery != "" {
96
		decodedReq.Header["RawQuery"] = req.URL.RawQuery
97
	}
98
	cm := req.Header.Get("Content-MD5")
99
	if cm != "" {
100
		decodedReq.Header["Content-MD5"] = cm
101
	}
102

103
	for _, key := range DefaultRequestHeaderKeys {
104
		if v, ok := header[key]; ok {
105
			decodedReq.Header[key] = v[0]
106
		}
107
	}
108
	// crc check header
109
	if encoded, ok := req.Header[rpc.HeaderCrcEncoded]; ok {
110
		decodedReq.Header[rpc.HeaderCrcEncoded] = encoded[0]
111
	}
112

113
	// decode request params, including:
114
	// 1. form-urlencoded
115
	// 2. json
116
	contentType, ok := req.Header["Content-Type"]
117
	if ok {
118
		decodedReq.Header["Content-Type"] = contentType[0]
119
	}
120
	if ok {
121
		switch contentType[0] {
122
		case rpc.MIMEPOSTForm:
123
			buff, err := d.readFull(req)
124
			if err == nil {
125
				req.Body = ReadCloser{bytes.NewReader(buff), req.Body}
126
				req.ParseForm()
127
				params := make(M)
128
				for k, v := range req.Form {
129
					if len(v) == 1 {
130
						params[k] = v[0]
131
					} else {
132
						params[k] = v
133
					}
134
				}
135
				decodedReq.Params = params.Encode()
136
			}
137
		case rpc.MIMEJSON:
138
			buff, err := d.readFull(req)
139
			if err == nil {
140
				req.Body = ReadCloser{bytes.NewReader(buff), req.Body}
141
				// check if request body is valid or not, and do not print invalid request body in audit log
142
				if json.Valid(buff) {
143
					decodedReq.Params = compactNewline(buff)
144
				}
145
			}
146
		default:
147
		}
148
	}
149
	return decodedReq
150
}
151

152
func (d *defaultDecoder) readFull(req *http.Request) ([]byte, error) {
153
	if req.ContentLength > maxSeekableBodyLength {
154
		return nil, errors.New("too large body for form or json")
155
	}
156

157
	buff := make([]byte, req.ContentLength)
158
	_, err := io.ReadFull(req.Body, buff)
159
	if err != nil {
160
		return nil, err
161
	}
162
	return buff, nil
163
}
164

165
// compactNewline json compact if buffer has '\n'(0x0a).
166
func compactNewline(src []byte) []byte {
167
	if bytes.IndexByte(src, 0x0a) < 0 {
168
		return src
169
	}
170
	newBuff := bytes.NewBuffer(make([]byte, 0, len(src)))
171
	if err := json.Compact(newBuff, src); err == nil {
172
		return newBuff.Bytes()
173
	}
174
	return src
175
}
176

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.