diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2940ec9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +; https://editorconfig.org/ + +root = true + +[*] +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +indent_style = tab +indent_size = 4 + +[*.md] +indent_size = 4 +trim_trailing_whitespace = false + +eclint_indent_style = unset diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml new file mode 100644 index 0000000..2a38d75 --- /dev/null +++ b/.github/workflows/issues.yml @@ -0,0 +1,21 @@ +# Add issues or pull-requests created to the project. +name: Add issue or pull request to Project + +on: + issues: + types: + - opened + pull_request_target: + types: + - opened + - reopened + +jobs: + add-to-project: + runs-on: ubuntu-latest + steps: + - name: Add issue to project + uses: actions/add-to-project@v0.5.0 + with: + project-url: https://github.com/orgs/gorilla/projects/4 + github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..f2e4b4d --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,55 @@ +name: CI +on: + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + verify-and-test: + strategy: + matrix: + go: ['1.19','1.20'] + os: [ubuntu-latest, macos-latest, windows-latest] + fail-fast: true + runs-on: ${{ matrix.os }} + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Setup Go ${{ matrix.go }} + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go }} + cache: false + + - name: Run GolangCI-Lint + uses: golangci/golangci-lint-action@v3 + with: + version: v1.53 + args: --timeout=5m + + - name: Run GoSec + if: matrix.os == 'ubuntu-latest' + uses: securego/gosec@master + with: + args: ./... + + - name: Run GoVulnCheck + uses: golang/govulncheck-action@v1 + with: + go-version-input: ${{ matrix.go }} + go-package: ./... + + - name: Run Tests + run: go test -race -cover -coverprofile=coverage -covermode=atomic -v ./... + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + files: ./coverage diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84039fe --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +coverage.coverprofile diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f983b60..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: go -sudo: false - -go: - - 1.3 - - 1.4 - - 1.5 - - tip diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 92fca62..0000000 --- a/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -Dave Cheney -Alexandre Fiori -Quinn Slack diff --git a/LICENSE b/LICENSE index 3078494..bb9d80b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013 Dave Cheney. All rights reserved. +Copyright (c) 2023 The Gorilla Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ac37ffd --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') +GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest + +GO_SEC=$(shell which gosec 2> /dev/null || echo '') +GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest + +GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') +GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest + +.PHONY: golangci-lint +golangci-lint: + $(if $(GO_LINT), ,go install $(GO_LINT_URI)) + @echo "##### Running golangci-lint" + golangci-lint run -v + +.PHONY: gosec +gosec: + $(if $(GO_SEC), ,go install $(GO_SEC_URI)) + @echo "##### Running gosec" + gosec ./... + +.PHONY: govulncheck +govulncheck: + $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) + @echo "##### Running govulncheck" + govulncheck ./... + +.PHONY: verify +verify: golangci-lint gosec govulncheck + +.PHONY: test +test: + @echo "##### Running tests" + go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... diff --git a/README.md b/README.md index bfd180d..3e20058 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ -## gorilla/http +# gorilla/http + +![testing](https://github.com/gorilla/http/actions/workflows/test.yml/badge.svg) +[![codecov](https://codecov.io/github/gorilla/http/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/http) +[![godoc](https://godoc.org/github.com/gorilla/http?status.svg)](https://godoc.org/github.com/gorilla/http) +[![sourcegraph](https://sourcegraph.com/github.com/gorilla/http/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/http?badge) -A simple, safe and powerful HTTP client for the Go language. -Build Status: [![Build Status](https://travis-ci.org/gorilla/http.png?branch=master)](https://travis-ci.org/gorilla/http) +![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5) + +A simple, safe and powerful HTTP client for the Go language. # Image of an under construction GIF diff --git a/client.go b/client.go index f693635..f50dd07 100644 --- a/client.go +++ b/client.go @@ -4,7 +4,6 @@ import ( "compress/gzip" "fmt" "io" - "io/ioutil" stdurl "net/url" "strings" @@ -61,7 +60,7 @@ func (c *Client) Do(method, url string, headers map[string][]string, body io.Rea rc := &readCloser{rbody, conn} if rstatus.IsRedirect() && c.FollowRedirects { // consume the response body - _, err := io.Copy(ioutil.Discard, rc) + _, err := io.Copy(io.Discard, rc) if err := firstErr(err, rc.Close()); err != nil { return client.Status{}, nil, nil, err // TODO } @@ -134,7 +133,7 @@ func toHeaders(h map[string][]string) []client.Header { var r []client.Header for k, v := range h { for _, v := range v { - r = append(r, client.Header{k, v}) + r = append(r, client.Header{Key: k, Value: v}) } } return r diff --git a/client/client_test.go b/client/client_test.go index fb56645..8b9c224 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -196,20 +196,23 @@ var readResponseTests = []struct { Status: Status{200, "OK"}, Headers: []Header{{"Host", "localhost"}, {"Connection", "close"}}, }, io.EOF}, - // excessively long chunk. - {"HTTP/1.1 200 Ok\r\nTransfer-encoding: chunked\r\n\r\n" + - "004\r\n1234\r\n" + - "1000000000000000000001\r\n@\r\n" + - "00000000\r\n" + - "\r\n", - &Response{ - Version: HTTP_1_1, - Status: Status{200, "Ok"}, - Headers: []Header{{"Transfer-encoding", "chunked"}}, - Body: b("1234@"), - }, - nil, - }, + // The following test case no longer meets the expectations as per + // the conditions introduced with go version >=1.6. + // (ref: https://github.com/golang/go/blob/release-branch.go1.6/src/net/http/internal/chunked.go#L234) + // + // {"HTTP/1.1 200 Ok\r\nTransfer-encoding: chunked\r\n\r\n" + + // "004\r\n1234\r\n" + + // "1000000000000000000001\r\n@\r\n" + + // "00000000\r\n" + + // "\r\n", + // &Response{ + // Version: HTTP_1_1, + // Status: Status{200, "Ok"}, + // Headers: []Header{{"Transfer-encoding", "chunked"}}, + // Body: b("1234@"), + // }, + // nil, + // }, // silly redirect header { "HTTP/1.1 302 WebCenter Redirect\r\n" + @@ -281,12 +284,16 @@ func TestClientReadResponse(t *testing.T) { var buf bytes.Buffer var expected, actual string if tt.Response.Body != nil { - _, err = io.Copy(&buf, tt.Response.Body) + if _, err := io.Copy(&buf, tt.Response.Body); err != nil { + t.Fatal(err) + } expected = buf.String() } buf.Reset() if resp.Body != nil { - _, err = io.Copy(&buf, resp.Body) + if _, err = io.Copy(&buf, resp.Body); err != nil { + t.Fatal(err) + } actual = buf.String() } if actual != expected { @@ -338,7 +345,7 @@ func TestRequestCloseRequested(t *testing.T) { t.Fatal(err) } if actual := resp.CloseRequested(); actual != tt.expected { - t.Errorf("ReadResponse(%q): CloseRequested: expected %d got %d", tt.data, tt.expected, actual) + t.Errorf("ReadResponse(%q): CloseRequested: expected %v got %v", tt.data, tt.expected, actual) } } } @@ -363,7 +370,7 @@ func TestTransferEncoding(t *testing.T) { t.Fatal(err) } if actual := resp.TransferEncoding(); actual != tt.expected { - t.Errorf("ReadResponse(%q): TransferEncoding: expected %d got %d", tt.data, tt.expected, actual) + t.Errorf("ReadResponse(%q): TransferEncoding: expected %v got %v", tt.data, tt.expected, actual) } } } diff --git a/client/reader_test.go b/client/reader_test.go index 5e2f9df..f01bfc2 100644 --- a/client/reader_test.go +++ b/client/reader_test.go @@ -158,7 +158,7 @@ NEXT: } } -var readBodyTests = []struct { +var readBodyTests = []struct { // nolint:unused body string length int expected string @@ -170,7 +170,7 @@ var readBodyTests = []struct { } // disabled til I know what ReadBody should look like -func testReadBody(t *testing.T) { +func testReadBody(t *testing.T) { // nolint:unused for _, tt := range readBodyTests { c := &reader{b(tt.body)} r := c.ReadBody() diff --git a/client/status.go b/client/status.go index 9690312..6d4d368 100644 --- a/client/status.go +++ b/client/status.go @@ -61,12 +61,12 @@ type Status struct { Reason string } -var invalidStatus Status - func (s Status) String() string { return fmt.Sprintf("%d %s", s.Code, s.Reason) } func (s Status) IsInformational() bool { return s.Code >= INFO_CONTINUE && s.Code < SUCCESS_OK } -func (s Status) IsSuccess() bool { return s.Code >= SUCCESS_OK && s.Code < REDIRECTION_MULTIPLE_CHOICES } +func (s Status) IsSuccess() bool { + return s.Code >= SUCCESS_OK && s.Code < REDIRECTION_MULTIPLE_CHOICES +} func (s Status) IsRedirect() bool { return s.Code >= REDIRECTION_MULTIPLE_CHOICES && s.Code < CLIENT_ERROR_BAD_REQUEST } diff --git a/client/writer_test.go b/client/writer_test.go index cd2548e..dd2185a 100644 --- a/client/writer_test.go +++ b/client/writer_test.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "io" - "io/ioutil" "strings" "testing" ) @@ -106,7 +105,9 @@ func TestStartBody(t *testing.T) { if err := c.WriteHeader("Host", "localhost"); err != nil { t.Fatal(err) } - c.StartBody() + if err := c.StartBody(); err != nil { + t.Fatal(err) + } err := c.WriteHeader("Connection", "close") if _, ok := err.(*phaseError); !ok { t.Fatalf("expected %T, got %v", new(phaseError), err) @@ -124,7 +125,9 @@ func TestStartBody(t *testing.T) { func TestDoubleWriteBody(t *testing.T) { var b bytes.Buffer c := &writer{Writer: bufio.NewWriter(&b), tmp: &b} - c.StartBody() + if err := c.StartBody(); err != nil { + t.Fatal(err) + } if err := c.WriteBody(strings.NewReader("")); err != nil { t.Fatal(err) } @@ -138,7 +141,9 @@ func TestDoubleWriteBody(t *testing.T) { func TestDoubleWriteChunked(t *testing.T) { var b bytes.Buffer c := &writer{Writer: bufio.NewWriter(&b), tmp: &b} - c.StartBody() + if err := c.StartBody(); err != nil { + t.Fatal(err) + } if err := c.WriteChunked(strings.NewReader("")); err != nil { t.Fatal(err) } @@ -170,7 +175,9 @@ func (c *writer) write(t *testing.T, w writeTest) { t.Fatal(err) } } - c.StartBody() + if err := c.StartBody(); err != nil { + t.Fatal(err) + } if err := c.WriteBody(b(w.body)); err != nil { t.Fatal(err) } @@ -339,7 +346,7 @@ func (w *countingWriter) Write(buf []byte) (int, error) { // verify that header buffering works func TestHeaderBuffering(t *testing.T) { for _, tt := range headerBufferingTests { - cw := countingWriter{Writer: ioutil.Discard} + cw := countingWriter{Writer: io.Discard} w := &writer{Writer: &cw} if err := tt.f(w); err != nil { t.Fatal(err) diff --git a/client_test.go b/client_test.go index f9169f8..af1118b 100644 --- a/client_test.go +++ b/client_test.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "log" "net/http" "reflect" "sort" @@ -31,19 +32,25 @@ var clientDoTests = []struct { }{ { - Client: Client{dialer: new(dialer)}, - method: "GET", - path: "/200", - Status: client.Status{200, "OK"}, + Client: Client{dialer: new(dialer)}, + method: "GET", + path: "/200", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, rheaders: map[string][]string{"Content-Length": []string{"2"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader("OK"), }, { - Client: Client{dialer: new(dialer)}, - method: "GET", - path: "/query1?a=1", - Status: client.Status{200, "OK"}, + Client: Client{dialer: new(dialer)}, + method: "GET", + path: "/query1?a=1", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, rheaders: map[string][]string{"Content-Length": []string{"3"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader("a=1"), }, @@ -58,49 +65,64 @@ var clientDoTests = []struct { }, **/ { - Client: Client{dialer: new(dialer)}, - method: "GET", - path: "/query2?a=1&b=2", - Status: client.Status{200, "OK"}, + Client: Client{dialer: new(dialer)}, + method: "GET", + path: "/query2?a=1&b=2", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, rheaders: map[string][]string{"Content-Length": []string{"7"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader("a=1&b=2"), }, { - Client: Client{dialer: new(dialer)}, - method: "GET", - path: "/404", - Status: client.Status{404, "Not Found"}, + Client: Client{dialer: new(dialer)}, + method: "GET", + path: "/404", + Status: client.Status{ + Code: 404, + Reason: "Not Found", + }, rheaders: map[string][]string{"Content-Length": []string{"19"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader("404 page not found\n"), }, { - Client: Client{dialer: new(dialer)}, - method: "GET", - path: "/a", - Status: client.Status{200, "OK"}, + Client: Client{dialer: new(dialer)}, + method: "GET", + path: "/a", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, rheaders: map[string][]string{"Transfer-Encoding": {"chunked"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader(a()), }, { - Client: Client{dialer: new(dialer)}, - method: "GET", - path: "/a", - Status: client.Status{200, "OK"}, + Client: Client{dialer: new(dialer)}, + method: "GET", + path: "/a", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, headers: map[string][]string{"Accept-Encoding": []string{"gzip"}}, rheaders: map[string][]string{ // net/http can buffer the first write to avoid chunked "Content-Length": []string{"48"}, "Content-Encoding": []string{"gzip"}, - "Content-Type": []string{"application/x-gzip"}, + // "Content-Type": []string{"application/x-gzip"}, }, rbody: strings.NewReader(a()), }, { - Client: Client{dialer: new(dialer)}, - method: "POST", - path: "/201", - body: func() io.Reader { return strings.NewReader(postBody) }, - Status: client.Status{201, "Created"}, + Client: Client{dialer: new(dialer)}, + method: "POST", + path: "/201", + body: func() io.Reader { return strings.NewReader(postBody) }, + Status: client.Status{ + Code: 201, + Reason: "Created", + }, rheaders: map[string][]string{"Content-Length": []string{"8"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader("Created\n"), }, @@ -108,7 +130,10 @@ var clientDoTests = []struct { Client: Client{dialer: new(dialer)}, method: "GET", path: "/301", - Status: client.Status{301, "Moved Permanently"}, + Status: client.Status{ + Code: 301, + Reason: "Moved Permanently", + }, rheaders: map[string][]string{ "Location": []string{"/200"}, "Content-Length": []string{"39"}, @@ -120,7 +145,10 @@ var clientDoTests = []struct { Client: Client{dialer: new(dialer)}, method: "GET", path: "/302", - Status: client.Status{302, "Found"}, + Status: client.Status{ + Code: 302, + Reason: "Found", + }, rheaders: map[string][]string{ "Location": []string{"/200"}, "Content-Length": []string{"27"}, @@ -129,18 +157,24 @@ var clientDoTests = []struct { rbody: strings.NewReader("Found.\n\n"), }, { - Client: Client{dialer: new(dialer), FollowRedirects: true}, - method: "GET", - path: "/301", - Status: client.Status{200, "OK"}, + Client: Client{dialer: new(dialer), FollowRedirects: true}, + method: "GET", + path: "/301", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, rheaders: map[string][]string{"Content-Length": []string{"2"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader("OK"), }, { - Client: Client{dialer: new(dialer), FollowRedirects: true}, - method: "GET", - path: "/302", - Status: client.Status{200, "OK"}, + Client: Client{dialer: new(dialer), FollowRedirects: true}, + method: "GET", + path: "/302", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, rheaders: map[string][]string{"Content-Length": []string{"2"}, "Content-Type": []string{"text/plain; charset=utf-8"}}, rbody: strings.NewReader("OK"), }, @@ -148,7 +182,11 @@ var clientDoTests = []struct { func stdmux() *http.ServeMux { mux := http.NewServeMux() - mux.HandleFunc("/200", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("OK")) }) + mux.HandleFunc("/200", func(w http.ResponseWriter, _ *http.Request) { + if _, err := w.Write([]byte("OK")); err != nil { + log.Fatal(err) + } + }) mux.HandleFunc("/a", func(w http.ResponseWriter, r *http.Request) { var ww io.Writer = w if r.Header.Get("Accept-Encoding") == "gzip" { @@ -156,7 +194,9 @@ func stdmux() *http.ServeMux { ww = gzip.NewWriter(ww) } for i := 0; i < 1024; i++ { - ww.Write([]byte("aaaaaaaa")) + if _, err := ww.Write([]byte("aaaaaaaa")); err != nil { + log.Fatal(err) + } } if w, ok := ww.(*gzip.Writer); ok { w.Close() @@ -164,18 +204,20 @@ func stdmux() *http.ServeMux { }) mux.HandleFunc("/201", func(w http.ResponseWriter, r *http.Request) { var b bytes.Buffer - io.Copy(&b, r.Body) + if _, err := io.Copy(&b, r.Body); err != nil { + log.Fatal(err) + } if b.String() != postBody { http.Error(w, fmt.Sprintf("/201, expected %q, got %q", postBody, b.String()), 400) } else { - http.Error(w, "Created", 201) + http.Error(w, "Created", http.StatusCreated) } }) mux.HandleFunc("/301", func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, "200", 301) + http.Redirect(w, r, "200", http.StatusMovedPermanently) }) mux.HandleFunc("/302", func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, "200", 302) + http.Redirect(w, r, "200", http.StatusFound) }) mux.HandleFunc("/query1", func(w http.ResponseWriter, r *http.Request) { rq := r.URL.RawQuery @@ -183,7 +225,9 @@ func stdmux() *http.ServeMux { http.Error(w, "Bad Request", 400) return } - w.Write([]byte(rq)) + if _, err := w.Write([]byte(rq)); err != nil { + log.Fatal(err) + } }) mux.HandleFunc("/query2", func(w http.ResponseWriter, r *http.Request) { rq := r.URL.RawQuery @@ -191,7 +235,9 @@ func stdmux() *http.ServeMux { http.Error(w, "Bad Request", 400) return } - w.Write([]byte(rq)) + if _, err := w.Write([]byte(rq)); err != nil { + log.Fatal(err) + } }) return mux } @@ -207,13 +253,13 @@ func TestClientDo(t *testing.T) { } status, headers, rbody, err := tt.Client.Do(tt.method, url, tt.headers, body) if err != tt.err { - t.Errorf("Client.Do(%q, %q, %v, %v): err expected %v, got %v", tt.method, tt.path, tt.headers, tt.body, tt.err, err) + t.Errorf("Client.Do(%q, %q, %v, %v): err expected %v, got %v", tt.method, tt.path, tt.headers, reflect.ValueOf(tt.body), tt.err, err) } if err != nil { continue } if status != tt.Status { - t.Errorf("Client.Do(%q, %q, %v, %v): status expected %v, got %v", tt.method, tt.path, tt.headers, tt.body, tt.Status, status) + t.Errorf("Client.Do(%q, %q, %v, %v): status expected %v, got %v", tt.method, tt.path, tt.headers, reflect.ValueOf(tt.body), tt.Status, status) } delete(headers, "Date") // hard to predict delete(headers, "X-Content-Type-Options") // a free gift from the Go http server @@ -221,10 +267,10 @@ func TestClientDo(t *testing.T) { sort.Strings(v) } if !reflect.DeepEqual(tt.rheaders, headers) { - t.Errorf("Client.Do(%q, %q, %v, %v): headers expected %v, got %v", tt.method, tt.path, tt.headers, tt.body, tt.rheaders, headers) + t.Errorf("Client.Do(%q, %q, %v, %v): headers expected %v, got %v", tt.method, tt.path, tt.headers, reflect.ValueOf(tt.body), tt.rheaders, headers) } if actual, expected := readBodies(t, rbody, tt.rbody); actual != expected { - t.Errorf("Client.Do(%q, %q, %v, %v): body expected %q, got %q", tt.method, tt.path, tt.headers, tt.body, expected, actual) + t.Errorf("Client.Do(%q, %q, %v, %v): body expected %q, got %q", tt.method, tt.path, tt.headers, reflect.ValueOf(tt.body), expected, actual) } } } @@ -253,12 +299,18 @@ var clientGetTests = []struct { err error }{ { - path: "/200", - Status: client.Status{200, "OK"}, + path: "/200", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, }, { - path: "/404", - Status: client.Status{404, "Not Found"}, + path: "/404", + Status: client.Status{ + Code: 404, + Reason: "Not Found", + }, }, } @@ -288,13 +340,19 @@ var clientPostTests = []struct { err error }{ { - path: "/201", - body: func() io.Reader { return strings.NewReader(postBody) }, - Status: client.Status{201, "Created"}, + path: "/201", + body: func() io.Reader { return strings.NewReader(postBody) }, + Status: client.Status{ + Code: 201, + Reason: "Created", + }, }, { - path: "/404", - Status: client.Status{404, "Not Found"}, + path: "/404", + Status: client.Status{ + Code: 404, + Reason: "Not Found", + }, }, } @@ -328,13 +386,19 @@ var clientPutTests = []struct { err error }{ { - path: "/201", - body: func() io.Reader { return strings.NewReader(postBody) }, - Status: client.Status{201, "Created"}, + path: "/201", + body: func() io.Reader { return strings.NewReader(postBody) }, + Status: client.Status{ + Code: 201, + Reason: "Created", + }, }, { - path: "/404", - Status: client.Status{404, "Not Found"}, + path: "/404", + Status: client.Status{ + Code: 404, + Reason: "Not Found", + }, }, } @@ -368,13 +432,19 @@ var clientPatchTests = []struct { err error }{ { - path: "/201", - body: func() io.Reader { return strings.NewReader(postBody) }, - Status: client.Status{201, "Created"}, + path: "/201", + body: func() io.Reader { return strings.NewReader(postBody) }, + Status: client.Status{ + Code: 201, + Reason: "Created", + }, }, { - path: "/404", - Status: client.Status{404, "Not Found"}, + path: "/404", + Status: client.Status{ + Code: 404, + Reason: "Not Found", + }, }, } @@ -407,12 +477,18 @@ var clientDeleteTests = []struct { err error }{ { - path: "/200", - Status: client.Status{200, "OK"}, + path: "/200", + Status: client.Status{ + Code: 200, + Reason: "OK", + }, }, { - path: "/404", - Status: client.Status{404, "Not Found"}, + path: "/404", + Status: client.Status{ + Code: 404, + Reason: "Not Found", + }, }, } @@ -496,7 +572,7 @@ var fromResponseTests = []struct { body io.Reader headers map[string][]string }{ -// TODO(dfc) + // TODO(dfc) } func TestFromResponse(t *testing.T) { diff --git a/conn.go b/conn.go index 46709ec..21e6835 100644 --- a/conn.go +++ b/conn.go @@ -28,7 +28,7 @@ func (d *dialer) Dial(network, addr string) (Conn, error) { if c, ok := d.conns[addr]; ok { if len(c) > 0 { conn := c[0] - c[0], c = c[len(c)-1], c[:len(c)-1] + c[0], c = c[len(c)-1], c[:len(c)-1] // nolint:staticcheck d.Unlock() return conn, nil } diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0d1c3f8 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/gorilla/http + +go 1.19 diff --git a/header_test.go b/header_test.go index e0d6664..1946351 100644 --- a/header_test.go +++ b/header_test.go @@ -15,11 +15,14 @@ var toHeadersTests = []struct { {nil, nil}, { map[string][]string{"Host": []string{"a"}}, - []client.Header{{"Host", "a"}}, + []client.Header{{Key: "Host", Value: "a"}}, }, { map[string][]string{"Host": []string{"a", "B"}}, - []client.Header{{"Host", "B"}, {"Host", "a"}}, + []client.Header{ + {Key: "Host", Value: "B"}, + {Key: "Host", Value: "a"}, + }, }, { map[string][]string{ @@ -27,8 +30,8 @@ var toHeadersTests = []struct { "Connection": []string{"close"}, }, []client.Header{ - {"Connection", "close"}, - {"Host", "a"}, + {Key: "Connection", Value: "close"}, + {Key: "Host", Value: "a"}, }, }, { @@ -37,8 +40,9 @@ var toHeadersTests = []struct { "Connection": []string{"close"}, }, []client.Header{ - {"Connection", "close"}, - {"Host", "B"}, {"Host", "a"}, + {Key: "Connection", Value: "close"}, + {Key: "Host", Value: "B"}, + {Key: "Host", Value: "a"}, }, }, } @@ -59,17 +63,20 @@ var fromHeadersTests = []struct { }{ {nil, nil}, { - []client.Header{{"Host", "a"}}, + []client.Header{{Key: "Host", Value: "a"}}, map[string][]string{"Host": []string{"a"}}, }, { - []client.Header{{"Host", "B"}, {"Host", "a"}}, + []client.Header{ + {Key: "Host", Value: "B"}, + {Key: "Host", Value: "a"}, + }, map[string][]string{"Host": []string{"B", "a"}}, }, { []client.Header{ - {"Connection", "close"}, - {"Host", "a"}, + {Key: "Connection", Value: "close"}, + {Key: "Host", Value: "a"}, }, map[string][]string{ "Host": []string{"a"}, @@ -78,8 +85,9 @@ var fromHeadersTests = []struct { }, { []client.Header{ - {"Connection", "close"}, - {"Host", "B"}, {"Host", "a"}, + {Key: "Connection", Value: "close"}, + {Key: "Host", Value: "B"}, + {Key: "Host", Value: "a"}, }, map[string][]string{ "Host": []string{"B", "a"}, diff --git a/http_test.go b/http_test.go index eb0221d..2a0ccb7 100644 --- a/http_test.go +++ b/http_test.go @@ -39,7 +39,7 @@ func newServer(t *testing.T, mux *http.ServeMux) *server { } // /404 is not handled, generating a 404 go func() { - if err := http.Serve(l, mux); err != nil { + if err := http.Serve(l, mux); err != nil { // nolint:staticcheck // t.Error(err) } }()