Skip to content

Commit 5d35b55

Browse files
committed
reqbuilder: fix non GET methods, add python requests support
1 parent 6047a66 commit 5d35b55

File tree

2 files changed

+228
-27
lines changed

2 files changed

+228
-27
lines changed

pkg/server/templates/content/tab_reqbuilder.templ

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type ReqBuilderForm struct {
2626

2727
templ ReqBuilderTab(txsSet vsl.TransactionSet) {
2828
<div id="tabRequest" class="tabcontent">
29-
<p>Here you can generate a <a href="https://curl.se/" target="_blank">curl</a> command based on parsed transactions VSL tags.</p>
29+
<p>Here you can generate commands with <a href="https://curl.se/" target="_blank">curl</a> and other tools based on parsed VSL transaction tags. For POST/PUT requests, the <b>body is not available</b> in varnishlog and won’t be included.</p>
3030
<form
3131
class="simple-form"
3232
hx-post="/reqbuilder/"
@@ -108,22 +108,22 @@ templ ReqBuilderTab(txsSet vsl.TransactionSet) {
108108

109109
templ ReqBuild(txsSet vsl.TransactionSet, tx *vsl.Transaction, f ReqBuilderForm) {
110110
<div class="fade-me-in">
111-
<h3>Command</h3>
111+
<h3>curl</h3>
112112
<pre>
113113
<code>
114-
@templ.Raw(curlHeaders(tx, f))
114+
@templ.Raw(curlCommand(tx, f))
115115
</code>
116116
</pre>
117-
<h3>{ tx.TXID() }</h3>
117+
<h3>python</h3>
118118
<pre>
119119
<code>
120-
@templ.Raw(tx.FullRawLog(false))
120+
@templ.Raw(pythonCommand(tx, f))
121121
</code>
122122
</pre>
123123
</div>
124124
}
125125

126-
func curlHeaders(t *vsl.Transaction, f ReqBuilderForm) string {
126+
func curlCommand(t *vsl.Transaction, f ReqBuilderForm) string {
127127
var s strings.Builder
128128

129129
hdrState := header.NewHeaderState(t.LogRecords(), false)
@@ -153,6 +153,22 @@ func curlHeaders(t *vsl.Transaction, f ReqBuilderForm) string {
153153
}
154154
s.WriteString(fmt.Sprintf(`curl "%s://%s%s"`+" \\\n", protocol, hostHdr.HeaderValue(), url.Value()))
155155

156+
// Method
157+
method := t.FirstRecordOfType(vsl.MethodRecord{})
158+
if method == nil {
159+
return "Method not found!"
160+
}
161+
162+
switch method.Value() {
163+
case "GET":
164+
// Nothing
165+
case "POST", "PUT":
166+
s.WriteString(" -X " + method.Value() + " \\\n")
167+
s.WriteString(" -d '' \\\n")
168+
default:
169+
s.WriteString(" -X " + method.Value() + " \\\n")
170+
}
171+
156172
// Add headers
157173
var hdrVal string
158174
for _, hc := range hdrState {
@@ -164,11 +180,12 @@ func curlHeaders(t *vsl.Transaction, f ReqBuilderForm) string {
164180
} else {
165181
hdrVal = hc.FinalValue()
166182
}
183+
hdrVal = strings.ReplaceAll(hdrVal, `"`, `\"`)
167184
s.WriteString(fmt.Sprintf(` -H "%s: %s" \`+"\n", hc.Header(), hdrVal))
168185
}
169186

170187
// Fixed options
171-
s.WriteString(" -s -v -o /dev/null")
188+
s.WriteString(" -s -k -v -o /dev/null")
172189

173190
// Optional resolve
174191
switch f.ResolveTo {
@@ -192,6 +209,96 @@ func curlHeaders(t *vsl.Transaction, f ReqBuilderForm) string {
192209
return s.String()
193210
}
194211

212+
func pythonCommand(t *vsl.Transaction, f ReqBuilderForm) string {
213+
var s strings.Builder
214+
215+
hdrState := header.NewHeaderState(t.LogRecords(), false)
216+
217+
// Find the host header
218+
hostHdr := hdrState.FindHeader("host", f.OriginalHeaders, true)
219+
if hostHdr == nil {
220+
return "Host header not found!"
221+
}
222+
223+
// Find the URL
224+
var url vsl.Record
225+
if f.OriginalURL {
226+
url = t.FirstRecordOfType(vsl.URLRecord{})
227+
} else {
228+
url = t.LastRecordOfType(vsl.URLRecord{})
229+
}
230+
if url == nil {
231+
return "URL not found!"
232+
}
233+
234+
// Set the protocol and port
235+
port := "80"
236+
protocol := "http"
237+
if f.HTTPS {
238+
port = "443"
239+
protocol = "https"
240+
}
241+
242+
s.WriteString("import requests\n\n")
243+
244+
includeHostHdr := false
245+
246+
// Optional resolve
247+
switch f.ResolveTo {
248+
case SendToLocalhost:
249+
s.WriteString(fmt.Sprintf("url = \"%s://%s%s\"\n\n", protocol, "127.0.0.1:"+port, url.Value()))
250+
includeHostHdr = true
251+
case SendToBackend, SendToCustom:
252+
custom := strings.SplitN(f.CustomResolve, ":", 2)
253+
if custom[0] == "none" {
254+
return "Backed address not found for selected transaction."
255+
}
256+
if len(custom) < 2 {
257+
return "Incorrect backend address."
258+
}
259+
s.WriteString(fmt.Sprintf("url = \"%s://%s%s\"\n\n", protocol, custom[0]+":"+custom[1], url.Value()))
260+
includeHostHdr = true
261+
}
262+
263+
// Add headers
264+
s.WriteString("headers = {\n")
265+
if includeHostHdr {
266+
s.WriteString(fmt.Sprintf(" \"%s\": \"%s\",\n", "Host", hostHdr.HeaderValue()))
267+
}
268+
for _, hc := range hdrState {
269+
if hc.Header() == "host" || (f.OriginalHeaders && !hc.IsOriginalHeader()) {
270+
continue
271+
}
272+
var hdrVal string
273+
if f.OriginalHeaders {
274+
hdrVal = hc.OriginalValue()
275+
} else {
276+
hdrVal = hc.FinalValue()
277+
}
278+
hdrVal = strings.ReplaceAll(hdrVal, `"`, `\"`)
279+
s.WriteString(fmt.Sprintf(" \"%s\": \"%s\",\n", hc.Header(), hdrVal))
280+
}
281+
s.WriteString("}\n\n")
282+
283+
// Method
284+
method := t.FirstRecordOfType(vsl.MethodRecord{})
285+
if method == nil {
286+
return "Method not found!"
287+
}
288+
switch method.Value() {
289+
case "GET":
290+
s.WriteString("response = requests.get(url, headers=headers, verify=False)\n")
291+
case "POST", "PUT":
292+
s.WriteString("response = requests." + strings.ToLower(method.Value()) + "(url, headers=headers, verify=False, data={})\n")
293+
default:
294+
s.WriteString("response = requests." + strings.ToLower(method.Value()) + "(url, headers=headers, verify=False)\n")
295+
}
296+
297+
s.WriteString("\nprint(response.status_code)\nprint(response.text)\n")
298+
299+
return s.String()
300+
}
301+
195302
func getBackend(t *vsl.Transaction) string {
196303
r := t.FirstRecordOfType(vsl.BackendOpenRecord{})
197304
if r == nil {

pkg/server/templates/content/tab_reqbuilder_templ.go

Lines changed: 114 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)