Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion pkg/linters/httpnoctx/httpnoctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,17 @@ func isHTTPPackage(pass *analysis.Pass, expr ast.Expr) bool {
func hasContextInEnclosingFunc(pass *analysis.Pass, cursor inspector.Cursor) bool {
for enclosing := range cursor.Enclosing((*ast.FuncDecl)(nil), (*ast.FuncLit)(nil)) {
fnType := astutil.EnclosingFuncType(enclosing.Node())
if fnType == nil || fnType.Params == nil {
if fnType == nil {
continue
}
if _, ok := astutil.ContextParamName(pass, fnType); ok {
return true
}
// Stop at a plain closure boundary: a context from an outer scope does
// not apply to code running inside a callback closure.
if _, isFuncLit := enclosing.Node().(*ast.FuncLit); isFuncLit && !astutil.IsGoOrDeferClosure(enclosing) {
return false
}
}

return false
Expand Down
26 changes: 26 additions & 0 deletions pkg/linters/httpnoctx/testdata/src/httpnoctx/httpnoctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,29 @@ func GoodTimeoutClientDo(ctx context.Context, rawURL string) (*http.Response, er
client := &http.Client{Timeout: time.Second}
return client.Do(req)
}

// GoodNewRequestInPlainClosure calls http.NewRequest inside a plain closure that
// has no context parameter; the outer context must not be attributed to it.
func GoodNewRequestInPlainClosure(ctx context.Context, rawURL string) http.HandlerFunc {
_ = ctx
return func(w http.ResponseWriter, r *http.Request) {
_, _ = http.NewRequest(http.MethodGet, rawURL, nil)
}
}

// BadNewRequestInGoClosure calls http.NewRequest inside a go closure; the outer
// context is still in scope there so the call is flagged.
func BadNewRequestInGoClosure(ctx context.Context, rawURL string) {
_ = ctx
go func() {
_, _ = http.NewRequest(http.MethodGet, rawURL, nil) // want `http\.NewRequest does not propagate context`
}()
}

// BadNewRequestInDeferClosure calls http.NewRequest inside a defer closure.
func BadNewRequestInDeferClosure(ctx context.Context, rawURL string) {
_ = ctx
defer func() {
_, _ = http.NewRequest(http.MethodGet, rawURL, nil) // want `http\.NewRequest does not propagate context`
}()
}
Loading