-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.go
188 lines (153 loc) · 4.39 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package main
import (
"fmt"
authlib "github.com/clawio/service-auth/lib"
metapb "github.com/clawio/service-ocwebdav/proto/metadata"
"github.com/nu7hatch/gouuid"
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
"google.golang.org/grpc"
metadata "google.golang.org/grpc/metadata"
"net/http"
"path"
"regexp"
"strconv"
"strings"
)
func getMeta(ctx context.Context, addr, p string, children bool) (*metapb.Metadata, error) {
in := &metapb.StatReq{}
in.AccessToken = authlib.MustFromTokenContext(ctx)
in.Children = children
in.Path = p
con, err := getConnection(addr)
if err != nil {
return nil, err
}
defer con.Close()
client := metapb.NewMetaClient(con)
meta, err := client.Stat(ctx, in)
if err != nil {
return nil, err
}
return meta, nil
}
func getIdentityFromReq(r *http.Request, secret string) (*authlib.Identity, error) {
return authlib.ParseToken(getTokenFromReq(r), secret)
}
func getPathFromReq(r *http.Request) string {
return path.Join("/", strings.TrimPrefix(r.URL.Path, remoteURL))
}
func getConnection(addr string) (*grpc.ClientConn, error) {
con, err := grpc.Dial(addr, grpc.WithInsecure())
if err != nil {
return nil, err
}
return con, nil
}
// getTraceID returns the traceID that comes in the request
// or generate a new one
func getTraceID(r *http.Request) (string, error) {
traceID := r.Header.Get("CIO-TraceID")
if traceID == "" {
u, err := uuid.NewV4()
if err != nil {
return "", err
}
return u.String(), nil
}
return traceID, nil
}
// The key type is unexported to prevent collisions with context keys defined in
// other packages.
type key int
// logKey is the context key for an identity. Its value of zero is
// arbitrary. If this package defined other context keys, they would have
// different integer values.
const logKey key = 0
// NewLogContext returns a new Context carrying a logger.
func NewLogContext(ctx context.Context, logger *log.Entry) context.Context {
return context.WithValue(ctx, logKey, logger)
}
// MustFromLogContext extracts the logger from ctx.
// If not present it panics.
func MustFromLogContext(ctx context.Context) *log.Entry {
val, ok := ctx.Value(logKey).(*log.Entry)
if !ok {
panic("logger is not registered")
}
return val
}
func getTokenFromReq(r *http.Request) string {
var token string
// Look for cookie - Just for OwnCloud
authCookie, err := r.Cookie("OC_SessionPassphrase")
if err == nil && authCookie.Value != "" {
return authCookie.Value
}
// Look for an Authorization header
if ah := r.Header.Get("Authorization"); ah != "" {
// Should be a bearer token
if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
token = ah[7:]
}
}
if token == "" {
// Look for "auth_token" parameter
r.ParseMultipartForm(10e6)
if tokStr := r.Form.Get("access_token"); tokStr != "" {
token = tokStr
}
}
return token
}
func newGRPCTraceContext(ctx context.Context, trace string) context.Context {
md := metadata.Pairs("trace", trace)
ctx = metadata.NewContext(ctx, md)
return ctx
}
type chunkPathInfo struct {
ResourcePath string
TransferID string
TotalChunks uint64
CurrentChunk uint64
}
func (c *chunkPathInfo) UploadID() string {
return "chunking-" + c.TransferID + "-" + strconv.FormatUint(c.TotalChunks, 10)
}
type chunkHeaderInfo struct {
// OC-Chunked = 1
OCChunked bool
// OC-Chunk-Size
OCChunkSize uint64
// OC-Total-Length
OCTotalLength uint64
}
func (c *chunkPathInfo) String() string {
return fmt.Sprintf("< path:%s total_chunks:%d current_chunk:%d id:%s >", c.ResourcePath, c.TotalChunks, c.CurrentChunk, c.TransferID)
}
// IsChunked determines if an upload is chunked or not.
func isChunked(p string) (bool, error) {
return regexp.MatchString(`-chunking-\w+-[0-9]+-[0-9]+$`, p)
}
// GetChunkPathInfo obtains the different parts of a chunk from the path.
func getChunkPathInfo(p string) (*chunkPathInfo, error) {
parts := strings.Split(p, "-chunking-")
tail := strings.Split(parts[1], "-")
totalChunks, err := strconv.ParseUint(tail[1], 10, 64)
if err != nil {
return nil, err
}
currentChunk, err := strconv.ParseUint(tail[2], 10, 64)
if err != nil {
return nil, err
}
if currentChunk >= totalChunks {
return nil, fmt.Errorf("current chunk:%d exceeds total chunks:%d.", currentChunk, totalChunks)
}
info := &chunkPathInfo{}
info.ResourcePath = parts[0]
info.TransferID = tail[0]
info.TotalChunks = totalChunks
info.CurrentChunk = currentChunk
return info, nil
}