1
1
package server
2
2
3
3
import (
4
+ "encoding/json"
4
5
"errors"
5
6
"fmt"
6
7
"net/http"
7
- "net/url"
8
8
"runtime/debug"
9
9
"strconv"
10
10
"sync"
@@ -24,12 +24,18 @@ var (
24
24
errLabelIsRequired = errors .New ("label parameter is required" )
25
25
errNoData = errors .New ("no data" )
26
26
errTimeParamsAreRequired = errors .New ("leftFrom,leftUntil,rightFrom,rightUntil are required" )
27
+ errMethodNotAllowed = errors .New ("Method not allowed" )
27
28
)
28
29
29
30
type renderParams struct {
30
31
format string
31
32
maxNodes int
32
33
gi * storage.GetInput
34
+
35
+ leftStartTime time.Time
36
+ leftEndTime time.Time
37
+ rghtStartTime time.Time
38
+ rghtEndTime time.Time
33
39
}
34
40
35
41
func (ctrl * Controller ) renderHandler (w http.ResponseWriter , r * http.Request ) {
@@ -38,7 +44,9 @@ func (ctrl *Controller) renderHandler(w http.ResponseWriter, r *http.Request) {
38
44
ctrl .writeInvalidParameterError (w , err )
39
45
return
40
46
}
41
- if ok := ctrl .expectJSON (w , p .format ); ! ok {
47
+
48
+ if err := ctrl .expectJSON (p .format ); err != nil {
49
+ ctrl .writeInvalidParameterError (w , errUnknownFormat )
42
50
return
43
51
}
44
52
@@ -59,17 +67,41 @@ func (ctrl *Controller) renderHandler(w http.ResponseWriter, r *http.Request) {
59
67
}
60
68
61
69
func (ctrl * Controller ) renderDiffHandler (w http.ResponseWriter , r * http.Request ) {
62
- var p renderParams
63
- if err := ctrl .renderParametersFromRequest (r , & p ); err != nil {
64
- ctrl .writeInvalidParameterError (w , err )
65
- return
66
- }
67
- if ok := ctrl .expectJSON (w , p .format ); ! ok {
70
+
71
+ var (
72
+ p renderParams
73
+ rP RenderDiffParams
74
+
75
+ leftStartParam string
76
+ leftEndParam string
77
+ rghtStartParam string
78
+ rghtEndParam string
79
+ )
80
+
81
+ switch r .Method {
82
+ case http .MethodGet :
83
+ if err := ctrl .renderParametersFromRequest (r , & p ); err != nil {
84
+ ctrl .writeInvalidParameterError (w , err )
85
+ return
86
+ }
87
+ leftStartParam , leftEndParam = "leftFrom" , "leftUntil"
88
+ rghtStartParam , rghtEndParam = "rightFrom" , "rightUntil"
89
+
90
+ case http .MethodPost :
91
+ if err := ctrl .renderParametersFromRequestBody (r , & p , & rP ); err != nil {
92
+ ctrl .writeInvalidParameterError (w , err )
93
+ return
94
+ }
95
+ leftStartParam , leftEndParam = rP .Left .From , rP .Left .Until
96
+ rghtStartParam , rghtEndParam = rP .Right .From , rP .Right .Until
97
+
98
+ default :
99
+ ctrl .writeInvalidMethodError (w , errMethodNotAllowed )
68
100
return
69
101
}
70
102
71
- leftStartTime , leftEndTime , leftOK := parseRenderRangeParams (r . URL . Query (), "leftFrom" , "leftUntil" )
72
- rghtStartTime , rghtEndTime , rghtOK := parseRenderRangeParams (r . URL . Query (), "rightFrom" , "rightUntil" )
103
+ leftStartTime , leftEndTime , leftOK := parseRenderRangeParams (r , leftStartParam , leftEndParam )
104
+ rghtStartTime , rghtEndTime , rghtOK := parseRenderRangeParams (r , rghtStartParam , rghtEndParam )
73
105
if ! leftOK || ! rghtOK {
74
106
ctrl .writeInvalidParameterError (w , errTimeParamsAreRequired )
75
107
return
@@ -124,6 +156,52 @@ func (ctrl *Controller) renderParametersFromRequest(r *http.Request, p *renderPa
124
156
p .gi .StartTime = attime .Parse (v .Get ("from" ))
125
157
p .gi .EndTime = attime .Parse (v .Get ("until" ))
126
158
p .format = v .Get ("format" )
159
+
160
+ if err := ctrl .expectJSON (p .format ); err != nil {
161
+ return err
162
+ }
163
+
164
+ return nil
165
+ }
166
+
167
+ func (ctrl * Controller ) renderParametersFromRequestBody (r * http.Request , p * renderParams , rP * RenderDiffParams ) error {
168
+
169
+ decoder := json .NewDecoder (r .Body )
170
+ if err := decoder .Decode (rP ); err != nil {
171
+ return err
172
+ }
173
+
174
+ p .gi = new (storage.GetInput )
175
+ switch {
176
+ case rP .Name == nil && rP .Query == nil :
177
+ return fmt .Errorf ("'query' or 'name' parameter is required" )
178
+ case rP .Name != nil :
179
+ sk , err := segment .ParseKey (* rP .Name )
180
+ if err != nil {
181
+ return fmt .Errorf ("name: parsing storage key: %w" , err )
182
+ }
183
+ p .gi .Key = sk
184
+ case rP .Query != nil :
185
+ qry , err := flameql .ParseQuery (* rP .Query )
186
+ if err != nil {
187
+ return fmt .Errorf ("query: %w" , err )
188
+ }
189
+ p .gi .Query = qry
190
+ }
191
+
192
+ p .maxNodes = ctrl .config .MaxNodesRender
193
+ if rP .MaxNodes != nil && * rP .MaxNodes > 0 {
194
+ p .maxNodes = * rP .MaxNodes
195
+ }
196
+
197
+ p .gi .StartTime = attime .Parse (rP .From )
198
+ p .gi .EndTime = attime .Parse (rP .Until )
199
+ p .format = rP .Format
200
+
201
+ if err := ctrl .expectJSON (p .format ); err != nil {
202
+ return err
203
+ }
204
+
127
205
return nil
128
206
}
129
207
@@ -145,10 +223,20 @@ func renderResponse(fs *tree.Flamebearer, out *storage.GetOutput) map[string]int
145
223
return res
146
224
}
147
225
148
- func parseRenderRangeParams (v url.Values , from , until string ) (startTime , endTime time.Time , ok bool ) {
149
- fromStr , untilStr := v .Get (from ), v .Get (until )
150
- startTime , endTime = attime .Parse (fromStr ), attime .Parse (untilStr )
151
- return startTime , endTime , fromStr != "" || untilStr != ""
226
+ func parseRenderRangeParams (r * http.Request , from , until string ) (startTime , endTime time.Time , ok bool ) {
227
+
228
+ switch r .Method {
229
+ case http .MethodGet :
230
+ fromStr , untilStr := r .URL .Query ().Get (from ), r .URL .Query ().Get (until )
231
+ startTime , endTime = attime .Parse (fromStr ), attime .Parse (untilStr )
232
+ return startTime , endTime , fromStr != "" || untilStr != ""
233
+ case http .MethodPost :
234
+ startTime , endTime = attime .Parse (from ), attime .Parse (until )
235
+ return startTime , endTime , from != "" || until != ""
236
+ }
237
+
238
+ return time .Now (), time .Now (), false
239
+
152
240
}
153
241
154
242
func (ctrl * Controller ) loadTreeConcurrently (
@@ -198,3 +286,23 @@ func (ctrl *Controller) loadTree(gi *storage.GetInput, startTime, endTime time.T
198
286
}
199
287
return out , nil
200
288
}
289
+
290
+ // Request Body Interface
291
+ type RenderDiffParams struct {
292
+ Name * string `json:"name,omitempty"`
293
+ Query * string `json:"query,omitempty"`
294
+
295
+ From string `json:"from"`
296
+ Until string `json:"until"`
297
+
298
+ Format string `json:"format"`
299
+ MaxNodes * int `json:"maxNodes,omitempty"`
300
+
301
+ Left RenderTreeParams `json:"leftParams"`
302
+ Right RenderTreeParams `json:"rightParams"`
303
+ }
304
+
305
+ type RenderTreeParams struct {
306
+ From string `json:"from"`
307
+ Until string `json:"until"`
308
+ }
0 commit comments