bodyclose

repository·master·Indexed 43 days ago

https://github.com/timakin/bodyclose

A static analysis tool for Go that ensures res.Body in net/http.Response is correctly closed to allow HTTP clients to reuse persistent TCP connections. It can be run as a go vet tool and includes an optional -check-consumption flag to verify that response bodies are consumed.

Tokens
1K
Snippets
6
Records
8
Agent score
6%

What's inside bodyclose

  1. Use the //bodyclose:handled directive

    master

    If you have a function that fully handles every returned *http.Response body (e.g., by closing it or consuming it and then replacing it with a NopCloser), you can annotate the function with //bodyclose:handled.

    This tells the analyzer to skip both close and consumption checks for calls to this function, including calls made from other packages. Note that this only works for statically resolved function calls.

    // bodyclose:handled
    func doRequest(req *http.Request, handle func([]byte) error) (*http.Response, error) {
    	resp, err := http.DefaultClient.Do(req)
    	if err != nil {
    		return nil, err
    	}
    	defer resp.Body.Close()
    
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return nil, err
    	}
    	if err := handle(body); err != nil {
    		return nil, err
    	}
    
    	resp.Body = io.NopCloser(bytes.NewReader(body))
    	return resp, nil
    }
  2. How to use bodyclose with go vet

    master

    For Go versions 1.12 and higher, run bodyclose as a go vet tool. This checks your packages for unclosed res.Body instances.

    To enable additional checks that verify response bodies are actually consumed (not just closed), use the -check-consumption flag.

    # Standard check for closing bodies
    $ go vet -vettool=$(which bodyclose) github.com/timakin/go_api/...
    
    # Check for both closing AND consumption of bodies
    $ go vet -vettool=$(which bodyclose) -check-consumption github.com/timakin/go_api/...
  3. Use bodyclose for Go versions < 1.12

    master

    For Go versions older than 1.12, run the bodyclose command directly with the package name (import path). Note that this legacy mode does not support certain options like --tags.

    $ bodyclose github.com/timakin/go_api/...
  4. Suppress false positives with //nolint:bodyclose

    master

    If you use a custom consumption pattern that the analyzer does not recognize, it may trigger a false positive. You can suppress these warnings by adding //nolint:bodyclose to the line or function.

    func customBodyProcessing() {
        resp, _ := http.Get("http://example.com/") //nolint:bodyclose
        defer resp.Body.Close()
    
        // Custom consumption logic that analyzer doesn't recognize
        buf := make([]byte, 1024)
        resp.Body.Read(buf) 
    }
  5. Use the bodyclose CLI tool

    master

    The bodyclose tool is a linter designed to be used with the go vet command. It checks for HTTP response bodies that are not being closed, which can lead to resource leaks. Because it is built using the golang.org/x/tools/go/analysis framework, you run it by passing the package path to go vet.

    go vet -vettool=$(which bodyclose) ./...
  6. Supported consumption patterns for -check-consumption

    master

    When using the -check-consumption flag, bodyclose recognizes the following patterns as valid body consumption:

    • io.Copy(io.Discard, resp.Body)
    • io.ReadAll(resp.Body)
    • ioutil.ReadAll(resp.Body) (legacy)
    • json.NewDecoder(resp.Body)
    • bufio.NewScanner(resp.Body)
    • bufio.NewReader(resp.Body)
  7. bodyclose.Analyzer

    master
    The bodyclose.Analyzer is the core analysis engine exported by the github.com/timakin/bodyclose/passes/bodyclose package. It implements the analysis.Analyzer interface and is used by the CLI entrypoint to perform the actual inspection of HTTP response body closures.