Giter VIP home page Giter VIP logo

noctx's Introduction

noctx

noctx finds sending http request without context.Context.

You should use noctx if sending http request in your library. Passing context.Context enables library user to cancel http request, getting trace information and so on.

Usage

noctx with go vet

go vet is a Go standard tool for analyzing source code.

  1. Install noctx.
$ go install github.com/sonatard/noctx/cmd/noctx@latest
  1. noctx execute
$ go vet -vettool=`which noctx` main.go
./main.go:6:11: net/http.Get must not be called

noctx with golangci-lint

golangci-lint is a fast Go linters runner.

  1. Install golangci-lint. golangci-lint - Install

  2. Setup .golangci.yml

# Add noctx to enable linters.
linters:
  enable:
    - noctx

# Or enable-all is true.
linters:
  enable-all: true
  disable:
   - xxx # Add unused linter to disable linters.
  1. noctx execute
# Use .golangci.yml
$ golangci-lint run

# Only noctx execute
golangci-lint run --disable-all -E noctx

Detection rules

  • Executing following functions
    • net/http.Get
    • net/http.Head
    • net/http.Post
    • net/http.PostForm
    • (*net/http.Client).Get
    • (*net/http.Client).Head
    • (*net/http.Client).Post
    • (*net/http.Client).PostForm
  • http.Request returned by http.NewRequest function and passes it to other function.

How to fix

  • Send http request using (*http.Client).Do(*http.Request) method.
  • In Go 1.13 and later, use http.NewRequestWithContext function instead of using http.NewRequest function.
  • In Go 1.12 and earlier, call (http.Request).WithContext(ctx) after http.NewRequest.

(http.Request).WithContext(ctx) has a disadvantage of performance because it returns a copy of http.Request. Use http.NewRequestWithContext function if you only support Go1.13 or later.

If your library already provides functions that don't accept context, you define a new function that accepts context and make the existing function a wrapper for a new function.

// Before fix code
// Sending an HTTP request but not accepting context
func Send(body io.Reader)  error {
    req,err := http.NewRequest(http.MethodPost, "http://example.com", body)
    if err != nil {
        return nil
    }
    _, err = http.DefaultClient.Do(req)
    if err !=nil{
        return err
    }

    return nil
}
// After fix code
func Send(body io.Reader) error {
    // Pass context.Background() to SendWithContext
    return SendWithContext(context.Background(), body)
}

// Sending an HTTP request and accepting context
func SendWithContext(ctx context.Context, body io.Reader) error {
    // Change NewRequest to NewRequestWithContext and pass context it
    req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://example.com", body)
    if err != nil {
        return nil
    }
    _, err = http.DefaultClient.Do(req)
    if err != nil {
        return err
    }

    return nil
}

Detection sample

package main

import (
	"context"
	"net/http"
)

func main() {
	const url = "http://example.com"
	http.Get(url) // want `net/http\.Get must not be called`
	http.Head(url)          // want `net/http\.Head must not be called`
	http.Post(url, "", nil) // want `net/http\.Post must not be called`
	http.PostForm(url, nil) // want `net/http\.PostForm must not be called`

	cli := &http.Client{}
	cli.Get(url) // want `\(\*net/http\.Client\)\.Get must not be called`
	cli.Head(url)          // want `\(\*net/http\.Client\)\.Head must not be called`
	cli.Post(url, "", nil) // want `\(\*net/http\.Client\)\.Post must not be called`
	cli.PostForm(url, nil) // want `\(\*net/http\.Client\)\.PostForm must not be called`

	req, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext`
	cli.Do(req)

	ctx := context.Background()
	req2, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) // OK
	cli.Do(req2)

	req3, _ := http.NewRequest(http.MethodPost, url, nil) // OK
	req3 = req3.WithContext(ctx)
	cli.Do(req3)

	f2 := func(req *http.Request, ctx context.Context) *http.Request {
		return req
	}
	req4, _ := http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext`
	req4 = f2(req4, ctx)
	cli.Do(req4)

	req5, _ := func() (*http.Request, error) {
		return http.NewRequest(http.MethodPost, url, nil) // want `should rewrite http.NewRequestWithContext or add \(\*Request\).WithContext`
	}()
	cli.Do(req5)

}

Reference

noctx's People

Contributors

sonatard avatar reillywatson avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.