Skip to content

Commit 08506ee

Browse files
authored
feat(enhancement)!: seperate generate curl cmd from debug flow #928 (#934)
1 parent cf25584 commit 08506ee

File tree

7 files changed

+128
-88
lines changed

7 files changed

+128
-88
lines changed

client.go

+42-19
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ type Client struct {
209209
proxyURL *url.URL
210210
requestDebugLog DebugLogCallback
211211
responseDebugLog DebugLogCallback
212-
generateCurlOnDebug bool
212+
generateCurlCmd bool
213+
debugLogCurlCmd bool
213214
unescapeQueryParams bool
214215
loadBalancer LoadBalancer
215216
beforeRequest []RequestMiddleware
@@ -641,7 +642,8 @@ func (c *Client) R() *Request {
641642
jsonEscapeHTML: c.jsonEscapeHTML,
642643
log: c.log,
643644
setContentLength: c.setContentLength,
644-
generateCurlOnDebug: c.generateCurlOnDebug,
645+
generateCurlCmd: c.generateCurlCmd,
646+
debugLogCurlCmd: c.debugLogCurlCmd,
645647
unescapeQueryParams: c.unescapeQueryParams,
646648
credentials: c.credentials,
647649
}
@@ -731,7 +733,7 @@ func (c *Client) requestMiddlewares() []RequestMiddleware {
731733
func (c *Client) AddRequestMiddleware(m RequestMiddleware) *Client {
732734
c.lock.Lock()
733735
defer c.lock.Unlock()
734-
idx := len(c.beforeRequest) - 2
736+
idx := len(c.beforeRequest) - 1
735737
c.beforeRequest = slices.Insert(c.beforeRequest, idx, m)
736738
return c
737739
}
@@ -1965,35 +1967,56 @@ func (c *Client) SetTrace(t bool) *Client {
19651967
return c
19661968
}
19671969

1968-
// EnableGenerateCurlOnDebug method enables the generation of CURL commands in the debug log.
1969-
// It works in conjunction with debug mode.
1970+
// EnableGenerateCurlCmd method enables the generation of curl command at the
1971+
// client instance level.
1972+
//
1973+
// By default, Resty does not log the curl command in the debug log since it has the potential
1974+
// to leak sensitive data unless explicitly enabled via [Client.SetDebugLogCurlCmd].
19701975
//
19711976
// NOTE: Use with care.
1972-
// - Potential to leak sensitive data from [Request] and [Response] in the debug log.
1973-
// - Beware of memory usage since the request body is reread.
1974-
func (c *Client) EnableGenerateCurlOnDebug() *Client {
1975-
c.SetGenerateCurlOnDebug(true)
1977+
// - Potential to leak sensitive data from [Request] and [Response] in the debug log
1978+
// when the debug log option is enabled.
1979+
// - Additional memory usage since the request body was reread.
1980+
// - curl body is not generated for [io.Reader] and multipart request flow.
1981+
func (c *Client) EnableGenerateCurlCmd() *Client {
1982+
c.SetGenerateCurlCmd(true)
19761983
return c
19771984
}
19781985

1979-
// DisableGenerateCurlOnDebug method disables the option set by [Client.EnableGenerateCurlOnDebug].
1980-
func (c *Client) DisableGenerateCurlOnDebug() *Client {
1981-
c.SetGenerateCurlOnDebug(false)
1986+
// DisableGenerateCurlCmd method disables the option set by [Client.EnableGenerateCurlCmd] or
1987+
// [Client.SetGenerateCurlCmd].
1988+
func (c *Client) DisableGenerateCurlCmd() *Client {
1989+
c.SetGenerateCurlCmd(false)
19821990
return c
19831991
}
19841992

1985-
// SetGenerateCurlOnDebug method is used to turn on/off the generate CURL command in debug mode
1986-
// at the client instance level. It works in conjunction with debug mode.
1993+
// SetGenerateCurlCmd method is used to turn on/off the generate curl command at the
1994+
// client instance level.
1995+
//
1996+
// By default, Resty does not log the curl command in the debug log since it has the potential
1997+
// to leak sensitive data unless explicitly enabled via [Client.SetDebugLogCurlCmd].
19871998
//
19881999
// NOTE: Use with care.
1989-
// - Potential to leak sensitive data from [Request] and [Response] in the debug log.
1990-
// - Beware of memory usage since the request body is reread.
2000+
// - Potential to leak sensitive data from [Request] and [Response] in the debug log
2001+
// when the debug log option is enabled.
2002+
// - Additional memory usage since the request body was reread.
2003+
// - curl body is not generated for [io.Reader] and multipart request flow.
2004+
//
2005+
// It can be overridden at the request level; see [Request.SetGenerateCurlCmd]
2006+
func (c *Client) SetGenerateCurlCmd(b bool) *Client {
2007+
c.lock.Lock()
2008+
defer c.lock.Unlock()
2009+
c.generateCurlCmd = b
2010+
return c
2011+
}
2012+
2013+
// SetDebugLogCurlCmd method enables the curl command to be logged in the debug log.
19912014
//
1992-
// It can be overridden at the request level; see [Request.SetGenerateCurlOnDebug]
1993-
func (c *Client) SetGenerateCurlOnDebug(b bool) *Client {
2015+
// It can be overridden at the request level; see [Request.SetDebugLogCurlCmd]
2016+
func (c *Client) SetDebugLogCurlCmd(b bool) *Client {
19942017
c.lock.Lock()
19952018
defer c.lock.Unlock()
1996-
c.generateCurlOnDebug = b
2019+
c.debugLogCurlCmd = b
19972020
return c
19982021
}
19992022

curl.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ import (
1616
)
1717

1818
func buildCurlCmd(req *Request) string {
19-
// 1. Generate curl raw headers
19+
// generate curl raw headers
2020
var curl = "curl -X " + req.Method + " "
2121
headers := dumpCurlHeaders(req.RawRequest)
2222
for _, kv := range *headers {
2323
curl += "-H " + cmdQuote(kv[0]+": "+kv[1]) + " "
2424
}
2525

26-
// 2. Generate curl cookies
26+
// generate curl cookies
2727
if cookieJar := req.client.CookieJar(); cookieJar != nil {
2828
if cookies := cookieJar.Cookies(req.RawRequest.URL); len(cookies) > 0 {
2929
curl += "-H " + cmdQuote(dumpCurlCookies(cookies)) + " "
3030
}
3131
}
3232

33-
// 3. Generate curl body except for io.Reader and multipart request
33+
// generate curl body except for io.Reader and multipart request flow
3434
if req.RawRequest.GetBody != nil {
3535
body, err := req.RawRequest.GetBody()
3636
if err == nil {

curl_test.go

+18-15
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ func TestCurlGenerateUnexecutedRequest(t *testing.T) {
2727
).
2828
SetMethod(MethodPost)
2929

30-
assertEqual(t, "", req.GenerateCurlCommand())
30+
assertEqual(t, "", req.CurlCmd())
3131

32-
curlCmdUnexecuted := req.EnableGenerateCurlOnDebug().GenerateCurlCommand()
33-
req.DisableGenerateCurlOnDebug()
32+
curlCmdUnexecuted := req.EnableGenerateCurlCmd().CurlCmd()
33+
req.DisableGenerateCurlCmd()
3434

3535
if !strings.Contains(curlCmdUnexecuted, "Cookie: count=1") ||
3636
!strings.Contains(curlCmdUnexecuted, "curl -X POST") ||
@@ -60,15 +60,15 @@ func TestCurlGenerateExecutedRequest(t *testing.T) {
6060

6161
url := ts.URL + "/curl-cmd-post"
6262
resp, err := req.
63-
EnableGenerateCurlOnDebug().
63+
EnableGenerateCurlCmd().
6464
Post(url)
6565
if err != nil {
6666
t.Fatal(err)
6767
}
68-
curlCmdExecuted := resp.Request.GenerateCurlCommand()
68+
curlCmdExecuted := resp.Request.CurlCmd()
6969

70-
c.DisableGenerateCurlOnDebug()
71-
req.DisableGenerateCurlOnDebug()
70+
c.DisableGenerateCurlCmd()
71+
req.DisableGenerateCurlCmd()
7272
if !strings.Contains(curlCmdExecuted, "Cookie: count=1") ||
7373
!strings.Contains(curlCmdExecuted, "curl -X POST") ||
7474
!strings.Contains(curlCmdExecuted, `-d '{"name":"Resty"}'`) ||
@@ -84,17 +84,20 @@ func TestCurlCmdDebugMode(t *testing.T) {
8484
defer ts.Close()
8585

8686
c, logBuf := dcldb()
87+
c.EnableGenerateCurlCmd().
88+
SetDebugLogCurlCmd(true)
8789

8890
// Build request
89-
req := c.EnableGenerateCurlOnDebug().R().
91+
req := c.R().
9092
SetBody(map[string]string{
9193
"name": "Resty",
9294
}).
9395
SetCookies(
9496
[]*http.Cookie{
9597
{Name: "count", Value: "1"},
9698
},
97-
)
99+
).
100+
SetDebugLogCurlCmd(true)
98101

99102
// Execute request: set debug mode
100103
url := ts.URL + "/curl-cmd-post"
@@ -103,8 +106,8 @@ func TestCurlCmdDebugMode(t *testing.T) {
103106
t.Fatal(err)
104107
}
105108

106-
c.DisableGenerateCurlOnDebug()
107-
req.DisableGenerateCurlOnDebug()
109+
c.DisableGenerateCurlCmd()
110+
req.DisableGenerateCurlCmd()
108111

109112
// test logContent curl cmd
110113
logContent := logBuf.String()
@@ -237,10 +240,10 @@ func TestCurlRequestGetBodyError(t *testing.T) {
237240
).
238241
SetMethod(MethodPost)
239242

240-
assertEqual(t, "", req.GenerateCurlCommand())
243+
assertEqual(t, "", req.CurlCmd())
241244

242-
curlCmdUnexecuted := req.EnableGenerateCurlOnDebug().GenerateCurlCommand()
243-
req.DisableGenerateCurlOnDebug()
245+
curlCmdUnexecuted := req.EnableGenerateCurlCmd().CurlCmd()
246+
req.DisableGenerateCurlCmd()
244247

245248
if !strings.Contains(curlCmdUnexecuted, "Cookie: count=1") ||
246249
!strings.Contains(curlCmdUnexecuted, "curl -X POST") ||
@@ -261,7 +264,7 @@ func TestCurlRequestMiddlewaresError(t *testing.T) {
261264
PrepareRequestMiddleware,
262265
)
263266

264-
curlCmdUnexecuted := c.R().EnableGenerateCurlOnDebug().GenerateCurlCommand()
267+
curlCmdUnexecuted := c.R().EnableGenerateCurlCmd().CurlCmd()
265268
assertEqual(t, "", curlCmdUnexecuted)
266269
}
267270

middleware.go

+3-13
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,10 @@ func PrepareRequestMiddleware(c *Client, r *Request) (err error) {
4545
// is URL-related, and those get caught up in the `parseRequestURL`
4646
createRawRequest(c, r)
4747

48-
// last one doesn't need if condition
49-
return addCredentials(c, r)
50-
}
48+
addCredentials(c, r)
49+
50+
_ = r.generateCurlCommand()
5151

52-
// GenerateCurlRequestMiddleware method is used to perform CURL command
53-
// generation during a request preparation
54-
//
55-
// See, [Client.SetGenerateCurlOnDebug], [Request.SetGenerateCurlOnDebug]
56-
func GenerateCurlRequestMiddleware(c *Client, r *Request) (err error) {
57-
if r.Debug && r.generateCurlOnDebug {
58-
if isStringEmpty(r.resultCurlCmd) {
59-
r.resultCurlCmd = buildCurlCmd(r)
60-
}
61-
}
6252
return nil
6353
}
6454

request.go

+61-36
Original file line numberDiff line numberDiff line change
@@ -95,29 +95,12 @@ type Request struct {
9595
multipartFields []*MultipartField
9696
retryConditions []RetryConditionFunc
9797
resultCurlCmd string
98-
generateCurlOnDebug bool
98+
generateCurlCmd bool
99+
debugLogCurlCmd bool
99100
unescapeQueryParams bool
100101
multipartErrChan chan error
101102
}
102103

103-
// GenerateCurlCommand method generates the CURL command for the request.
104-
func (r *Request) GenerateCurlCommand() string {
105-
if !(r.Debug && r.generateCurlOnDebug) {
106-
return ""
107-
}
108-
if len(r.resultCurlCmd) > 0 {
109-
return r.resultCurlCmd
110-
}
111-
if r.RawRequest == nil {
112-
if err := r.client.executeRequestMiddlewares(r); err != nil {
113-
r.log.Errorf("%v", err)
114-
return ""
115-
}
116-
}
117-
r.resultCurlCmd = buildCurlCmd(r)
118-
return r.resultCurlCmd
119-
}
120-
121104
// SetMethod method used to set the HTTP verb for the request
122105
func (r *Request) SetMethod(m string) *Request {
123106
r.Method = m
@@ -1086,37 +1069,79 @@ func (r *Request) SetTrace(t bool) *Request {
10861069
return r
10871070
}
10881071

1089-
// EnableGenerateCurlOnDebug method enables the generation of CURL commands in the debug log.
1090-
// It works in conjunction with debug mode. It overrides the options set by the [Client].
1072+
// EnableGenerateCurlCmd method enables the generation of curl commands for the current request.
1073+
// It overrides the options set in the [Client].
1074+
//
1075+
// By default, Resty does not log the curl command in the debug log since it has the potential
1076+
// to leak sensitive data unless explicitly enabled via [Request.SetDebugLogCurlCmd].
10911077
//
10921078
// NOTE: Use with care.
1093-
// - Potential to leak sensitive data from [Request] and [Response] in the debug log.
1094-
// - Beware of memory usage since the request body is reread.
1095-
func (r *Request) EnableGenerateCurlOnDebug() *Request {
1096-
r.SetGenerateCurlOnDebug(true)
1079+
// - Potential to leak sensitive data from [Request] and [Response] in the debug log
1080+
// when the debug log option is enabled.
1081+
// - Additional memory usage since the request body was reread.
1082+
// - curl body is not generated for [io.Reader] and multipart request flow.
1083+
func (r *Request) EnableGenerateCurlCmd() *Request {
1084+
r.SetGenerateCurlCmd(true)
10971085
return r
10981086
}
10991087

1100-
// DisableGenerateCurlOnDebug method disables the option set by [Request.EnableGenerateCurlOnDebug].
1101-
// It overrides the options set by the [Client].
1102-
func (r *Request) DisableGenerateCurlOnDebug() *Request {
1103-
r.SetGenerateCurlOnDebug(false)
1088+
// DisableGenerateCurlCmd method disables the option set by [Request.EnableGenerateCurlCmd] or
1089+
// [Request.SetGenerateCurlCmd].
1090+
//
1091+
// It overrides the options set in the [Client].
1092+
func (r *Request) DisableGenerateCurlCmd() *Request {
1093+
r.SetGenerateCurlCmd(false)
11041094
return r
11051095
}
11061096

1107-
// SetGenerateCurlOnDebug method is used to turn on/off the generate CURL command in debug mode.
1108-
// It works in conjunction with debug mode.
1097+
// SetGenerateCurlCmd method is used to turn on/off the generate curl command for the current request.
1098+
//
1099+
// By default, Resty does not log the curl command in the debug log since it has the potential
1100+
// to leak sensitive data unless explicitly enabled via [Request.SetDebugLogCurlCmd].
11091101
//
11101102
// NOTE: Use with care.
1111-
// - Potential to leak sensitive data from [Request] and [Response] in the debug log.
1112-
// - Beware of memory usage since the request body is reread.
1103+
// - Potential to leak sensitive data from [Request] and [Response] in the debug log
1104+
// when the debug log option is enabled.
1105+
// - Additional memory usage since the request body was reread.
1106+
// - curl body is not generated for [io.Reader] and multipart request flow.
11131107
//
1114-
// It overrides the options set by the [Client.SetGenerateCurlOnDebug]
1115-
func (r *Request) SetGenerateCurlOnDebug(b bool) *Request {
1116-
r.generateCurlOnDebug = b
1108+
// It overrides the options set by the [Client.SetGenerateCurlCmd]
1109+
func (r *Request) SetGenerateCurlCmd(b bool) *Request {
1110+
r.generateCurlCmd = b
11171111
return r
11181112
}
11191113

1114+
// SetDebugLogCurlCmd method enables the curl command to be logged in the debug log
1115+
// for the current request.
1116+
//
1117+
// It can be overridden at the request level; see [Client.SetDebugLogCurlCmd]
1118+
func (r *Request) SetDebugLogCurlCmd(b bool) *Request {
1119+
r.debugLogCurlCmd = b
1120+
return r
1121+
}
1122+
1123+
// CurlCmd method generates the curl command for the request.
1124+
func (r *Request) CurlCmd() string {
1125+
return r.generateCurlCommand()
1126+
}
1127+
1128+
func (r *Request) generateCurlCommand() string {
1129+
if !r.generateCurlCmd {
1130+
return ""
1131+
}
1132+
if len(r.resultCurlCmd) > 0 {
1133+
return r.resultCurlCmd
1134+
}
1135+
if r.RawRequest == nil {
1136+
if err := r.client.executeRequestMiddlewares(r); err != nil {
1137+
r.log.Errorf("%v", err)
1138+
return ""
1139+
}
1140+
}
1141+
r.resultCurlCmd = buildCurlCmd(r)
1142+
return r.resultCurlCmd
1143+
}
1144+
11201145
// SetUnescapeQueryParams method sets the choice of unescape query parameters for the request URL.
11211146
// To prevent broken URL, Resty replaces space (" ") with "+" in the query parameters.
11221147
//

resty.go

-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ func createClient(hc *http.Client) *Client {
196196
// request middlewares
197197
c.SetRequestMiddlewares(
198198
PrepareRequestMiddleware,
199-
GenerateCurlRequestMiddleware,
200199
)
201200

202201
// response middlewares

util.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ func requestDebugLogger(c *Client, r *Request) {
363363

364364
reqLog := "\n==============================================================================\n"
365365

366-
if r.Debug && r.generateCurlOnDebug {
366+
if r.generateCurlCmd && r.debugLogCurlCmd {
367367
reqLog += "~~~ REQUEST(CURL) ~~~\n" +
368368
fmt.Sprintf(" %v\n", r.resultCurlCmd)
369369
}

0 commit comments

Comments
 (0)