Showing preview only (1,369K chars total). Download the full file or copy to clipboard to get everything.
Repository: valyala/fasthttp
Branch: master
Commit: 87f0fe1394de
Files: 157
Total size: 1.3 MB
Directory structure:
gitextract_z0m1bue7/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── cifuzz.yml
│ ├── lint.yml
│ ├── security.yml
│ └── test.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── README.md
├── SECURITY.md
├── TODO
├── allocation_test.go
├── args.go
├── args_test.go
├── args_timing_test.go
├── b2s.go
├── brotli.go
├── brotli_test.go
├── bytesconv.go
├── bytesconv_32.go
├── bytesconv_32_test.go
├── bytesconv_64.go
├── bytesconv_64_test.go
├── bytesconv_table.go
├── bytesconv_table_gen.go
├── bytesconv_test.go
├── bytesconv_timing_test.go
├── client.go
├── client_example_test.go
├── client_test.go
├── client_timing_test.go
├── coarsetime.go
├── compress.go
├── compress_test.go
├── cookie.go
├── cookie_test.go
├── cookie_timing_test.go
├── doc.go
├── examples/
│ ├── README.md
│ ├── host_client/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.md
│ │ └── hostclient.go
│ ├── letsencrypt/
│ │ └── letsencryptserver.go
│ └── multidomain/
│ ├── Makefile
│ ├── README.md
│ └── multidomain.go
├── expvarhandler/
│ ├── expvar.go
│ └── expvar_test.go
├── fasthttpadaptor/
│ ├── adaptor.go
│ ├── adaptor_test.go
│ ├── b2s.go
│ ├── request.go
│ └── request_test.go
├── fasthttpproxy/
│ ├── dialer.go
│ ├── dialer_test.go
│ ├── doc.go
│ ├── http.go
│ ├── proxy_env.go
│ └── socks5.go
├── fasthttputil/
│ ├── doc.go
│ ├── inmemory_listener.go
│ ├── inmemory_listener_test.go
│ ├── inmemory_listener_timing_test.go
│ ├── pipeconns.go
│ ├── pipeconns_test.go
│ └── s2b.go
├── fs.go
├── fs_example_test.go
├── fs_fs_test.go
├── fs_handler_example_test.go
├── fs_test.go
├── fuzz_test.go
├── go.mod
├── go.sum
├── header.go
├── header_regression_test.go
├── header_test.go
├── header_timing_test.go
├── headers.go
├── headerscanner.go
├── http.go
├── http_test.go
├── http_timing_test.go
├── ipv6.go
├── ipv6_test.go
├── lbclient.go
├── lbclient_example_test.go
├── methods.go
├── nocopy.go
├── peripconn.go
├── peripconn_test.go
├── pprofhandler/
│ └── pprof.go
├── prefork/
│ ├── README.md
│ ├── prefork.go
│ └── prefork_test.go
├── requestctx_setbodystreamwriter_example_test.go
├── reuseport/
│ ├── LICENSE
│ ├── reuseport.go
│ ├── reuseport_aix.go
│ ├── reuseport_error.go
│ ├── reuseport_example_test.go
│ ├── reuseport_solaris.go
│ ├── reuseport_test.go
│ └── reuseport_windows.go
├── round2_32.go
├── round2_32_test.go
├── round2_64.go
├── round2_64_test.go
├── s2b.go
├── server.go
├── server_example_test.go
├── server_race_test.go
├── server_test.go
├── server_timing_test.go
├── stackless/
│ ├── doc.go
│ ├── func.go
│ ├── func_test.go
│ ├── func_timing_test.go
│ ├── s2b.go
│ ├── writer.go
│ └── writer_test.go
├── status.go
├── status_test.go
├── status_timing_test.go
├── stream.go
├── stream_test.go
├── stream_timing_test.go
├── streaming.go
├── streaming_test.go
├── strings.go
├── tcpdialer.go
├── tcplisten/
│ ├── README.md
│ ├── socket.go
│ ├── socket_darwin.go
│ ├── socket_other.go
│ ├── socket_zos_s390x.go
│ ├── tcplisten.go
│ ├── tcplisten_js_wasm.go
│ ├── tcplisten_linux.go
│ ├── tcplisten_other.go
│ └── tcplisten_test.go
├── timer.go
├── tls.go
├── uri.go
├── uri_test.go
├── uri_timing_test.go
├── uri_unix.go
├── uri_windows.go
├── uri_windows_test.go
├── userdata.go
├── userdata_test.go
├── userdata_timing_test.go
├── workerpool.go
├── workerpool_test.go
├── zstd.go
└── zstd_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
================================================
FILE: .github/workflows/cifuzz.yml
================================================
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'fasthttp'
dry-run: false
language: go
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'fasthttp'
fuzz-seconds: 300
dry-run: false
language: go
- name: Upload Crash
uses: actions/upload-artifact@v7
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint
on:
push:
branches:
- master
pull_request:
permissions:
# Required: allow read access to the content for analysis.
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read
# Optional: Allow write access to checks to allow the action to annotate code in the PR.
checks: write
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: 1.26.x
- run: go version
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v9.2.0
with:
version: v2.10.1
args: --verbose
================================================
FILE: .github/workflows/security.yml
================================================
name: Security
on:
push:
branches:
- master
pull_request:
jobs:
test:
strategy:
matrix:
go-version: [1.20.x]
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
env:
GO111MODULE: on
steps:
- uses: actions/checkout@v6
- name: Run Gosec Security Scanner
uses: securego/gosec@v2.25.0
with:
args: '-exclude=G103,G104,G304,G402 ./...'
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
push:
branches:
- master
pull_request:
jobs:
test:
strategy:
fail-fast: false
matrix:
go-version: [1.24.x, 1.26.x]
os: [ubuntu-latest, macos-latest, windows-latest, macos-14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
- run: go version
- run: go test -shuffle=on ./...
- run: go test -race -shuffle=on ./...
================================================
FILE: .gitignore
================================================
tags
*.pprof
*.fasthttp.br
*.fasthttp.zst
*.fasthttp.gz
.idea
.vscode
.DS_Store
vendor/
testdata/fuzz
================================================
FILE: .golangci.yml
================================================
version: "2"
linters:
default: all
disable:
- copyloopvar
- cyclop
- depguard
- dupl
- err113
- errname
- errorlint
- exhaustive
- exhaustruct
- forbidigo
- forcetypeassert
- funcorder
- funlen
- gochecknoglobals
- gocognit
- goconst
- gocyclo
- godox
- gosec
- gosmopolitan
- inamedparam
- intrange
- ireturn
- maintidx
- mnd
- nakedret
- nestif
- nlreturn
- noctx
- noinlineerr
- nonamedreturns
- paralleltest
- testableexamples
- testpackage
- thelper
- tparallel
- unparam
- usestdlibvars
- varnamelen
- wrapcheck
- wsl
- wsl_v5
settings:
gocritic:
disabled-checks:
- deferInLoop
- importShadow
- sloppyReassign
- unnamedResult
- whyNoLint
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
govet:
disable:
- fieldalignment
- shadow
enable-all: true
lll:
line-length: 130
revive:
rules:
- name: indent-error-flow
- name: use-any
staticcheck:
checks:
- -ST1000
- all
exclusions:
generated: lax
presets:
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- lll
path: _test\.go
paths:
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# fasthttp
[](https://pkg.go.dev/github.com/valyala/fasthttp) [](https://goreportcard.com/report/github.com/valyala/fasthttp)

Fast HTTP implementation for Go.
## fasthttp might not be for you!
fasthttp was designed for some high performance edge cases. **Unless** your server/client needs to handle **thousands of small to medium requests per second** and needs a consistent low millisecond response time fasthttp might not be for you. **For most cases `net/http` is much better** as it's easier to use and can handle more cases. For most cases you won't even notice the performance difference.
## General info and links
Currently fasthttp is successfully used by [VertaMedia](https://vertamedia.com/)
in a production serving up to 200K rps from more than 1.5M concurrent keep-alive
connections per physical server.
[TechEmpower Benchmark round 23 results](https://www.techempower.com/benchmarks/#section=data-r23&hw=ph&test=plaintext)
[Server Benchmarks](#http-server-performance-comparison-with-nethttp)
[Client Benchmarks](#http-client-comparison-with-nethttp)
[Install](#install)
[Documentation](https://pkg.go.dev/github.com/valyala/fasthttp)
[Examples from docs](https://pkg.go.dev/github.com/valyala/fasthttp#pkg-examples)
[Code examples](examples)
[Awesome fasthttp tools](https://github.com/fasthttp)
[Switching from net/http to fasthttp](#switching-from-nethttp-to-fasthttp)
[Fasthttp best practices](#fasthttp-best-practices)
[Related projects](#related-projects)
[FAQ](#faq)
## HTTP server performance comparison with [net/http](https://pkg.go.dev/net/http)
In short, fasthttp server is up to 6 times faster than net/http.
Below are benchmark results.
_GOMAXPROCS=1_
net/http server:
```
$ GOMAXPROCS=1 go test -bench=NetHTTPServerGet -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkNetHTTPServerGet1ReqPerConn 722565 15327 ns/op 3258 B/op 36 allocs/op
BenchmarkNetHTTPServerGet2ReqPerConn 990067 11533 ns/op 2817 B/op 28 allocs/op
BenchmarkNetHTTPServerGet10ReqPerConn 1376821 8734 ns/op 2483 B/op 23 allocs/op
BenchmarkNetHTTPServerGet10KReqPerConn 1691265 7151 ns/op 2385 B/op 21 allocs/op
BenchmarkNetHTTPServerGet1ReqPerConn10KClients 643940 17152 ns/op 3529 B/op 36 allocs/op
BenchmarkNetHTTPServerGet2ReqPerConn10KClients 868576 14010 ns/op 2826 B/op 28 allocs/op
BenchmarkNetHTTPServerGet10ReqPerConn10KClients 1297398 9329 ns/op 2611 B/op 23 allocs/op
BenchmarkNetHTTPServerGet100ReqPerConn10KClients 1467963 7902 ns/op 2450 B/op 21 allocs/op
```
fasthttp server:
```
$ GOMAXPROCS=1 go test -bench=kServerGet -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkServerGet1ReqPerConn 4304683 2733 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet2ReqPerConn 5685157 2140 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet10ReqPerConn 7659729 1550 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet10KReqPerConn 8580660 1422 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet1ReqPerConn10KClients 4092148 3009 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet2ReqPerConn10KClients 5272755 2208 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet10ReqPerConn10KClients 7566351 1546 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet100ReqPerConn10KClients 8369295 1418 ns/op 0 B/op 0 allocs/op
```
_GOMAXPROCS=4_
net/http server:
```
$ GOMAXPROCS=4 go test -bench=NetHTTPServerGet -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkNetHTTPServerGet1ReqPerConn-4 2670654 4542 ns/op 3263 B/op 36 allocs/op
BenchmarkNetHTTPServerGet2ReqPerConn-4 3376021 3559 ns/op 2823 B/op 28 allocs/op
BenchmarkNetHTTPServerGet10ReqPerConn-4 4387959 2707 ns/op 2489 B/op 23 allocs/op
BenchmarkNetHTTPServerGet10KReqPerConn-4 5412049 2179 ns/op 2386 B/op 21 allocs/op
BenchmarkNetHTTPServerGet1ReqPerConn10KClients-4 2226048 5216 ns/op 3289 B/op 36 allocs/op
BenchmarkNetHTTPServerGet2ReqPerConn10KClients-4 2989957 3982 ns/op 2839 B/op 28 allocs/op
BenchmarkNetHTTPServerGet10ReqPerConn10KClients-4 4383570 2834 ns/op 2514 B/op 23 allocs/op
BenchmarkNetHTTPServerGet100ReqPerConn10KClients-4 5315100 2394 ns/op 2419 B/op 21 allocs/op
```
fasthttp server:
```
$ GOMAXPROCS=4 go test -bench=kServerGet -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkServerGet1ReqPerConn-4 7797037 1494 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet2ReqPerConn-4 13004892 963.7 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet10ReqPerConn-4 22479348 522.6 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet10KReqPerConn-4 25899390 451.4 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet1ReqPerConn10KClients-4 8421531 1469 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet2ReqPerConn10KClients-4 13426772 903.7 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet10ReqPerConn10KClients-4 21899584 513.5 ns/op 0 B/op 0 allocs/op
BenchmarkServerGet100ReqPerConn10KClients-4 25291686 439.4 ns/op 0 B/op 0 allocs/op
```
## HTTP client comparison with net/http
In short, fasthttp client is up to 4 times faster than net/http.
Below are benchmark results.
_GOMAXPROCS=1_
net/http client:
```
$ GOMAXPROCS=1 go test -bench='HTTPClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkNetHTTPClientDoFastServer 885637 13883 ns/op 3384 B/op 44 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1TCP 203875 55619 ns/op 6296 B/op 70 allocs/op
BenchmarkNetHTTPClientGetEndToEnd10TCP 231290 54618 ns/op 6299 B/op 70 allocs/op
BenchmarkNetHTTPClientGetEndToEnd100TCP 202879 58278 ns/op 6304 B/op 69 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1Inmemory 396764 26878 ns/op 6216 B/op 69 allocs/op
BenchmarkNetHTTPClientGetEndToEnd10Inmemory 396422 28373 ns/op 6209 B/op 68 allocs/op
BenchmarkNetHTTPClientGetEndToEnd100Inmemory 363976 33101 ns/op 6326 B/op 68 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1000Inmemory 208881 51725 ns/op 8298 B/op 84 allocs/op
BenchmarkNetHTTPClientGetEndToEndWaitConn1Inmemory 237 50451765 ns/op 7474 B/op 79 allocs/op
BenchmarkNetHTTPClientGetEndToEndWaitConn10Inmemory 237 50447244 ns/op 7434 B/op 77 allocs/op
BenchmarkNetHTTPClientGetEndToEndWaitConn100Inmemory 238 50067993 ns/op 8639 B/op 82 allocs/op
BenchmarkNetHTTPClientGetEndToEndWaitConn1000Inmemory 1366 7324990 ns/op 4064 B/op 44 allocs/op
```
fasthttp client:
```
$ GOMAXPROCS=1 go test -bench='kClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkClientGetEndToEnd1TCP 406376 26558 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10TCP 517425 23595 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd100TCP 474800 25153 ns/op 3 B/op 0 allocs/op
BenchmarkClientGetEndToEnd1Inmemory 2563800 4827 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10Inmemory 2460135 4805 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd100Inmemory 2520543 4846 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd1000Inmemory 2437015 4914 ns/op 2 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10KInmemory 2481050 5049 ns/op 9 B/op 0 allocs/op
```
_GOMAXPROCS=4_
net/http client:
```
$ GOMAXPROCS=4 go test -bench='HTTPClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkNetHTTPClientGetEndToEnd1TCP-4 767133 16175 ns/op 6304 B/op 69 allocs/op
BenchmarkNetHTTPClientGetEndToEnd10TCP-4 785198 15276 ns/op 6295 B/op 69 allocs/op
BenchmarkNetHTTPClientGetEndToEnd100TCP-4 780464 15605 ns/op 6305 B/op 69 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1Inmemory-4 1356932 8772 ns/op 6220 B/op 68 allocs/op
BenchmarkNetHTTPClientGetEndToEnd10Inmemory-4 1379245 8726 ns/op 6213 B/op 68 allocs/op
BenchmarkNetHTTPClientGetEndToEnd100Inmemory-4 1119213 10294 ns/op 6418 B/op 68 allocs/op
BenchmarkNetHTTPClientGetEndToEnd1000Inmemory-4 504194 31010 ns/op 17668 B/op 102 allocs/op
```
fasthttp client:
```
$ GOMAXPROCS=4 go test -bench='kClient(Do|GetEndToEnd)' -benchmem -benchtime=10s
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
BenchmarkClientGetEndToEnd1TCP-4 1474552 8143 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10TCP-4 1710270 7186 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd100TCP-4 1701672 6892 ns/op 4 B/op 0 allocs/op
BenchmarkClientGetEndToEnd1Inmemory-4 6797713 1590 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10Inmemory-4 6663642 1782 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd100Inmemory-4 6608209 1867 ns/op 0 B/op 0 allocs/op
BenchmarkClientGetEndToEnd1000Inmemory-4 6254452 2645 ns/op 8 B/op 0 allocs/op
BenchmarkClientGetEndToEnd10KInmemory-4 6944584 1966 ns/op 17 B/op 0 allocs/op
```
## Install
```
go get -u github.com/valyala/fasthttp
```
## Switching from net/http to fasthttp
Unfortunately, fasthttp doesn't provide API identical to net/http.
See the [FAQ](#faq) for details.
There is [net/http -> fasthttp handler converter](https://pkg.go.dev/github.com/valyala/fasthttp/fasthttpadaptor),
but it is better to write fasthttp request handlers by hand in order to use
all of the fasthttp advantages (especially high performance :) ).
Important points:
- Fasthttp works with [RequestHandler functions](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler)
instead of objects implementing [Handler interface](https://pkg.go.dev/net/http#Handler).
Fortunately, it is easy to pass bound struct methods to fasthttp:
```go
type MyHandler struct {
foobar string
}
// request handler in net/http style, i.e. method bound to MyHandler struct.
func (h *MyHandler) HandleFastHTTP(ctx *fasthttp.RequestCtx) {
// notice that we may access MyHandler properties here - see h.foobar.
fmt.Fprintf(ctx, "Hello, world! Requested path is %q. Foobar is %q",
ctx.Path(), h.foobar)
}
// request handler in fasthttp style, i.e. just plain function.
func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
fmt.Fprintf(ctx, "Hi there! RequestURI is %q", ctx.RequestURI())
}
// pass bound struct method to fasthttp
myHandler := &MyHandler{
foobar: "foobar",
}
fasthttp.ListenAndServe(":8080", myHandler.HandleFastHTTP)
// pass plain function to fasthttp
fasthttp.ListenAndServe(":8081", fastHTTPHandler)
```
- The [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler)
accepts only one argument - [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx).
It contains all the functionality required for http request processing
and response writing. Below is an example of a simple request handler conversion
from net/http to fasthttp.
```go
// net/http request handler
requestHandler := func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/foo":
fooHandler(w, r)
case "/bar":
barHandler(w, r)
default:
http.Error(w, "Unsupported path", http.StatusNotFound)
}
}
```
```go
// the corresponding fasthttp request handler
requestHandler := func(ctx *fasthttp.RequestCtx) {
switch string(ctx.Path()) {
case "/foo":
fooHandler(ctx)
case "/bar":
barHandler(ctx)
default:
ctx.Error("Unsupported path", fasthttp.StatusNotFound)
}
}
```
- Fasthttp allows setting response headers and writing response body
in an arbitrary order. There is no 'headers first, then body' restriction
like in net/http. The following code is valid for fasthttp:
```go
requestHandler := func(ctx *fasthttp.RequestCtx) {
// set some headers and status code first
ctx.SetContentType("foo/bar")
ctx.SetStatusCode(fasthttp.StatusOK)
// then write the first part of body
fmt.Fprintf(ctx, "this is the first part of body\n")
// then set more headers
ctx.Response.Header.Set("Foo-Bar", "baz")
// then write more body
fmt.Fprintf(ctx, "this is the second part of body\n")
// then override already written body
ctx.SetBody([]byte("this is completely new body contents"))
// then update status code
ctx.SetStatusCode(fasthttp.StatusNotFound)
// basically, anything may be updated many times before
// returning from RequestHandler.
//
// Unlike net/http fasthttp doesn't put response to the wire until
// returning from RequestHandler.
}
```
- Fasthttp doesn't provide [ServeMux](https://pkg.go.dev/net/http#ServeMux),
but there are more powerful third-party routers and web frameworks
with fasthttp support:
- [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing)
- [router](https://github.com/fasthttp/router)
- [lu](https://github.com/vincentLiuxiang/lu)
- [atreugo](https://github.com/savsgio/atreugo)
- [Fiber](https://github.com/gofiber/fiber)
- [Gearbox](https://github.com/gogearbox/gearbox)
Net/http code with simple ServeMux is trivially converted to fasthttp code:
```go
// net/http code
m := &http.ServeMux{}
m.HandleFunc("/foo", fooHandlerFunc)
m.HandleFunc("/bar", barHandlerFunc)
m.Handle("/baz", bazHandler)
http.ListenAndServe(":80", m)
```
```go
// the corresponding fasthttp code
m := func(ctx *fasthttp.RequestCtx) {
switch string(ctx.Path()) {
case "/foo":
fooHandlerFunc(ctx)
case "/bar":
barHandlerFunc(ctx)
case "/baz":
bazHandler.HandlerFunc(ctx)
default:
ctx.Error("not found", fasthttp.StatusNotFound)
}
}
fasthttp.ListenAndServe(":80", m)
```
- Because creating a new channel for every request is just too expensive, so the channel returned by RequestCtx.Done() is only closed when the server is shutting down.
```go
func main() {
fasthttp.ListenAndServe(":8080", fasthttp.TimeoutHandler(func(ctx *fasthttp.RequestCtx) {
select {
case <-ctx.Done():
// ctx.Done() is only closed when the server is shutting down.
log.Println("context cancelled")
return
case <-time.After(10 * time.Second):
log.Println("process finished ok")
}
}, time.Second*2, "timeout"))
}
```
- net/http -> fasthttp conversion table:
- All the pseudocode below assumes w, r and ctx have these types:
```go
var (
w http.ResponseWriter
r *http.Request
ctx *fasthttp.RequestCtx
)
```
- [r.Body](https://pkg.go.dev/net/http#Request) **➜** [ctx.PostBody()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostBody)
- [r.URL.Path](https://pkg.go.dev/net/url#URL) **➜** [ctx.Path()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Path)
- [r.URL](https://pkg.go.dev/net/http#Request) **➜** [ctx.URI()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.URI)
- [r.Method](https://pkg.go.dev/net/http#Request) **➜** [ctx.Method()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Method)
- [r.Header](https://pkg.go.dev/net/http#Request) **➜** [ctx.Request.Header](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHeader)
- [r.Header.Get()](https://pkg.go.dev/net/http#Header.Get) **➜** [ctx.Request.Header.Peek()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHeader.Peek)
- [r.Host](https://pkg.go.dev/net/http#Request) **➜** [ctx.Host()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Host)
- [r.Form](https://pkg.go.dev/net/http#Request) **➜** [ctx.QueryArgs()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.QueryArgs) +
[ctx.PostArgs()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostArgs)
- [r.PostForm](https://pkg.go.dev/net/http#Request) **➜** [ctx.PostArgs()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostArgs)
- [r.FormValue()](https://pkg.go.dev/net/http#Request.FormValue) **➜** [ctx.FormValue()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.FormValue)
- [r.FormFile()](https://pkg.go.dev/net/http#Request.FormFile) **➜** [ctx.FormFile()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.FormFile)
- [r.MultipartForm](https://pkg.go.dev/net/http#Request) **➜** [ctx.MultipartForm()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.MultipartForm)
For untrusted multipart input, use [ctx.MultipartFormWithLimit()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.MultipartFormWithLimit) (or a custom [Server.FormValueFunc](https://pkg.go.dev/github.com/valyala/fasthttp#Server)) to enforce a parsing size limit.
- [r.RemoteAddr](https://pkg.go.dev/net/http#Request) **➜** [ctx.RemoteAddr()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.RemoteAddr)
- [r.RequestURI](https://pkg.go.dev/net/http#Request) **➜** [ctx.RequestURI()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.RequestURI)
- [r.TLS](https://pkg.go.dev/net/http#Request) **➜** [ctx.IsTLS()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.IsTLS)
- [r.Cookie()](https://pkg.go.dev/net/http#Request.Cookie) **➜** [ctx.Request.Header.Cookie()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHeader.Cookie)
- [r.Referer()](https://pkg.go.dev/net/http#Request.Referer) **➜** [ctx.Referer()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Referer)
- [r.UserAgent()](https://pkg.go.dev/net/http#Request.UserAgent) **➜** [ctx.UserAgent()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.UserAgent)
- [w.Header()](https://pkg.go.dev/net/http#ResponseWriter) **➜** [ctx.Response.Header](https://pkg.go.dev/github.com/valyala/fasthttp#ResponseHeader)
- [w.Header().Set()](https://pkg.go.dev/net/http#Header.Set) **➜** [ctx.Response.Header.Set()](https://pkg.go.dev/github.com/valyala/fasthttp#ResponseHeader.Set)
- [w.Header().Set("Content-Type")](https://pkg.go.dev/net/http#Header.Set) **➜** [ctx.SetContentType()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetContentType)
- [w.Header().Set("Set-Cookie")](https://pkg.go.dev/net/http#Header.Set) **➜** [ctx.Response.Header.SetCookie()](https://pkg.go.dev/github.com/valyala/fasthttp#ResponseHeader.SetCookie)
- [w.Write()](https://pkg.go.dev/net/http#ResponseWriter) **➜** [ctx.Write()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Write),
[ctx.SetBody()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetBody),
[ctx.SetBodyStream()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetBodyStream),
[ctx.SetBodyStreamWriter()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetBodyStreamWriter)
- [w.WriteHeader()](https://pkg.go.dev/net/http#ResponseWriter) **➜** [ctx.SetStatusCode()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.SetStatusCode)
- [w.(http.Hijacker).Hijack()](https://pkg.go.dev/net/http#Hijacker) **➜** [ctx.Hijack()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Hijack)
- [http.Error()](https://pkg.go.dev/net/http#Error) **➜** [ctx.Error()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Error)
- [http.FileServer()](https://pkg.go.dev/net/http#FileServer) **➜** [fasthttp.FSHandler()](https://pkg.go.dev/github.com/valyala/fasthttp#FSHandler),
[fasthttp.FS](https://pkg.go.dev/github.com/valyala/fasthttp#FS)
- [http.ServeFile()](https://pkg.go.dev/net/http#ServeFile) **➜** [fasthttp.ServeFile()](https://pkg.go.dev/github.com/valyala/fasthttp#ServeFile)
- [http.Redirect()](https://pkg.go.dev/net/http#Redirect) **➜** [ctx.Redirect()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Redirect)
- [http.NotFound()](https://pkg.go.dev/net/http#NotFound) **➜** [ctx.NotFound()](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.NotFound)
- [http.StripPrefix()](https://pkg.go.dev/net/http#StripPrefix) **➜** [fasthttp.PathRewriteFunc](https://pkg.go.dev/github.com/valyala/fasthttp#PathRewriteFunc)
- _VERY IMPORTANT!_ Fasthttp disallows holding references
to [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx) or to its'
members after returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
Otherwise [data races](http://go.dev/blog/race-detector) are inevitable.
Carefully inspect all the net/http request handlers converted to fasthttp whether
they retain references to RequestCtx or to its' members after returning.
RequestCtx provides the following _band aids_ for this case:
- Wrap RequestHandler into [TimeoutHandler](https://pkg.go.dev/github.com/valyala/fasthttp#TimeoutHandler).
- Call [TimeoutError](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.TimeoutError)
before returning from RequestHandler if there are references to RequestCtx or to its' members.
See [the example](https://pkg.go.dev/github.com/valyala/fasthttp#example-RequestCtx-TimeoutError)
for more details.
Use this brilliant tool - [race detector](http://go.dev/blog/race-detector) -
for detecting and eliminating data races in your program. If you detected
data race related to fasthttp in your program, then there is high probability
you forgot calling [TimeoutError](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.TimeoutError)
before returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
- Blind switching from net/http to fasthttp won't give you performance boost.
While fasthttp is optimized for speed, its' performance may be easily saturated
by slow [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
So [profile](http://go.dev/blog/pprof) and optimize your
code after switching to fasthttp. For instance, use [quicktemplate](https://github.com/valyala/quicktemplate)
instead of [html/template](https://pkg.go.dev/html/template).
- See also [fasthttputil](https://pkg.go.dev/github.com/valyala/fasthttp/fasthttputil),
[fasthttpadaptor](https://pkg.go.dev/github.com/valyala/fasthttp/fasthttpadaptor) and
[expvarhandler](https://pkg.go.dev/github.com/valyala/fasthttp/expvarhandler).
## Performance optimization tips for multi-core systems
- Use [reuseport](https://pkg.go.dev/github.com/valyala/fasthttp/reuseport) listener.
- Run a separate server instance per CPU core with GOMAXPROCS=1.
- Pin each server instance to a separate CPU core using [taskset](http://linux.die.net/man/1/taskset).
- Ensure the interrupts of multiqueue network card are evenly distributed between CPU cores.
See [this article](https://blog.cloudflare.com/how-to-achieve-low-latency/) for details.
- Use the latest version of Go as each version contains performance improvements.
## Fasthttp best practices
- Do not allocate objects and `[]byte` buffers - just reuse them as much
as possible. Fasthttp API design encourages this.
- [sync.Pool](https://pkg.go.dev/sync#Pool) is your best friend.
- [Profile your program](http://go.dev/blog/pprof)
in production.
`go tool pprof --alloc_objects your-program mem.pprof` usually gives better
insights for optimization opportunities than `go tool pprof your-program cpu.pprof`.
- Write [tests and benchmarks](https://pkg.go.dev/testing) for hot paths.
- Avoid conversion between `[]byte` and `string`, since this may result in memory
allocation+copy - see [this wiki page](https://github.com/golang/go/wiki/CompilerOptimizations#string-and-byte)
for more details.
- Verify your tests and production code under
[race detector](https://go.dev/doc/articles/race_detector.html) on a regular basis.
- Prefer [quicktemplate](https://github.com/valyala/quicktemplate) instead of
[html/template](https://pkg.go.dev/html/template) in your webserver.
## Unsafe Zero-Allocation Conversions
In performance-critical code, converting between `[]byte` and `string` using standard Go allocations can be inefficient. To address this, `fasthttp` uses **unsafe**, zero-allocation helpers:
> ⚠️ **Warning:** These conversions break Go's type safety. Use only when you're certain the converted value will not be mutated, as violating immutability can cause undefined behavior.
### `UnsafeString(b []byte) string`
Converts a `[]byte` to a `string` **without memory allocation**.
```go
// UnsafeString returns a string pointer without allocation
func UnsafeString(b []byte) string {
// #nosec G103
return *(*string)(unsafe.Pointer(&b))
}
```
### `UnsafeBytes(s string) []byte`
Converts a `string` to a `[]byte` **without memory allocation**.
```go
// UnsafeBytes returns a byte pointer without allocation.
func UnsafeBytes(s string) []byte {
// #nosec G103
return unsafe.Slice(unsafe.StringData(s), len(s))
}
```
### Use Cases & Caveats
- These functions are ideal for performance-sensitive scenarios where allocations must be avoided (e.g., request/response processing loops).
- **Do not** mutate the `[]byte` returned from `UnsafeBytes(s string)` if the original string is still in use, as strings are immutable in Go and may be shared across the runtime.
- Use samples guarded with `#nosec G103` comments to suppress static analysis warnings about unsafe operations.
## Tricks with `[]byte` buffers
The following tricks are used by fasthttp. Use them in your code too.
- Standard Go functions accept nil buffers
```go
var (
// both buffers are uninitialized
dst []byte
src []byte
)
dst = append(dst, src...) // is legal if dst is nil and/or src is nil
copy(dst, src) // is legal if dst is nil and/or src is nil
(string(src) == "") // is true if src is nil
(len(src) == 0) // is true if src is nil
src = src[:0] // works like a charm with nil src
// this for loop doesn't panic if src is nil
for i, ch := range src {
doSomething(i, ch)
}
```
So throw away nil checks for `[]byte` buffers from you code. For example,
```go
srcLen := 0
if src != nil {
srcLen = len(src)
}
```
becomes
```go
srcLen := len(src)
```
- String may be appended to `[]byte` buffer with `append`
```go
dst = append(dst, "foobar"...)
```
- `[]byte` buffer may be extended to its' capacity.
```go
buf := make([]byte, 100)
a := buf[:10] // len(a) == 10, cap(a) == 100.
b := a[:100] // is valid, since cap(a) == 100.
```
- All fasthttp functions accept nil `[]byte` buffer
```go
statusCode, body, err := fasthttp.Get(nil, "http://google.com/")
uintBuf := fasthttp.AppendUint(nil, 1234)
```
- String and `[]byte` buffers may converted without memory allocations
```go
func b2s(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func s2b(s string) (b []byte) {
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh.Data = sh.Data
bh.Cap = sh.Len
bh.Len = sh.Len
return b
}
```
### Warning:
This is an **unsafe** way, the result string and `[]byte` buffer share the same bytes.
**Please make sure not to modify the bytes in the `[]byte` buffer if the string still survives!**
## Related projects
- [fasthttp](https://github.com/fasthttp) - various useful
helpers for projects based on fasthttp.
- [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing) - fast and
powerful routing package for fasthttp servers.
- [http2](https://github.com/dgrr/http2) - HTTP/2 implementation for fasthttp.
- [router](https://github.com/fasthttp/router) - a high
performance fasthttp request router that scales well.
- [fasthttp-auth](https://github.com/casbin/fasthttp-auth) - Authorization middleware for fasthttp using Casbin.
- [fastws](https://github.com/fasthttp/fastws) - Bloatless WebSocket package made for fasthttp
to handle Read/Write operations concurrently.
- [gramework](https://github.com/gramework/gramework) - a web framework made by one of fasthttp maintainers.
- [lu](https://github.com/vincentLiuxiang/lu) - a high performance
go middleware web framework which is based on fasthttp.
- [websocket](https://github.com/fasthttp/websocket) - Gorilla-based
websocket implementation for fasthttp.
- [websocket](https://github.com/dgrr/websocket) - Event-based high-performance WebSocket library for zero-allocation
websocket servers and clients.
- [fasthttpsession](https://github.com/phachon/fasthttpsession) - a fast and powerful session package for fasthttp servers.
- [atreugo](https://github.com/savsgio/atreugo) - High performance and extensible micro web framework with zero memory allocations in hot paths.
- [kratgo](https://github.com/savsgio/kratgo) - Simple, lightweight and ultra-fast HTTP Cache to speed up your websites.
- [kit-plugins](https://github.com/wencan/kit-plugins/tree/master/transport/fasthttp) - go-kit transport implementation for fasthttp.
- [Fiber](https://github.com/gofiber/fiber) - An Expressjs inspired web framework running on Fasthttp.
- [Gearbox](https://github.com/gogearbox/gearbox) - :gear: gearbox is a web framework written in Go with a focus on high performance and memory optimization.
- [http2curl](https://github.com/li-jin-gou/http2curl) - A tool to convert fasthttp requests to curl command line.
- [OpenTelemetry Golang Compile Time Instrumentation](https://github.com/alibaba/opentelemetry-go-auto-instrumentation) - A tool to monitor fasthttp application without changing any code with OpenTelemetry APIs.
## FAQ
- _Why creating yet another http package instead of optimizing net/http?_
Because net/http API limits many optimization opportunities.
For example:
- net/http Request object lifetime isn't limited by request handler execution
time. So the server must create a new request object per each request instead
of reusing existing objects like fasthttp does.
- net/http headers are stored in a `map[string][]string`. So the server
must parse all the headers, convert them from `[]byte` to `string` and put
them into the map before calling user-provided request handler.
This all requires unnecessary memory allocations avoided by fasthttp.
- net/http client API requires creating a new response object per each request.
- _Why fasthttp API is incompatible with net/http?_
Because net/http API limits many optimization opportunities. See the answer
above for more details. Also certain net/http API parts are suboptimal
for use:
- Compare [net/http connection hijacking](https://pkg.go.dev/net/http#Hijacker)
to [fasthttp connection hijacking](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Hijack).
- Compare [net/http Request.Body reading](https://pkg.go.dev/net/http#Request)
to [fasthttp request body reading](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.PostBody).
- _Why fasthttp doesn't support HTTP/2.0 and WebSockets?_
[HTTP/2.0 support](https://github.com/fasthttp/http2) is in progress. [WebSockets](https://github.com/fasthttp/websockets) has been done already.
Third parties also may use [RequestCtx.Hijack](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.Hijack)
for implementing these goodies.
- _Are there known net/http advantages comparing to fasthttp?_
Yes:
- net/http supports [HTTP/2.0 starting from go1.6](https://pkg.go.dev/golang.org/x/net/http2).
- net/http API is stable, while fasthttp API constantly evolves.
- net/http handles more HTTP corner cases.
- net/http can stream both request and response bodies
- net/http can handle bigger bodies as it doesn't read the whole body into memory
- net/http should contain less bugs, since it is used and tested by much
wider audience.
- _Why fasthttp API prefers returning `[]byte` instead of `string`?_
Because `[]byte` to `string` conversion isn't free - it requires memory
allocation and copy. Feel free wrapping returned `[]byte` result into
`string()` if you prefer working with strings instead of byte slices.
But be aware that this has non-zero overhead.
- _Which GO versions are supported by fasthttp?_
We support the same versions the Go team supports.
Currently that is Go 1.24.x and newer.
Older versions might work, but won't officially be supported.
- _Please provide real benchmark data and server information_
See [this issue](https://github.com/valyala/fasthttp/issues/4).
- _Are there plans to add request routing to fasthttp?_
There are no plans to add request routing into fasthttp.
Use third-party routers and web frameworks with fasthttp support:
- [fasthttp-routing](https://github.com/qiangxue/fasthttp-routing)
- [router](https://github.com/fasthttp/router)
- [gramework](https://github.com/gramework/gramework)
- [lu](https://github.com/vincentLiuxiang/lu)
- [atreugo](https://github.com/savsgio/atreugo)
- [Fiber](https://github.com/gofiber/fiber)
- [Gearbox](https://github.com/gogearbox/gearbox)
- _I detected data race in fasthttp!_
Cool! [File a bug](https://github.com/valyala/fasthttp/issues/new). But before
doing this check the following in your code:
- Make sure there are no references to [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx)
or to its' members after returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler).
- Make sure you call [TimeoutError](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx.TimeoutError)
before returning from [RequestHandler](https://pkg.go.dev/github.com/valyala/fasthttp#RequestHandler)
if there are references to [RequestCtx](https://pkg.go.dev/github.com/valyala/fasthttp#RequestCtx)
or to its' members, which may be accessed by other goroutines.
- _I didn't find an answer for my question here_
Try exploring [these questions](https://github.com/valyala/fasthttp/issues?q=label%3Aquestion).
================================================
FILE: SECURITY.md
================================================
### TL;DR
We use a simplified version of [Golang Security Policy](https://go.dev/security).
For example, for now we skip CVE assignment.
### Reporting a Security Bug
Please report to us any issues you find. This document explains how to do that and what to expect in return.
All security bugs in our releases should be reported by email to erik@dubbelboer.com
Your email will be acknowledged within 24 hours, and you'll receive a more detailed response
to your email within 72 hours indicating the next steps in handling your report.
Please use a descriptive subject line for your report email.
### Flagging Existing Issues as Security-related
If you believe that an existing issue is security-related, we ask that you send an email to erik@dubbelboer.com
The email should include the issue ID and a short description of why it should be handled according to this security policy.
### Disclosure Process
Our project uses the following disclosure process:
- Once the security report is received it is assigned a primary handler. This person coordinates the fix and release process.
- The issue is confirmed and a list of affected software is determined.
- Code is audited to find any potential similar problems.
- Fixes are prepared for the two most recent major releases and the head/master revision. These fixes are not yet committed to the public repository.
- To notify users, a new issue without security details is submitted to our GitHub repository.
- Three working days following this notification, the fixes are applied to the public repository and a new release is issued.
- On the date that the fixes are applied, announcement is published in the issue.
This process can take some time, especially when coordination is required with maintainers of other projects.
Every effort will be made to handle the bug in as timely a manner as possible, however it's important that we follow
the process described above to ensure that disclosures are handled consistently.
### Receiving Security Updates
The best way to receive security announcements is to subscribe ("Watch") to our repository.
Any GitHub issues pertaining to a security issue will be prefixed with [security].
### Comments on This Policy
If you have any suggestions to improve this policy, please send an email to erik@dubbelboer.com for discussion.
================================================
FILE: TODO
================================================
- SessionClient with referer and cookies support.
- ProxyHandler similar to FSHandler.
- WebSockets. See https://tools.ietf.org/html/rfc6455 .
- HTTP/2.0. See https://tools.ietf.org/html/rfc7540 .
================================================
FILE: allocation_test.go
================================================
//go:build !race
package fasthttp
import (
"net"
"testing"
)
func TestAllocationServeConn(t *testing.T) {
s := &Server{
Handler: func(ctx *RequestCtx) {
ctx.SetStatusCode(StatusOK)
ctx.SetBodyString("Hello, World!")
ctx.Response.Header.Set("Content-Type", "text/plain; charset=utf-8")
},
}
rw := &readWriter{}
// Make space for the request and response here so it
// doesn't allocate within the test.
rw.r.Grow(1024)
rw.w.Grow(1024)
n := testing.AllocsPerRun(100, func() {
rw.r.WriteString("GET / HTTP/1.1\r\nHost: google.com\r\nCookie: foo=bar\r\n\r\n")
if err := s.ServeConn(rw); err != nil {
t.Fatal(err)
}
// Reset the write buffer to make space for the next response.
rw.w.Reset()
})
if n != 0 {
t.Fatalf("expected 0 allocations, got %f", n)
}
}
func TestAllocationClient(t *testing.T) {
ln, err := net.Listen("tcp4", "127.0.0.1:0")
if err != nil {
t.Fatalf("cannot listen: %v", err)
}
defer ln.Close()
s := &Server{
Handler: func(ctx *RequestCtx) {
ctx.SetStatusCode(StatusOK)
ctx.SetBodyString("Hello, World!")
ctx.Response.Header.Set("Content-Type", "text/plain; charset=utf-8")
},
}
go s.Serve(ln) //nolint:errcheck
c := &Client{}
url := "http://test:test@" + ln.Addr().String() + "/foo?bar=baz"
n := testing.AllocsPerRun(100, func() {
req := AcquireRequest()
res := AcquireResponse()
req.SetRequestURI(url)
req.Header.Add("Foo", "bar")
if err := c.Do(req, res); err != nil {
t.Fatal(err)
}
ReleaseRequest(req)
ReleaseResponse(res)
})
if n != 0 {
t.Fatalf("expected 0 allocations, got %f", n)
}
}
func TestAllocationURI(t *testing.T) {
uri := []byte("http://username:password@hello.%e4%b8%96%e7%95%8c.com/some/path?foo=bar#test")
n := testing.AllocsPerRun(100, func() {
u := AcquireURI()
u.Parse(nil, uri) //nolint:errcheck
ReleaseURI(u)
})
if n != 0 {
t.Fatalf("expected 0 allocations, got %f", n)
}
}
func TestAllocationFS(t *testing.T) {
// Create a simple test filesystem handler
fs := &FS{
Root: ".",
GenerateIndexPages: false,
Compress: false,
AcceptByteRange: false,
}
h := fs.NewRequestHandler()
ctx := &RequestCtx{}
n := testing.AllocsPerRun(100, func() {
ctx.Request.Reset()
ctx.Response.Reset()
ctx.Request.SetRequestURI("/allocation_test.go")
ctx.Request.Header.Set("Host", "localhost")
h(ctx)
})
t.Logf("FS operations allocate %f times per request", n)
if n != 0 {
t.Fatalf("expected 0 allocations, got %f", n)
}
}
func TestAllocationsHeaderScanner(t *testing.T) {
body := []byte("Host: a.com\r\nCookie: foo=bar\r\nWithTabs: \t v1 \t\r\nWithTabs-Start: \t \t v1 \r\nWithTabs-End: v1 \t \t\t\t\r\nWithTabs-Multi-Line: \t v1 \t;\r\n \t v2 \t;\r\n\t v3\r\n\r\n")
n := testing.AllocsPerRun(100, func() {
var s headerScanner
s.b = body
for s.next() {
}
if s.err != nil {
t.Fatal(s.err)
}
})
if n != 0 {
t.Fatalf("expected 0 allocations, got %f", n)
}
}
================================================
FILE: args.go
================================================
package fasthttp
import (
"bytes"
"errors"
"io"
"iter"
"sort"
"sync"
)
const (
argsNoValue = true
argsHasValue = false
)
// AcquireArgs returns an empty Args object from the pool.
//
// The returned Args may be returned to the pool with ReleaseArgs
// when no longer needed. This allows reducing GC load.
func AcquireArgs() *Args {
return argsPool.Get().(*Args)
}
// ReleaseArgs returns the object acquired via AcquireArgs to the pool.
//
// Do not access the released Args object, otherwise data races may occur.
func ReleaseArgs(a *Args) {
a.Reset()
argsPool.Put(a)
}
var argsPool = &sync.Pool{
New: func() any {
return &Args{}
},
}
// Args represents query arguments.
//
// It is forbidden copying Args instances. Create new instances instead
// and use CopyTo().
//
// Args instance MUST NOT be used from concurrently running goroutines.
type Args struct {
noCopy noCopy
args []argsKV
buf []byte
}
type argsKV struct {
key []byte
value []byte
noValue bool
}
// Reset clears query args.
func (a *Args) Reset() {
a.args = a.args[:0]
}
// CopyTo copies all args to dst.
func (a *Args) CopyTo(dst *Args) {
dst.args = copyArgs(dst.args, a.args)
}
// All returns an iterator over key-value pairs from args.
//
// The key and value may invalid outside the iteration loop.
// Make copies if you need to use them after the loop ends.
//
// Making modifications to the Args during the iteration loop leads to undefined
// behavior and can cause panics.
func (a *Args) All() iter.Seq2[[]byte, []byte] {
return func(yield func([]byte, []byte) bool) {
for i := range a.args {
if !yield(a.args[i].key, a.args[i].value) {
break
}
}
}
}
// VisitAll calls f for each existing arg.
//
// f must not retain references to key and value after returning.
// Make key and/or value copies if you need storing them after returning.
//
// Deprecated: Use All instead.
func (a *Args) VisitAll(f func(key, value []byte)) {
a.All()(func(key, value []byte) bool {
f(key, value)
return true
})
}
// Len returns the number of query args.
func (a *Args) Len() int {
return len(a.args)
}
// Parse parses the given string containing query args.
func (a *Args) Parse(s string) {
a.buf = append(a.buf[:0], s...)
a.ParseBytes(a.buf)
}
// ParseBytes parses the given b containing query args.
func (a *Args) ParseBytes(b []byte) {
a.Reset()
var s argsScanner
s.b = b
var kv *argsKV
a.args, kv = allocArg(a.args)
for s.next(kv) {
if len(kv.key) > 0 || len(kv.value) > 0 {
a.args, kv = allocArg(a.args)
}
}
a.args = releaseArg(a.args)
}
// String returns string representation of query args.
func (a *Args) String() string {
return string(a.QueryString())
}
// QueryString returns query string for the args.
//
// The returned value is valid until the Args is reused or released (ReleaseArgs).
// Do not store references to the returned value. Make copies instead.
func (a *Args) QueryString() []byte {
a.buf = a.AppendBytes(a.buf[:0])
return a.buf
}
// Sort sorts Args by key and then value using 'f' as comparison function.
//
// For example args.Sort(bytes.Compare).
func (a *Args) Sort(f func(x, y []byte) int) {
sort.SliceStable(a.args, func(i, j int) bool {
n := f(a.args[i].key, a.args[j].key)
if n == 0 {
return f(a.args[i].value, a.args[j].value) == -1
}
return n == -1
})
}
// SortKeys sorts Args by key only using 'f' as comparison function.
//
// For example args.SortKeys(bytes.Compare).
func (a *Args) SortKeys(f func(x, y []byte) int) {
sort.SliceStable(a.args, func(i, j int) bool {
return f(a.args[i].key, a.args[j].key) == -1
})
}
// AppendBytes appends query string to dst and returns the extended dst.
func (a *Args) AppendBytes(dst []byte) []byte {
for i, n := 0, len(a.args); i < n; i++ {
kv := &a.args[i]
dst = AppendQuotedArg(dst, kv.key)
if !kv.noValue {
dst = append(dst, '=')
if len(kv.value) > 0 {
dst = AppendQuotedArg(dst, kv.value)
}
}
if i+1 < n {
dst = append(dst, '&')
}
}
return dst
}
// WriteTo writes query string to w.
//
// WriteTo implements io.WriterTo interface.
func (a *Args) WriteTo(w io.Writer) (int64, error) {
n, err := w.Write(a.QueryString())
return int64(n), err
}
// Del deletes argument with the given key from query args.
func (a *Args) Del(key string) {
a.args = delAllArgsStable(a.args, key)
}
// DelBytes deletes argument with the given key from query args.
func (a *Args) DelBytes(key []byte) {
a.args = delAllArgsStable(a.args, b2s(key))
}
// Add adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func (a *Args) Add(key, value string) {
a.args = appendArg(a.args, key, value, argsHasValue)
}
// AddBytesK adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func (a *Args) AddBytesK(key []byte, value string) {
a.args = appendArg(a.args, b2s(key), value, argsHasValue)
}
// AddBytesV adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func (a *Args) AddBytesV(key string, value []byte) {
a.args = appendArg(a.args, key, b2s(value), argsHasValue)
}
// AddBytesKV adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func (a *Args) AddBytesKV(key, value []byte) {
a.args = appendArg(a.args, b2s(key), b2s(value), argsHasValue)
}
// AddNoValue adds only 'key' as argument without the '='.
//
// Multiple values for the same key may be added.
func (a *Args) AddNoValue(key string) {
a.args = appendArg(a.args, key, "", argsNoValue)
}
// AddBytesKNoValue adds only 'key' as argument without the '='.
//
// Multiple values for the same key may be added.
func (a *Args) AddBytesKNoValue(key []byte) {
a.args = appendArg(a.args, b2s(key), "", argsNoValue)
}
// Set sets 'key=value' argument.
func (a *Args) Set(key, value string) {
a.args = setArg(a.args, key, value, argsHasValue)
}
// SetBytesK sets 'key=value' argument.
func (a *Args) SetBytesK(key []byte, value string) {
a.args = setArg(a.args, b2s(key), value, argsHasValue)
}
// SetBytesV sets 'key=value' argument.
func (a *Args) SetBytesV(key string, value []byte) {
a.args = setArg(a.args, key, b2s(value), argsHasValue)
}
// SetBytesKV sets 'key=value' argument.
func (a *Args) SetBytesKV(key, value []byte) {
a.args = setArgBytes(a.args, key, value, argsHasValue)
}
// SetNoValue sets only 'key' as argument without the '='.
//
// Only key in argument, like key1&key2.
func (a *Args) SetNoValue(key string) {
a.args = setArg(a.args, key, "", argsNoValue)
}
// SetBytesKNoValue sets 'key' argument.
func (a *Args) SetBytesKNoValue(key []byte) {
a.args = setArg(a.args, b2s(key), "", argsNoValue)
}
// Peek returns query arg value for the given key.
//
// The returned value is valid until the Args is reused or released (ReleaseArgs).
// Do not store references to the returned value. Make copies instead.
func (a *Args) Peek(key string) []byte {
return peekArgStr(a.args, key)
}
// PeekBytes returns query arg value for the given key.
//
// The returned value is valid until the Args is reused or released (ReleaseArgs).
// Do not store references to the returned value. Make copies instead.
func (a *Args) PeekBytes(key []byte) []byte {
return peekArgBytes(a.args, key)
}
// PeekMulti returns all the arg values for the given key.
func (a *Args) PeekMulti(key string) [][]byte {
var values [][]byte
for k, v := range a.All() {
if string(k) == key {
values = append(values, v)
}
}
return values
}
// PeekMultiBytes returns all the arg values for the given key.
func (a *Args) PeekMultiBytes(key []byte) [][]byte {
return a.PeekMulti(b2s(key))
}
// Has returns true if the given key exists in Args.
func (a *Args) Has(key string) bool {
return hasArg(a.args, key)
}
// HasBytes returns true if the given key exists in Args.
func (a *Args) HasBytes(key []byte) bool {
return hasArg(a.args, b2s(key))
}
// ErrNoArgValue is returned when Args value with the given key is missing.
var ErrNoArgValue = errors.New("no Args value for the given key")
// GetUint returns uint value for the given key.
func (a *Args) GetUint(key string) (int, error) {
value := a.Peek(key)
if len(value) == 0 {
return -1, ErrNoArgValue
}
return ParseUint(value)
}
// SetUint sets uint value for the given key.
func (a *Args) SetUint(key string, value int) {
a.buf = AppendUint(a.buf[:0], value)
a.SetBytesV(key, a.buf)
}
// SetUintBytes sets uint value for the given key.
func (a *Args) SetUintBytes(key []byte, value int) {
a.SetUint(b2s(key), value)
}
// GetUintOrZero returns uint value for the given key.
//
// Zero (0) is returned on error.
func (a *Args) GetUintOrZero(key string) int {
n, err := a.GetUint(key)
if err != nil {
n = 0
}
return n
}
// GetUfloat returns ufloat value for the given key.
func (a *Args) GetUfloat(key string) (float64, error) {
value := a.Peek(key)
if len(value) == 0 {
return -1, ErrNoArgValue
}
return ParseUfloat(value)
}
// GetUfloatOrZero returns ufloat value for the given key.
//
// Zero (0) is returned on error.
func (a *Args) GetUfloatOrZero(key string) float64 {
f, err := a.GetUfloat(key)
if err != nil {
f = 0
}
return f
}
// GetBool returns boolean value for the given key.
//
// true is returned for "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes",
// otherwise false is returned.
func (a *Args) GetBool(key string) bool {
switch string(a.Peek(key)) {
// Support the same true cases as strconv.ParseBool
// See: https://github.com/golang/go/blob/4e1b11e2c9bdb0ddea1141eed487be1a626ff5be/src/strconv/atob.go#L12
// and Y and Yes versions.
case "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes":
return true
default:
return false
}
}
func copyArgs(dst, src []argsKV) []argsKV {
if cap(dst) < len(src) {
tmp := make([]argsKV, len(src))
dstLen := len(dst)
dst = dst[:cap(dst)] // copy all of dst.
copy(tmp, dst)
for i := dstLen; i < len(tmp); i++ {
// Make sure nothing is nil.
tmp[i].key = []byte{}
tmp[i].value = []byte{}
}
dst = tmp
}
n := len(src)
dst = dst[:n]
for i := range n {
dstKV := &dst[i]
srcKV := &src[i]
dstKV.key = append(dstKV.key[:0], srcKV.key...)
if srcKV.noValue {
dstKV.value = dstKV.value[:0]
} else {
dstKV.value = append(dstKV.value[:0], srcKV.value...)
}
dstKV.noValue = srcKV.noValue
}
return dst
}
func delAllArgsStable(args []argsKV, key string) []argsKV {
for i, n := 0, len(args); i < n; i++ {
kv := &args[i]
if key == string(kv.key) {
tmp := *kv
copy(args[i:], args[i+1:])
n--
i--
args[n] = tmp
args = args[:n]
}
}
return args
}
func delAllArgs(args []argsKV, key string) []argsKV {
n := len(args)
for i := 0; i < n; i++ {
if key == string(args[i].key) {
args[i], args[n-1] = args[n-1], args[i]
n--
i--
}
}
return args[:n]
}
func setArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
return setArg(h, b2s(key), b2s(value), noValue)
}
func setArg(h []argsKV, key, value string, noValue bool) []argsKV {
n := len(h)
for i := range n {
kv := &h[i]
if key == string(kv.key) {
if noValue {
kv.value = kv.value[:0]
} else {
kv.value = append(kv.value[:0], value...)
}
kv.noValue = noValue
return h
}
}
return appendArg(h, key, value, noValue)
}
func appendArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
return appendArg(h, b2s(key), b2s(value), noValue)
}
func appendArg(args []argsKV, key, value string, noValue bool) []argsKV {
var kv *argsKV
args, kv = allocArg(args)
kv.key = append(kv.key[:0], key...)
if noValue {
kv.value = kv.value[:0]
} else {
kv.value = append(kv.value[:0], value...)
}
kv.noValue = noValue
return args
}
func allocArg(h []argsKV) ([]argsKV, *argsKV) {
n := len(h)
if cap(h) > n {
h = h[:n+1]
} else {
h = append(h, argsKV{
value: []byte{},
})
}
return h, &h[n]
}
func releaseArg(h []argsKV) []argsKV {
return h[:len(h)-1]
}
func hasArg(h []argsKV, key string) bool {
for i, n := 0, len(h); i < n; i++ {
kv := &h[i]
if key == string(kv.key) {
return true
}
}
return false
}
func peekArgBytes(h []argsKV, k []byte) []byte {
for i, n := 0, len(h); i < n; i++ {
kv := &h[i]
if bytes.Equal(kv.key, k) {
return kv.value
}
}
return nil
}
func peekArgStr(h []argsKV, k string) []byte {
for i, n := 0, len(h); i < n; i++ {
kv := &h[i]
if string(kv.key) == k {
return kv.value
}
}
return nil
}
type argsScanner struct {
b []byte
}
func (s *argsScanner) next(kv *argsKV) bool {
if len(s.b) == 0 {
return false
}
kv.noValue = argsHasValue
isKey := true
k := 0
for i, c := range s.b {
switch c {
case '=':
if isKey {
isKey = false
kv.key = decodeArgAppend(kv.key[:0], s.b[:i])
k = i + 1
}
case '&':
if isKey {
kv.key = decodeArgAppend(kv.key[:0], s.b[:i])
kv.value = kv.value[:0]
kv.noValue = argsNoValue
} else {
kv.value = decodeArgAppend(kv.value[:0], s.b[k:i])
}
s.b = s.b[i+1:]
return true
}
}
if isKey {
kv.key = decodeArgAppend(kv.key[:0], s.b)
kv.value = kv.value[:0]
kv.noValue = argsNoValue
} else {
kv.value = decodeArgAppend(kv.value[:0], s.b[k:])
}
s.b = s.b[len(s.b):]
return true
}
func decodeArgAppend(dst, src []byte) []byte {
idxPercent := bytes.IndexByte(src, '%')
idxPlus := bytes.IndexByte(src, '+')
if idxPercent == -1 && idxPlus == -1 {
// fast path: src doesn't contain encoded chars
return append(dst, src...)
}
var idx int
switch {
case idxPercent == -1:
idx = idxPlus
case idxPlus == -1:
idx = idxPercent
case idxPercent > idxPlus:
idx = idxPlus
default:
idx = idxPercent
}
dst = append(dst, src[:idx]...)
// slow path
for i := idx; i < len(src); i++ {
c := src[i]
switch c {
case '%':
if i+2 >= len(src) {
return append(dst, src[i:]...)
}
x2 := hex2intTable[src[i+2]]
x1 := hex2intTable[src[i+1]]
if x1 == 16 || x2 == 16 {
dst = append(dst, '%')
} else {
dst = append(dst, x1<<4|x2)
i += 2
}
case '+':
dst = append(dst, ' ')
default:
dst = append(dst, c)
}
}
return dst
}
// decodeArgAppendNoPlus is almost identical to decodeArgAppend, but it doesn't
// substitute '+' with ' '.
//
// The function is copy-pasted from decodeArgAppend due to the performance
// reasons only.
func decodeArgAppendNoPlus(dst, src []byte) []byte {
idx := bytes.IndexByte(src, '%')
if idx < 0 {
// fast path: src doesn't contain encoded chars
return append(dst, src...)
}
dst = append(dst, src[:idx]...)
// slow path
for i := idx; i < len(src); i++ {
c := src[i]
if c == '%' {
if i+2 >= len(src) {
return append(dst, src[i:]...)
}
x2 := hex2intTable[src[i+2]]
x1 := hex2intTable[src[i+1]]
if x1 == 16 || x2 == 16 {
dst = append(dst, '%')
} else {
dst = append(dst, x1<<4|x2)
i += 2
}
} else {
dst = append(dst, c)
}
}
return dst
}
func peekAllArgBytesToDst(dst [][]byte, h []argsKV, k []byte) [][]byte {
for i, n := 0, len(h); i < n; i++ {
kv := &h[i]
if bytes.Equal(kv.key, k) {
dst = append(dst, kv.value)
}
}
return dst
}
================================================
FILE: args_test.go
================================================
package fasthttp
import (
"bytes"
"fmt"
"net/url"
"reflect"
"strings"
"testing"
"time"
"github.com/valyala/bytebufferpool"
)
func TestDecodeArgAppend(t *testing.T) {
t.Parallel()
testDecodeArgAppend(t, "", "")
testDecodeArgAppend(t, "foobar", "foobar")
testDecodeArgAppend(t, "тест", "тест")
testDecodeArgAppend(t, "a%", "a%")
testDecodeArgAppend(t, "%a%21", "%a!")
testDecodeArgAppend(t, "ab%test", "ab%test")
testDecodeArgAppend(t, "d%тестF", "d%тестF")
testDecodeArgAppend(t, "a%\xffb%20c", "a%\xffb c")
testDecodeArgAppend(t, "foo%20bar", "foo bar")
testDecodeArgAppend(t, "f.o%2C1%3A2%2F4=%7E%60%21%40%23%24%25%5E%26*%28%29_-%3D%2B%5C%7C%2F%5B%5D%7B%7D%3B%3A%27%22%3C%3E%2C.%2F%3F",
"f.o,1:2/4=~`!@#$%^&*()_-=+\\|/[]{};:'\"<>,./?")
}
func testDecodeArgAppend(t *testing.T, s, expectedResult string) {
result := decodeArgAppend(nil, []byte(s))
if string(result) != expectedResult {
t.Fatalf("unexpected decodeArgAppend(%q)=%q; expecting %q", s, result, expectedResult)
}
}
func TestArgsAdd(t *testing.T) {
t.Parallel()
var a Args
a.Add("foo", "bar")
a.Add("foo", "baz")
a.Add("foo", "1")
a.Add("ba", "23")
a.Add("foo", "")
a.AddNoValue("foo")
if a.Len() != 6 {
t.Fatalf("unexpected number of elements: %d. Expecting 6", a.Len())
}
s := a.String()
expectedS := "foo=bar&foo=baz&foo=1&ba=23&foo=&foo"
if s != expectedS {
t.Fatalf("unexpected result: %q. Expecting %q", s, expectedS)
}
a.Sort(bytes.Compare)
ss := a.String()
expectedSS := "ba=23&foo=&foo&foo=1&foo=bar&foo=baz"
if ss != expectedSS {
t.Fatalf("unexpected result: %q. Expecting %q", ss, expectedSS)
}
var a1 Args
a1.Parse(s)
if a1.Len() != 6 {
t.Fatalf("unexpected number of elements: %d. Expecting 6", a.Len())
}
var barFound, bazFound, oneFound, emptyFound1, emptyFound2, baFound bool
for k, v := range a1.All() {
switch string(k) {
case "foo":
switch string(v) {
case "bar":
barFound = true
case "baz":
bazFound = true
case "1":
oneFound = true
case "":
if emptyFound1 {
emptyFound2 = true
} else {
emptyFound1 = true
}
default:
t.Fatalf("unexpected value %q", v)
}
case "ba":
if string(v) != "23" {
t.Fatalf("unexpected value: %q. Expecting %q", v, "23")
}
baFound = true
default:
t.Fatalf("unexpected key found %q", k)
}
}
if !barFound || !bazFound || !oneFound || !emptyFound1 || !emptyFound2 || !baFound {
t.Fatalf("something is missing: %v, %v, %v, %v, %v, %v", barFound, bazFound, oneFound, emptyFound1, emptyFound2, baFound)
}
}
func TestArgsSortKeys(t *testing.T) {
t.Parallel()
var a Args
a.Add("a", "789")
a.Add("b", "456")
a.Add("a", "123")
a.SortKeys(bytes.Compare)
s := a.String()
expectedS := "a=789&a=123&b=456"
if s != expectedS {
t.Fatalf("unexpected result: %q. Expecting %q", s, expectedS)
}
}
func TestArgsAcquireReleaseSequential(t *testing.T) {
testArgsAcquireRelease(t)
}
func TestArgsAcquireReleaseConcurrent(t *testing.T) {
ch := make(chan struct{}, 10)
for range 10 {
go func() {
testArgsAcquireRelease(t)
ch <- struct{}{}
}()
}
for range 10 {
select {
case <-ch:
case <-time.After(time.Second):
t.Fatalf("timeout")
}
}
}
func testArgsAcquireRelease(t *testing.T) {
a := AcquireArgs()
for i := range 10 {
k := fmt.Sprintf("key_%d", i)
v := fmt.Sprintf("value_%d", i*3+123)
a.Set(k, v)
}
s := a.String()
a.Reset()
a.Parse(s)
for i := range 10 {
k := fmt.Sprintf("key_%d", i)
expectedV := fmt.Sprintf("value_%d", i*3+123)
v := a.Peek(k)
if string(v) != expectedV {
t.Fatalf("unexpected value %q for key %q. Expecting %q", v, k, expectedV)
}
}
ReleaseArgs(a)
}
func TestArgsPeekMulti(t *testing.T) {
t.Parallel()
var a Args
a.Parse("foo=123&bar=121&foo=321&foo=&barz=sdf")
vv := a.PeekMulti("foo")
expectedVV := [][]byte{
[]byte("123"),
[]byte("321"),
[]byte(nil),
}
if !reflect.DeepEqual(vv, expectedVV) {
t.Fatalf("unexpected vv\n%#v\nExpecting\n%#v\n", vv, expectedVV)
}
vv = a.PeekMulti("aaaa")
if len(vv) > 0 {
t.Fatalf("expecting empty result for non-existing key. Got %#v", vv)
}
vv = a.PeekMulti("bar")
expectedVV = [][]byte{[]byte("121")}
if !reflect.DeepEqual(vv, expectedVV) {
t.Fatalf("unexpected vv\n%#v\nExpecting\n%#v\n", vv, expectedVV)
}
}
func TestArgsEscape(t *testing.T) {
t.Parallel()
testArgsEscape(t, "foo", "bar", "foo=bar")
// Test all characters
k := "f.o,1:2/4"
v := make([]byte, 256)
for i := range 256 {
v[i] = byte(i)
}
u := url.Values{}
u.Add(k, string(v))
testArgsEscape(t, k, string(v), u.Encode())
}
func testArgsEscape(t *testing.T, k, v, expectedS string) {
var a Args
a.Set(k, v)
s := a.String()
if s != expectedS {
t.Fatalf("unexpected args %q. Expecting %q. k=%q, v=%q", s, expectedS, k, v)
}
}
func TestPathEscape(t *testing.T) {
t.Parallel()
testPathEscape(t, "/foo/bar")
testPathEscape(t, "")
testPathEscape(t, "/")
testPathEscape(t, "//")
testPathEscape(t, "*") // See https://github.com/golang/go/issues/11202
// Test all characters
pathSegment := make([]byte, 256)
for i := range 256 {
pathSegment[i] = byte(i)
}
testPathEscape(t, "/foo/"+string(pathSegment))
}
func testPathEscape(t *testing.T, s string) {
u := url.URL{Path: s}
expectedS := u.EscapedPath()
res := string(appendQuotedPath(nil, []byte(s)))
if res != expectedS {
t.Fatalf("unexpected args %q. Expecting %q.", res, expectedS)
}
}
func TestArgsWriteTo(t *testing.T) {
t.Parallel()
s := "foo=bar&baz=123&aaa=bbb"
var a Args
a.Parse(s)
var w bytebufferpool.ByteBuffer
n, err := a.WriteTo(&w)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if n != int64(len(s)) {
t.Fatalf("unexpected n: %d. Expecting %d", n, len(s))
}
result := string(w.B)
if result != s {
t.Fatalf("unexpected result %q. Expecting %q", result, s)
}
}
func TestArgsGetBool(t *testing.T) {
t.Parallel()
testArgsGetBool(t, "", false)
testArgsGetBool(t, "0", false)
testArgsGetBool(t, "n", false)
testArgsGetBool(t, "no", false)
testArgsGetBool(t, "1", true)
testArgsGetBool(t, "y", true)
testArgsGetBool(t, "yes", true)
testArgsGetBool(t, "123", false)
testArgsGetBool(t, "foobar", false)
}
func testArgsGetBool(t *testing.T, value string, expectedResult bool) {
var a Args
a.Parse("v=" + value)
result := a.GetBool("v")
if result != expectedResult {
t.Fatalf("unexpected result %v. Expecting %v for value %q", result, expectedResult, value)
}
}
func TestArgsUint(t *testing.T) {
t.Parallel()
var a Args
a.SetUint("foo", 123)
a.SetUint("bar", 0)
a.SetUint("aaaa", 34566)
expectedS := "foo=123&bar=0&aaaa=34566"
s := string(a.QueryString())
if s != expectedS {
t.Fatalf("unexpected args %q. Expecting %q", s, expectedS)
}
if a.GetUintOrZero("foo") != 123 {
t.Fatalf("unexpected arg value %d. Expecting %d", a.GetUintOrZero("foo"), 123)
}
if a.GetUintOrZero("bar") != 0 {
t.Fatalf("unexpected arg value %d. Expecting %d", a.GetUintOrZero("bar"), 0)
}
if a.GetUintOrZero("aaaa") != 34566 {
t.Fatalf("unexpected arg value %d. Expecting %d", a.GetUintOrZero("aaaa"), 34566)
}
if string(a.Peek("foo")) != "123" {
t.Fatalf("unexpected arg value %q. Expecting %q", a.Peek("foo"), "123")
}
if string(a.Peek("bar")) != "0" {
t.Fatalf("unexpected arg value %q. Expecting %q", a.Peek("bar"), "0")
}
if string(a.Peek("aaaa")) != "34566" {
t.Fatalf("unexpected arg value %q. Expecting %q", a.Peek("aaaa"), "34566")
}
}
func TestArgsCopyTo(t *testing.T) {
t.Parallel()
var a Args
// empty args
testCopyTo(t, &a)
a.Set("foo", "bar")
testCopyTo(t, &a)
a.Set("xxx", "yyy")
a.AddNoValue("ba")
testCopyTo(t, &a)
a.Del("foo")
testCopyTo(t, &a)
}
func testCopyTo(t *testing.T, a *Args) {
keys := make(map[string]struct{})
for k := range a.All() {
keys[string(k)] = struct{}{}
}
var b Args
a.CopyTo(&b)
if !reflect.DeepEqual(a, &b) {
t.Fatalf("ArgsCopyTo fail, a: \n%+v\nb: \n%+v\n", a, &b)
}
for k := range b.All() {
if _, ok := keys[string(k)]; !ok {
t.Fatalf("unexpected key %q after copying from %q", k, a.String())
}
delete(keys, string(k))
}
if len(keys) > 0 {
t.Fatalf("missing keys %#v after copying from %q", keys, a.String())
}
}
func TestArgsVisitAll(t *testing.T) {
t.Parallel()
var a Args
a.Set("foo", "bar")
i := 0
a.VisitAll(func(k, v []byte) {
if string(k) != "foo" {
t.Fatalf("unexpected key %q. Expected %q", k, "foo")
}
if string(v) != "bar" {
t.Fatalf("unexpected value %q. Expected %q", v, "bar")
}
i++
})
if i != 1 {
t.Fatalf("unexpected number of VisitAll calls: %d. Expected %d", i, 1)
}
}
func TestArgsStringCompose(t *testing.T) {
t.Parallel()
var a Args
a.Set("foo", "bar")
a.Set("aa", "bbb")
a.Set("привет", "мир")
a.SetNoValue("bb")
a.Set("", "xxxx")
a.Set("cvx", "")
a.SetNoValue("novalue")
expectedS := "foo=bar&aa=bbb&%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82=%D0%BC%D0%B8%D1%80&bb&=xxxx&cvx=&novalue"
s := a.String()
if s != expectedS {
t.Fatalf("Unexpected string %q. Expected %q", s, expectedS)
}
}
func TestArgsString(t *testing.T) {
t.Parallel()
var a Args
testArgsString(t, &a, "")
testArgsString(t, &a, "foobar")
testArgsString(t, &a, "foo=bar")
testArgsString(t, &a, "foo=bar&baz=sss")
testArgsString(t, &a, "")
testArgsString(t, &a, "f+o=x.x%2A-_8x%D0%BF%D1%80%D0%B8%D0%B2%D0%B5aaa&sdf=ss")
testArgsString(t, &a, "=asdfsdf")
}
func testArgsString(t *testing.T, a *Args, s string) {
a.Parse(s)
s1 := a.String()
if s != s1 {
t.Fatalf("Unexpected args %q. Expected %q", s1, s)
}
}
func TestArgsSetGetDel(t *testing.T) {
t.Parallel()
var a Args
if len(a.Peek("foo")) > 0 {
t.Fatalf("Unexpected value: %q", a.Peek("foo"))
}
if len(a.Peek("")) > 0 {
t.Fatalf("Unexpected value: %q", a.Peek(""))
}
a.Del("xxx")
for range 3 {
for i := range 10 {
k := fmt.Sprintf("foo%d", i)
v := fmt.Sprintf("bar_%d", i)
a.Set(k, v)
if string(a.Peek(k)) != v {
t.Fatalf("Unexpected value: %q. Expected %q", a.Peek(k), v)
}
}
}
for i := range 10 {
k := fmt.Sprintf("foo%d", i)
v := fmt.Sprintf("bar_%d", i)
if string(a.Peek(k)) != v {
t.Fatalf("Unexpected value: %q. Expected %q", a.Peek(k), v)
}
a.Del(k)
if len(a.Peek(k)) != 0 {
t.Fatalf("Unexpected value: %q. Expected %q", a.Peek(k), "")
}
}
a.Parse("aaa=xxx&bb=aa")
if len(a.Peek("foo0")) != 0 {
t.Fatalf("Unexpected value %q", a.Peek("foo0"))
}
if string(a.Peek("aaa")) != "xxx" {
t.Fatalf("Unexpected value %q. Expected %q", a.Peek("aaa"), "xxx")
}
if string(a.Peek("bb")) != "aa" {
t.Fatalf("Unexpected value %q. Expected %q", a.Peek("bb"), "aa")
}
for i := range 10 {
k := fmt.Sprintf("xx%d", i)
v := fmt.Sprintf("yy%d", i)
a.Set(k, v)
if string(a.Peek(k)) != v {
t.Fatalf("Unexpected value: %q. Expected %q", a.Peek(k), v)
}
}
for i := 5; i < 10; i++ {
k := fmt.Sprintf("xx%d", i)
v := fmt.Sprintf("yy%d", i)
if string(a.Peek(k)) != v {
t.Fatalf("Unexpected value: %q. Expected %q", a.Peek(k), v)
}
a.Del(k)
if len(a.Peek(k)) != 0 {
t.Fatalf("Unexpected value: %q. Expected %q", a.Peek(k), "")
}
}
}
func TestArgsParse(t *testing.T) {
t.Parallel()
var a Args
// empty args
testArgsParse(t, &a, "", 0, "foo=", "bar=", "=")
// arg without value
testArgsParse(t, &a, "foo1", 1, "foo=", "bar=", "=")
// arg without value, but with equal sign
testArgsParse(t, &a, "foo2=", 1, "foo=", "bar=", "=")
// arg with value
testArgsParse(t, &a, "foo3=bar1", 1, "foo3=bar1", "bar=", "=")
// empty key
testArgsParse(t, &a, "=bar2", 1, "foo=", "=bar2", "bar2=")
// missing kv
testArgsParse(t, &a, "&&&&", 0, "foo=", "bar=", "=")
// multiple values with the same key
testArgsParse(t, &a, "x=1&x=2&x=3", 3, "x=1")
// multiple args
testArgsParse(t, &a, "&&&qw=er&tyx=124&&&zxc_ss=2234&&", 3, "qw=er", "tyx=124", "zxc_ss=2234")
// multiple args without values
testArgsParse(t, &a, "&&a&&b&&bar&baz", 4, "a=", "b=", "bar=", "baz=")
// values with '='
testArgsParse(t, &a, "zz=1&k=v=v=a=a=s", 2, "k=v=v=a=a=s", "zz=1")
// mixed '=' and '&'
testArgsParse(t, &a, "sss&z=dsf=&df", 3, "sss=", "z=dsf=", "df=")
// encoded args
testArgsParse(t, &a, "f+o%20o=%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82+test", 1, "f o o=привет test")
// invalid percent encoding
testArgsParse(t, &a, "f%=x&qw%z=d%0k%20p&%%20=%%%20x", 3, "f%=x", "qw%z=d%0k p", "% =%% x")
// special chars
testArgsParse(t, &a, "a.b,c:d/e=f.g,h:i/q", 1, "a.b,c:d/e=f.g,h:i/q")
}
func TestArgsHas(t *testing.T) {
t.Parallel()
var a Args
// single arg
testArgsHas(t, &a, "foo", "foo")
testArgsHasNot(t, &a, "foo", "bar", "baz", "")
// multi args without values
testArgsHas(t, &a, "foo&bar", "foo", "bar")
testArgsHasNot(t, &a, "foo&bar", "", "aaaa")
// multi args
testArgsHas(t, &a, "b=xx&=aaa&c=", "b", "", "c")
testArgsHasNot(t, &a, "b=xx&=aaa&c=", "xx", "aaa", "foo")
// encoded args
testArgsHas(t, &a, "a+b=c+d%20%20e", "a b")
testArgsHasNot(t, &a, "a+b=c+d", "a+b", "c+d")
}
func testArgsHas(t *testing.T, a *Args, s string, expectedKeys ...string) {
a.Parse(s)
for _, key := range expectedKeys {
if !a.Has(key) {
t.Fatalf("Missing key %q in %q", key, s)
}
}
}
func testArgsHasNot(t *testing.T, a *Args, s string, unexpectedKeys ...string) {
a.Parse(s)
for _, key := range unexpectedKeys {
if a.Has(key) {
t.Fatalf("Unexpected key %q in %q", key, s)
}
}
}
func testArgsParse(t *testing.T, a *Args, s string, expectedLen int, expectedArgs ...string) {
a.Parse(s)
if a.Len() != expectedLen {
t.Fatalf("Unexpected args len %d. Expected %d. s=%q", a.Len(), expectedLen, s)
}
for _, xx := range expectedArgs {
tmp := strings.SplitN(xx, "=", 2)
k := tmp[0]
v := tmp[1]
buf := a.Peek(k)
if string(buf) != v {
t.Fatalf("Unexpected value for key=%q: %q. Expected %q. s=%q", k, buf, v, s)
}
}
}
func TestArgsDeleteAll(t *testing.T) {
t.Parallel()
var a Args
a.Add("q1", "foo")
a.Add("q1", "bar")
a.Add("q1", "baz")
a.Add("q1", "quux")
a.Add("q2", "1234")
a.Del("q1")
if a.Len() != 1 || a.Has("q1") {
t.Fatalf("Expected q1 arg to be completely deleted. Current Args: %q", a.String())
}
}
func TestIssue932(t *testing.T) {
t.Parallel()
var a []argsKV
a = setArg(a, "t1", "ok", argsHasValue)
a = setArg(a, "t2", "", argsHasValue)
a = setArg(a, "t1", "", argsHasValue)
a = setArgBytes(a, s2b("t3"), []byte{}, argsHasValue)
a = setArgBytes(a, s2b("t4"), nil, argsHasValue)
if peekArgStr(a, "t1") == nil {
t.Error("nil not expected for t1")
}
if peekArgStr(a, "t2") == nil {
t.Error("nil not expected for t2")
}
if peekArgStr(a, "t3") == nil {
t.Error("nil not expected for t3")
}
if peekArgStr(a, "t4") != nil {
t.Error("nil expected for t4")
}
}
================================================
FILE: args_timing_test.go
================================================
package fasthttp
import (
"bytes"
"testing"
)
func BenchmarkArgsParse(b *testing.B) {
s := []byte("foo=bar&baz=qqq&aaaaa=bbbb")
b.RunParallel(func(pb *testing.PB) {
var a Args
for pb.Next() {
a.ParseBytes(s)
}
})
}
func BenchmarkArgsPeek(b *testing.B) {
value := []byte("foobarbaz1234")
key := "foobarbaz"
b.RunParallel(func(pb *testing.PB) {
var a Args
a.SetBytesV(key, value)
for pb.Next() {
if !bytes.Equal(a.Peek(key), value) {
b.Fatalf("unexpected arg value %q. Expecting %q", a.Peek(key), value)
}
}
})
}
================================================
FILE: b2s.go
================================================
package fasthttp
import "unsafe"
// b2s converts byte slice to a string without memory allocation.
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
func b2s(b []byte) string {
return unsafe.String(unsafe.SliceData(b), len(b))
}
================================================
FILE: brotli.go
================================================
package fasthttp
import (
"bytes"
"fmt"
"io"
"sync"
"github.com/andybalholm/brotli"
"github.com/valyala/bytebufferpool"
"github.com/valyala/fasthttp/stackless"
)
// Supported compression levels.
const (
CompressBrotliNoCompression = 0
CompressBrotliBestSpeed = brotli.BestSpeed
CompressBrotliBestCompression = brotli.BestCompression
// CompressBrotliDefaultCompression chooses a default brotli compression level comparable to
// CompressDefaultCompression (gzip 6).
// See: https://github.com/valyala/fasthttp/issues/798#issuecomment-626293806
CompressBrotliDefaultCompression = 4
)
func acquireBrotliReader(r io.Reader) (*brotli.Reader, error) {
v := brotliReaderPool.Get()
if v == nil {
return brotli.NewReader(r), nil
}
zr := v.(*brotli.Reader)
if err := zr.Reset(r); err != nil {
return nil, err
}
return zr, nil
}
func releaseBrotliReader(zr *brotli.Reader) {
brotliReaderPool.Put(zr)
}
var brotliReaderPool sync.Pool
func acquireStacklessBrotliWriter(w io.Writer, level int) stackless.Writer {
nLevel := normalizeBrotliCompressLevel(level)
p := stacklessBrotliWriterPoolMap[nLevel]
v := p.Get()
if v == nil {
return stackless.NewWriter(w, func(w io.Writer) stackless.Writer {
return acquireRealBrotliWriter(w, level)
})
}
sw := v.(stackless.Writer)
sw.Reset(w)
return sw
}
func releaseStacklessBrotliWriter(sw stackless.Writer, level int) {
sw.Close()
nLevel := normalizeBrotliCompressLevel(level)
p := stacklessBrotliWriterPoolMap[nLevel]
p.Put(sw)
}
func acquireRealBrotliWriter(w io.Writer, level int) *brotli.Writer {
nLevel := normalizeBrotliCompressLevel(level)
p := realBrotliWriterPoolMap[nLevel]
v := p.Get()
if v == nil {
zw := brotli.NewWriterLevel(w, level)
return zw
}
zw := v.(*brotli.Writer)
zw.Reset(w)
return zw
}
func releaseRealBrotliWriter(zw *brotli.Writer, level int) {
zw.Close()
nLevel := normalizeBrotliCompressLevel(level)
p := realBrotliWriterPoolMap[nLevel]
p.Put(zw)
}
var (
stacklessBrotliWriterPoolMap = newCompressWriterPoolMap()
realBrotliWriterPoolMap = newCompressWriterPoolMap()
)
// AppendBrotliBytesLevel appends brotlied src to dst using the given
// compression level and returns the resulting dst.
//
// Supported compression levels are:
//
// - CompressBrotliNoCompression
// - CompressBrotliBestSpeed
// - CompressBrotliBestCompression
// - CompressBrotliDefaultCompression
func AppendBrotliBytesLevel(dst, src []byte, level int) []byte {
w := &byteSliceWriter{b: dst}
WriteBrotliLevel(w, src, level) //nolint:errcheck
return w.b
}
// WriteBrotliLevel writes brotlied p to w using the given compression level
// and returns the number of compressed bytes written to w.
//
// Supported compression levels are:
//
// - CompressBrotliNoCompression
// - CompressBrotliBestSpeed
// - CompressBrotliBestCompression
// - CompressBrotliDefaultCompression
func WriteBrotliLevel(w io.Writer, p []byte, level int) (int, error) {
switch w.(type) {
case *byteSliceWriter,
*bytes.Buffer,
*bytebufferpool.ByteBuffer:
// These writers don't block, so we can just use stacklessWriteBrotli
ctx := &compressCtx{
w: w,
p: p,
level: level,
}
stacklessWriteBrotli(ctx)
return len(p), nil
default:
zw := acquireStacklessBrotliWriter(w, level)
n, err := zw.Write(p)
releaseStacklessBrotliWriter(zw, level)
return n, err
}
}
var (
stacklessWriteBrotliOnce sync.Once
stacklessWriteBrotliFunc func(ctx any) bool
)
func stacklessWriteBrotli(ctx any) {
stacklessWriteBrotliOnce.Do(func() {
stacklessWriteBrotliFunc = stackless.NewFunc(nonblockingWriteBrotli)
})
stacklessWriteBrotliFunc(ctx)
}
func nonblockingWriteBrotli(ctxv any) {
ctx := ctxv.(*compressCtx)
zw := acquireRealBrotliWriter(ctx.w, ctx.level)
zw.Write(ctx.p) //nolint:errcheck // no way to handle this error anyway
releaseRealBrotliWriter(zw, ctx.level)
}
// WriteBrotli writes brotlied p to w and returns the number of compressed
// bytes written to w.
func WriteBrotli(w io.Writer, p []byte) (int, error) {
return WriteBrotliLevel(w, p, CompressBrotliDefaultCompression)
}
// AppendBrotliBytes appends brotlied src to dst and returns the resulting dst.
func AppendBrotliBytes(dst, src []byte) []byte {
return AppendBrotliBytesLevel(dst, src, CompressBrotliDefaultCompression)
}
// WriteUnbrotli writes unbrotlied p to w and returns the number of uncompressed
// bytes written to w.
func WriteUnbrotli(w io.Writer, p []byte) (int, error) {
return writeUnbrotli(w, p, 0)
}
func writeUnbrotli(w io.Writer, p []byte, maxBodySize int) (int, error) {
r := &byteSliceReader{b: p}
zr, err := acquireBrotliReader(r)
if err != nil {
return 0, err
}
n, err := copyZeroAllocWithLimit(w, zr, maxBodySize)
releaseBrotliReader(zr)
nn := int(n)
if int64(nn) != n {
return 0, fmt.Errorf("too much data unbrotlied: %d", n)
}
return nn, err
}
// AppendUnbrotliBytes appends unbrotlied src to dst and returns the resulting dst.
func AppendUnbrotliBytes(dst, src []byte) ([]byte, error) {
w := &byteSliceWriter{b: dst}
_, err := WriteUnbrotli(w, src)
return w.b, err
}
// normalizes compression level into [0..11], so it could be used as an index
// in *PoolMap.
func normalizeBrotliCompressLevel(level int) int {
// -2 is the lowest compression level - CompressHuffmanOnly
// 9 is the highest compression level - CompressBestCompression
if level < 0 || level > 11 {
level = CompressBrotliDefaultCompression
}
return level
}
================================================
FILE: brotli_test.go
================================================
package fasthttp
import (
"bufio"
"bytes"
"fmt"
"io"
"testing"
)
func TestBrotliBytesSerial(t *testing.T) {
t.Parallel()
if err := testBrotliBytes(); err != nil {
t.Fatal(err)
}
}
func TestBrotliBytesConcurrent(t *testing.T) {
t.Parallel()
if err := testConcurrent(10, testBrotliBytes); err != nil {
t.Fatal(err)
}
}
func testBrotliBytes() error {
for _, s := range compressTestcases {
if err := testBrotliBytesSingleCase(s); err != nil {
return err
}
}
return nil
}
func testBrotliBytesSingleCase(s string) error {
prefix := []byte("foobar")
brotlipedS := AppendBrotliBytes(prefix, []byte(s))
if !bytes.Equal(brotlipedS[:len(prefix)], prefix) {
return fmt.Errorf("unexpected prefix when compressing %q: %q. Expecting %q", s, brotlipedS[:len(prefix)], prefix)
}
unbrotliedS, err := AppendUnbrotliBytes(prefix, brotlipedS[len(prefix):])
if err != nil {
return fmt.Errorf("unexpected error when uncompressing %q: %w", s, err)
}
if !bytes.Equal(unbrotliedS[:len(prefix)], prefix) {
return fmt.Errorf("unexpected prefix when uncompressing %q: %q. Expecting %q", s, unbrotliedS[:len(prefix)], prefix)
}
unbrotliedS = unbrotliedS[len(prefix):]
if string(unbrotliedS) != s {
return fmt.Errorf("unexpected uncompressed string %q. Expecting %q", unbrotliedS, s)
}
return nil
}
func TestBrotliCompressSerial(t *testing.T) {
t.Parallel()
if err := testBrotliCompress(); err != nil {
t.Fatal(err)
}
}
func TestBrotliCompressConcurrent(t *testing.T) {
t.Parallel()
if err := testConcurrent(10, testBrotliCompress); err != nil {
t.Fatal(err)
}
}
func testBrotliCompress() error {
for _, s := range compressTestcases {
if err := testBrotliCompressSingleCase(s); err != nil {
return err
}
}
return nil
}
func testBrotliCompressSingleCase(s string) error {
var buf bytes.Buffer
zw := acquireStacklessBrotliWriter(&buf, CompressDefaultCompression)
if _, err := zw.Write([]byte(s)); err != nil {
return fmt.Errorf("unexpected error: %w. s=%q", err, s)
}
releaseStacklessBrotliWriter(zw, CompressDefaultCompression)
zr, err := acquireBrotliReader(&buf)
if err != nil {
return fmt.Errorf("unexpected error: %w. s=%q", err, s)
}
body, err := io.ReadAll(zr)
if err != nil {
return fmt.Errorf("unexpected error: %w. s=%q", err, s)
}
if string(body) != s {
return fmt.Errorf("unexpected string after decompression: %q. Expecting %q", body, s)
}
releaseBrotliReader(zr)
return nil
}
func TestCompressHandlerBrotliLevel(t *testing.T) {
t.Parallel()
expectedBody := createFixedBody(2e4)
h := CompressHandlerBrotliLevel(func(ctx *RequestCtx) {
ctx.Write(expectedBody) //nolint:errcheck
}, CompressBrotliDefaultCompression, CompressDefaultCompression)
var ctx RequestCtx
var resp Response
// verify uncompressed response
h(&ctx)
s := ctx.Response.String()
br := bufio.NewReader(bytes.NewBufferString(s))
if err := resp.Read(br); err != nil {
t.Fatalf("unexpected error: %v", err)
}
ce := resp.Header.ContentEncoding()
if len(ce) != 0 {
t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "")
}
body := resp.Body()
if !bytes.Equal(body, expectedBody) {
t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody)
}
// verify gzip-compressed response
ctx.Request.Reset()
ctx.Response.Reset()
ctx.Request.Header.Set("Accept-Encoding", "gzip, deflate, sdhc")
h(&ctx)
s = ctx.Response.String()
br = bufio.NewReader(bytes.NewBufferString(s))
if err := resp.Read(br); err != nil {
t.Fatalf("unexpected error: %v", err)
}
ce = resp.Header.ContentEncoding()
if string(ce) != "gzip" {
t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "gzip")
}
body, err := resp.BodyGunzip()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !bytes.Equal(body, expectedBody) {
t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody)
}
// verify brotli-compressed response
ctx.Request.Reset()
ctx.Response.Reset()
ctx.Request.Header.Set("Accept-Encoding", "gzip, deflate, sdhc, br")
h(&ctx)
s = ctx.Response.String()
br = bufio.NewReader(bytes.NewBufferString(s))
if err := resp.Read(br); err != nil {
t.Fatalf("unexpected error: %v", err)
}
ce = resp.Header.ContentEncoding()
if string(ce) != "br" {
t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "br")
}
body, err = resp.BodyUnbrotli()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !bytes.Equal(body, expectedBody) {
t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody)
}
}
================================================
FILE: bytesconv.go
================================================
//go:generate go run bytesconv_table_gen.go
package fasthttp
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"net"
"strconv"
"sync"
"time"
)
// AppendHTMLEscape appends html-escaped s to dst and returns the extended dst.
func AppendHTMLEscape(dst []byte, s string) []byte {
var (
prev int
sub string
)
for i, n := 0, len(s); i < n; i++ {
sub = ""
switch s[i] {
case '&':
sub = "&"
case '<':
sub = "<"
case '>':
sub = ">"
case '"':
sub = """ // """ is shorter than """.
case '\'':
sub = "'" // "'" is shorter than "'" and apos was not in HTML until HTML5.
}
if sub != "" {
dst = append(dst, s[prev:i]...)
dst = append(dst, sub...)
prev = i + 1
}
}
return append(dst, s[prev:]...)
}
// AppendHTMLEscapeBytes appends html-escaped s to dst and returns
// the extended dst.
func AppendHTMLEscapeBytes(dst, s []byte) []byte {
return AppendHTMLEscape(dst, b2s(s))
}
// AppendIPv4 appends string representation of the given ip v4 to dst
// and returns the extended dst.
func AppendIPv4(dst []byte, ip net.IP) []byte {
ip = ip.To4()
if ip == nil {
return append(dst, "non-v4 ip passed to AppendIPv4"...)
}
dst = AppendUint(dst, int(ip[0]))
for i := 1; i < 4; i++ {
dst = append(dst, '.')
dst = AppendUint(dst, int(ip[i]))
}
return dst
}
var errEmptyIPStr = errors.New("empty ip address string")
// ParseIPv4 parses ip address from ipStr into dst and returns the extended dst.
func ParseIPv4(dst net.IP, ipStr []byte) (net.IP, error) {
if len(ipStr) == 0 {
return dst, errEmptyIPStr
}
if len(dst) < net.IPv4len || len(dst) > net.IPv4len {
dst = make([]byte, net.IPv4len)
}
copy(dst, net.IPv4zero)
dst = dst.To4() // dst is always non-nil here
b := ipStr
for i := range 3 {
n := bytes.IndexByte(b, '.')
if n < 0 {
return dst, fmt.Errorf("cannot find dot in ipStr %q", ipStr)
}
octet, parsed, err := parseIPv4Octet(b[:n])
if err != nil {
if errors.Is(err, errIPv4PartTooLarge) {
return dst, fmt.Errorf("cannot parse ipStr %q: ip part cannot exceed 255: parsed %d", ipStr, parsed)
}
return dst, fmt.Errorf("cannot parse ipStr %q: %w", ipStr, err)
}
dst[i] = octet
b = b[n+1:]
}
octet, parsed, err := parseIPv4Octet(b)
if err != nil {
if errors.Is(err, errIPv4PartTooLarge) {
return dst, fmt.Errorf("cannot parse ipStr %q: ip part cannot exceed 255: parsed %d", ipStr, parsed)
}
return dst, fmt.Errorf("cannot parse ipStr %q: %w", ipStr, err)
}
dst[3] = octet
return dst, nil
}
// AppendHTTPDate appends HTTP-compliant (RFC1123) representation of date
// to dst and returns the extended dst.
func AppendHTTPDate(dst []byte, date time.Time) []byte {
dst = date.In(time.UTC).AppendFormat(dst, time.RFC1123)
copy(dst[len(dst)-3:], strGMT)
return dst
}
// ParseHTTPDate parses HTTP-compliant (RFC1123) date.
func ParseHTTPDate(date []byte) (time.Time, error) {
return time.Parse(time.RFC1123, b2s(date))
}
// AppendUint appends n to dst and returns the extended dst.
func AppendUint(dst []byte, n int) []byte {
if n < 0 {
// developer sanity-check
panic("BUG: int must be positive")
}
return strconv.AppendUint(dst, uint64(n), 10)
}
// ParseUint parses uint from buf.
func ParseUint(buf []byte) (int, error) {
v, n, err := parseUintBuf(buf)
if n != len(buf) {
return -1, errUnexpectedTrailingChar
}
return v, err
}
var (
errEmptyInt = errors.New("empty integer")
errIPv4PartTooLarge = errors.New("ip part cannot exceed 255")
errUnexpectedFirstChar = errors.New("unexpected first char found. Expecting 0-9")
errUnexpectedTrailingChar = errors.New("unexpected trailing char found. Expecting 0-9")
errTooLongInt = errors.New("too long int")
)
func parseUintBuf(b []byte) (int, int, error) {
n := len(b)
if n == 0 {
return -1, 0, errEmptyInt
}
v := 0
for i := range n {
c := b[i]
k := c - '0'
if k > 9 {
if i == 0 {
return -1, i, errUnexpectedFirstChar
}
return v, i, nil
}
vNew := 10*v + int(k)
// Test for overflow.
if vNew < v {
return -1, i, errTooLongInt
}
v = vNew
}
return v, n, nil
}
func parseIPv4Octet(b []byte) (byte, int, error) {
if len(b) == 0 {
return 0, 0, errEmptyInt
}
var (
octet byte
parsed int
)
for i := range len(b) {
c := b[i]
k := c - '0'
if k > 9 {
if i == 0 {
return 0, parsed, errUnexpectedFirstChar
}
return 0, parsed, errUnexpectedTrailingChar
}
parsed = parsed*10 + int(k)
if octet > 25 || (octet == 25 && k > 5) {
return 0, parsed, errIPv4PartTooLarge
}
octet = octet*10 + k
}
return octet, parsed, nil
}
// ParseUfloat parses unsigned float from buf.
func ParseUfloat(buf []byte) (float64, error) {
// The implementation of parsing a float string is not easy.
// We believe that the conservative approach is to call strconv.ParseFloat.
// https://github.com/valyala/fasthttp/pull/1865
res, err := strconv.ParseFloat(b2s(buf), 64)
if res < 0 {
return -1, errors.New("negative input is invalid")
}
if err != nil {
return -1, err
}
return res, err
}
var (
errEmptyHexNum = errors.New("empty hex number")
errTooLargeHexNum = errors.New("too large hex number")
)
func readHexInt(r *bufio.Reader) (int, error) {
var k, i, n int
for {
c, err := r.ReadByte()
if err != nil {
if err == io.EOF && i > 0 {
return n, nil
}
return -1, err
}
k = int(hex2intTable[c])
if k == 16 {
if i == 0 {
return -1, errEmptyHexNum
}
if err := r.UnreadByte(); err != nil {
return -1, err
}
return n, nil
}
if i >= maxHexIntChars {
return -1, errTooLargeHexNum
}
n = (n << 4) | k
i++
}
}
var hexIntBufPool sync.Pool
func writeHexInt(w *bufio.Writer, n int) error {
if n < 0 {
// developer sanity-check
panic("BUG: int must be positive")
}
v := hexIntBufPool.Get()
if v == nil {
v = make([]byte, maxHexIntChars+1)
}
buf := v.([]byte)
i := len(buf) - 1
for {
buf[i] = lowerhex[n&0xf]
n >>= 4
if n == 0 {
break
}
i--
}
_, err := w.Write(buf[i:])
hexIntBufPool.Put(v)
return err
}
const (
upperhex = "0123456789ABCDEF"
lowerhex = "0123456789abcdef"
)
func lowercaseBytes(b []byte) {
for i := range b {
p := &b[i]
*p = toLowerTable[*p]
}
}
// AppendUnquotedArg appends url-decoded src to dst and returns appended dst.
//
// dst may point to src. In this case src will be overwritten.
func AppendUnquotedArg(dst, src []byte) []byte {
return decodeArgAppend(dst, src)
}
// AppendQuotedArg appends url-encoded src to dst and returns appended dst.
func AppendQuotedArg(dst, src []byte) []byte {
for _, c := range src {
switch {
case c == ' ':
dst = append(dst, '+')
case quotedArgShouldEscapeTable[int(c)] != 0:
dst = append(dst, '%', upperhex[c>>4], upperhex[c&0xf])
default:
dst = append(dst, c)
}
}
return dst
}
func appendQuotedPath(dst, src []byte) []byte {
// Fix issue in https://github.com/golang/go/issues/11202
if len(src) == 1 && src[0] == '*' {
return append(dst, '*')
}
for _, c := range src {
if quotedPathShouldEscapeTable[int(c)] != 0 {
dst = append(dst, '%', upperhex[c>>4], upperhex[c&0xf])
} else {
dst = append(dst, c)
}
}
return dst
}
================================================
FILE: bytesconv_32.go
================================================
//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x
package fasthttp
const (
maxHexIntChars = 7
)
================================================
FILE: bytesconv_32_test.go
================================================
//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x
package fasthttp
import (
"testing"
)
func TestWriteHexInt(t *testing.T) {
t.Parallel()
testWriteHexInt(t, 0, "0")
testWriteHexInt(t, 1, "1")
testWriteHexInt(t, 0x123, "123")
testWriteHexInt(t, 0x7fffffff, "7fffffff")
}
func TestAppendUint(t *testing.T) {
t.Parallel()
testAppendUint(t, 0)
testAppendUint(t, 123)
testAppendUint(t, 0x7fffffff)
for i := 0; i < 2345; i++ {
testAppendUint(t, i)
}
}
func TestReadHexIntSuccess(t *testing.T) {
t.Parallel()
testReadHexIntSuccess(t, "0", 0)
testReadHexIntSuccess(t, "fF", 0xff)
testReadHexIntSuccess(t, "00abc", 0xabc)
testReadHexIntSuccess(t, "7ffffff", 0x7ffffff)
testReadHexIntSuccess(t, "000", 0)
testReadHexIntSuccess(t, "1234ZZZ", 0x1234)
}
func TestParseUintError32(t *testing.T) {
t.Parallel()
// Overflow by last digit: 2 ** 32 / 2 * 10 ** n
testParseUintError(t, "2147483648")
testParseUintError(t, "21474836480")
testParseUintError(t, "214748364800")
}
func TestParseUintSuccess(t *testing.T) {
t.Parallel()
testParseUintSuccess(t, "0", 0)
testParseUintSuccess(t, "123", 123)
testParseUintSuccess(t, "123456789", 123456789)
// Max supported value: 2 ** 32 / 2 - 1
testParseUintSuccess(t, "2147483647", 2147483647)
}
================================================
FILE: bytesconv_64.go
================================================
//go:build amd64 || arm64 || ppc64 || ppc64le || riscv64 || s390x
package fasthttp
const (
maxHexIntChars = 15
)
================================================
FILE: bytesconv_64_test.go
================================================
//go:build amd64 || arm64 || ppc64 || ppc64le || riscv64 || s390x
package fasthttp
import (
"testing"
)
func TestWriteHexInt(t *testing.T) {
t.Parallel()
testWriteHexInt(t, 0, "0")
testWriteHexInt(t, 1, "1")
testWriteHexInt(t, 0x123, "123")
testWriteHexInt(t, 0x7fffffffffffffff, "7fffffffffffffff")
}
func TestAppendUint(t *testing.T) {
t.Parallel()
testAppendUint(t, 0)
testAppendUint(t, 123)
testAppendUint(t, 0x7fffffffffffffff)
for i := range 2345 {
testAppendUint(t, i)
}
}
func TestReadHexIntSuccess(t *testing.T) {
t.Parallel()
testReadHexIntSuccess(t, "0", 0)
testReadHexIntSuccess(t, "fF", 0xff)
testReadHexIntSuccess(t, "00abc", 0xabc)
testReadHexIntSuccess(t, "7fffffff", 0x7fffffff)
testReadHexIntSuccess(t, "000", 0)
testReadHexIntSuccess(t, "1234ZZZ", 0x1234)
testReadHexIntSuccess(t, "7ffffffffffffff", 0x7ffffffffffffff)
}
func TestParseUintError64(t *testing.T) {
t.Parallel()
// Overflow by last digit: 2 ** 64 / 2 * 10 ** n
testParseUintError(t, "9223372036854775808")
testParseUintError(t, "92233720368547758080")
testParseUintError(t, "922337203685477580800")
}
func TestParseUintSuccess(t *testing.T) {
t.Parallel()
testParseUintSuccess(t, "0", 0)
testParseUintSuccess(t, "123", 123)
testParseUintSuccess(t, "1234567890", 1234567890)
testParseUintSuccess(t, "123456789012345678", 123456789012345678)
// Max supported value: 2 ** 64 / 2 - 1
testParseUintSuccess(t, "9223372036854775807", 9223372036854775807)
}
================================================
FILE: bytesconv_table.go
================================================
package fasthttp
// Code generated by go run bytesconv_table_gen.go; DO NOT EDIT.
// See bytesconv_table_gen.go for more information about these tables.
const hex2intTable = "\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x00\x01\x02\x03\x04\x05\x06\a\b\t\x10\x10\x10\x10\x10\x10\x10\n\v\f\r\x0e\x0f\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\n\v\f\r\x0e\x0f\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10"
const toLowerTable = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
const toUpperTable = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
const quotedArgShouldEscapeTable = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
const quotedPathShouldEscapeTable = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x01\x00\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
const validHeaderFieldByteTable = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x01\x01\x01\x01\x00\x00\x01\x01\x00\x01\x01\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x01\x00\x01\x00"
const validHeaderValueByteTable = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
const validMethodValueByteTable = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x01\x01\x01\x01\x00\x00\x01\x01\x00\x01\x01\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
================================================
FILE: bytesconv_table_gen.go
================================================
//go:build ignore
package main
import (
"bytes"
"fmt"
"log"
"os"
)
const (
toLower = 'a' - 'A'
)
func main() {
hex2intTable := func() [256]byte {
var b [256]byte
for i := 0; i < 256; i++ {
c := byte(16)
if i >= '0' && i <= '9' {
c = byte(i) - '0'
} else if i >= 'a' && i <= 'f' {
c = byte(i) - 'a' + 10
} else if i >= 'A' && i <= 'F' {
c = byte(i) - 'A' + 10
}
b[i] = c
}
return b
}()
toLowerTable := func() [256]byte {
var a [256]byte
for i := 0; i < 256; i++ {
c := byte(i)
if c >= 'A' && c <= 'Z' {
c += toLower
}
a[i] = c
}
return a
}()
toUpperTable := func() [256]byte {
var a [256]byte
for i := 0; i < 256; i++ {
c := byte(i)
if c >= 'a' && c <= 'z' {
c -= toLower
}
a[i] = c
}
return a
}()
quotedArgShouldEscapeTable := func() [256]byte {
// According to RFC 3986 §2.3
var a [256]byte
for i := 0; i < 256; i++ {
a[i] = 1
}
// ALPHA
for i := int('a'); i <= int('z'); i++ {
a[i] = 0
}
for i := int('A'); i <= int('Z'); i++ {
a[i] = 0
}
// DIGIT
for i := int('0'); i <= int('9'); i++ {
a[i] = 0
}
// Unreserved characters
for _, v := range `-_.~` {
a[v] = 0
}
return a
}()
quotedPathShouldEscapeTable := func() [256]byte {
// The implementation here equal to net/url shouldEscape(s, encodePath)
//
// The RFC allows : @ & = + $ but saves / ; , for assigning
// meaning to individual path segments. This package
// only manipulates the path as a whole, so we allow those
// last three as well. That leaves only ? to escape.
a := quotedArgShouldEscapeTable
for _, v := range `$&+,/:;=@` {
a[v] = 0
}
return a
}()
validHeaderFieldByteTable := func() [128]byte {
// Should match net/textproto's validHeaderFieldByte(c byte) bool
// Defined by RFC 7230 and 9110:
//
// header-field = field-name ":" OWS field-value OWS
// field-name = token
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
// token = 1*tchar
var table [128]byte
for c := 0; c < 128; c++ {
if (c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
c == '!' || c == '#' || c == '$' || c == '%' || c == '&' ||
c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' ||
c == '^' || c == '_' || c == '`' || c == '|' || c == '~' {
table[c] = 1
}
}
return table
}()
validHeaderValueByteTable := func() [256]byte {
// Should match net/textproto's validHeaderValueByte(c byte) bool
// Defined by RFC 7230 and 9110:
//
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
// field-vchar = VCHAR / obs-text
// obs-text = %x80-FF
//
// RFC 5234:
//
// HTAB = %x09
// SP = %x20
// VCHAR = %x21-7E
var table [256]byte
for c := 0; c < 256; c++ {
if (c >= 0x21 && c <= 0x7E) || // VCHAR
c == 0x20 || // SP
c == 0x09 || // HTAB
c >= 0x80 { // obs-text
table[c] = 1
}
}
return table
}()
validMethodValueByteTable := [256]byte{
/*
Same as net/http
Method = "OPTIONS" ; Section 9.2
| "GET" ; Section 9.3
| "HEAD" ; Section 9.4
| "POST" ; Section 9.5
| "PUT" ; Section 9.6
| "DELETE" ; Section 9.7
| "TRACE" ; Section 9.8
| "CONNECT" ; Section 9.9
| extension-method
extension-method = token
token = 1*<any CHAR except CTLs or separators>
*/
'!': 1,
'#': 1,
'$': 1,
'%': 1,
'&': 1,
'\'': 1,
'*': 1,
'+': 1,
'-': 1,
'.': 1,
'0': 1,
'1': 1,
'2': 1,
'3': 1,
'4': 1,
'5': 1,
'6': 1,
'7': 1,
'8': 1,
'9': 1,
'A': 1,
'B': 1,
'C': 1,
'D': 1,
'E': 1,
'F': 1,
'G': 1,
'H': 1,
'I': 1,
'J': 1,
'K': 1,
'L': 1,
'M': 1,
'N': 1,
'O': 1,
'P': 1,
'Q': 1,
'R': 1,
'S': 1,
'T': 1,
'U': 1,
'W': 1,
'V': 1,
'X': 1,
'Y': 1,
'Z': 1,
'^': 1,
'_': 1,
'`': 1,
'a': 1,
'b': 1,
'c': 1,
'd': 1,
'e': 1,
'f': 1,
'g': 1,
'h': 1,
'i': 1,
'j': 1,
'k': 1,
'l': 1,
'm': 1,
'n': 1,
'o': 1,
'p': 1,
'q': 1,
'r': 1,
's': 1,
't': 1,
'u': 1,
'v': 1,
'w': 1,
'x': 1,
'y': 1,
'z': 1,
'|': 1,
'~': 1,
}
w := bytes.NewBufferString(pre)
fmt.Fprintf(w, "const hex2intTable = %q\n", hex2intTable)
fmt.Fprintf(w, "const toLowerTable = %q\n", toLowerTable)
fmt.Fprintf(w, "const toUpperTable = %q\n", toUpperTable)
fmt.Fprintf(w, "const quotedArgShouldEscapeTable = %q\n", quotedArgShouldEscapeTable)
fmt.Fprintf(w, "const quotedPathShouldEscapeTable = %q\n", quotedPathShouldEscapeTable)
fmt.Fprintf(w, "const validHeaderFieldByteTable = %q\n", validHeaderFieldByteTable)
fmt.Fprintf(w, "const validHeaderValueByteTable = %q\n", validHeaderValueByteTable)
fmt.Fprintf(w, "const validMethodValueByteTable = %q\n", validMethodValueByteTable)
if err := os.WriteFile("bytesconv_table.go", w.Bytes(), 0o660); err != nil {
log.Fatal(err)
}
}
const pre = `package fasthttp
// Code generated by go run bytesconv_table_gen.go; DO NOT EDIT.
// See bytesconv_table_gen.go for more information about these tables.
`
================================================
FILE: bytesconv_test.go
================================================
package fasthttp
import (
"bufio"
"bytes"
"html"
"net"
"net/url"
"strconv"
"testing"
"time"
"github.com/valyala/bytebufferpool"
)
func TestAppendQuotedArg(t *testing.T) {
t.Parallel()
// Sync with url.QueryEscape
allcases := make([]byte, 256)
for i := range 256 {
allcases[i] = byte(i)
}
res := string(AppendQuotedArg(nil, allcases))
expect := url.QueryEscape(string(allcases))
if res != expect {
t.Fatalf("unexpected string %q. Expecting %q.", res, expect)
}
}
func TestAppendHTMLEscape(t *testing.T) {
t.Parallel()
// Sync with html.EscapeString
allcases := make([]byte, 256)
for i := range 256 {
allcases[i] = byte(i)
}
res := string(AppendHTMLEscape(nil, string(allcases)))
expect := html.EscapeString(string(allcases))
if res != expect {
t.Fatalf("unexpected string %q. Expecting %q.", res, expect)
}
testAppendHTMLEscape(t, "", "")
testAppendHTMLEscape(t, "<", "<")
testAppendHTMLEscape(t, "a", "a")
testAppendHTMLEscape(t, `><"''`, "><"''")
testAppendHTMLEscape(t, "fo<b x='ss'>a</b>xxx", "fo<b x='ss'>a</b>xxx")
}
func testAppendHTMLEscape(t *testing.T, s, expectedS string) {
buf := AppendHTMLEscapeBytes(nil, []byte(s))
if string(buf) != expectedS {
t.Fatalf("unexpected html-escaped string %q. Expecting %q. Original string %q", buf, expectedS, s)
}
}
func TestParseIPv4(t *testing.T) {
t.Parallel()
testParseIPv4(t, net.IP{0}, "0.0.0.0", true)
testParseIPv4(t, nil, "0.0.0.0", true)
testParseIPv4(t, net.IP{0, 0, 0, 0, 0}, "0.0.0.0", true)
testParseIPv4(t, nil, "255.255.255.255", true)
testParseIPv4(t, nil, "123.45.67.89", true)
// ipv6 shouldn't work
testParseIPv4(t, nil, "2001:4860:0:2001::68", false)
// invalid ip
testParseIPv4(t, nil, "", false)
testParseIPv4(t, nil, "foobar", false)
testParseIPv4(t, nil, "1.2.3", false)
testParseIPv4(t, nil, "123.456.789.11", false)
testParseIPv4(t, nil, "b.1.2.3", false)
testParseIPv4(t, nil, "1.2.3.b", false)
testParseIPv4(t, nil, "1.2.3.456", false)
}
func testParseIPv4(t *testing.T, dst net.IP, ipStr string, isValid bool) {
ip, err := ParseIPv4(dst, []byte(ipStr))
if isValid {
if err != nil {
t.Fatalf("unexpected error when parsing ip %q: %v", ipStr, err)
}
s := string(AppendIPv4(nil, ip))
if s != ipStr {
t.Fatalf("unexpected ip parsed %q. Expecting %q", s, ipStr)
}
} else if err == nil {
t.Fatalf("expecting error when parsing ip %q", ipStr)
}
}
func TestAppendIPv4(t *testing.T) {
t.Parallel()
testAppendIPv4(t, "0.0.0.0", true)
testAppendIPv4(t, "127.0.0.1", true)
testAppendIPv4(t, "8.8.8.8", true)
testAppendIPv4(t, "123.45.67.89", true)
// ipv6 shouldn't work
testAppendIPv4(t, "2001:4860:0:2001::68", false)
}
func testAppendIPv4(t *testing.T, ipStr string, isValid bool) {
ip := net.ParseIP(ipStr)
if ip == nil {
t.Fatalf("cannot parse ip %q", ipStr)
}
s := string(AppendIPv4(nil, ip))
if isValid {
if s != ipStr {
t.Fatalf("unexpected ip %q. Expecting %q", s, ipStr)
}
} else {
ipStr = "non-v4 ip passed to AppendIPv4"
if s != ipStr {
t.Fatalf("unexpected ip %q. Expecting %q", s, ipStr)
}
}
}
func testAppendUint(t *testing.T, n int) {
expectedS := strconv.Itoa(n)
s := AppendUint(nil, n)
if string(s) != expectedS {
t.Fatalf("unexpected uint %q. Expecting %q. n=%d", s, expectedS, n)
}
}
func testWriteHexInt(t *testing.T, n int, expectedS string) {
var w bytebufferpool.ByteBuffer
bw := bufio.NewWriter(&w)
if err := writeHexInt(bw, n); err != nil {
t.Fatalf("unexpected error when writing hex %x: %v", n, err)
}
if err := bw.Flush(); err != nil {
t.Fatalf("unexpected error when flushing hex %x: %v", n, err)
}
s := string(w.B)
if s != expectedS {
t.Fatalf("unexpected hex after writing %q. Expected %q", s, expectedS)
}
}
func TestReadHexIntError(t *testing.T) {
t.Parallel()
testReadHexIntError(t, "")
testReadHexIntError(t, "ZZZ")
testReadHexIntError(t, "-123")
testReadHexIntError(t, "+434")
}
func testReadHexIntError(t *testing.T, s string) {
r := bytes.NewBufferString(s)
br := bufio.NewReader(r)
n, err := readHexInt(br)
if err == nil {
t.Fatalf("expecting error when reading hex int %q", s)
}
if n >= 0 {
t.Fatalf("unexpected hex value read %d for hex int %q. must be negative", n, s)
}
}
func testReadHexIntSuccess(t *testing.T, s string, expectedN int) {
r := bytes.NewBufferString(s)
br := bufio.NewReader(r)
n, err := readHexInt(br)
if err != nil {
t.Fatalf("unexpected error: %v. s=%q", err, s)
}
if n != expectedN {
t.Fatalf("unexpected hex int %d. Expected %d. s=%q", n, expectedN, s)
}
}
func TestAppendHTTPDate(t *testing.T) {
t.Parallel()
d := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
s := string(AppendHTTPDate(nil, d))
expectedS := "Tue, 10 Nov 2009 23:00:00 GMT"
if s != expectedS {
t.Fatalf("unexpected date %q. Expecting %q", s, expectedS)
}
b := []byte("prefix")
s = string(AppendHTTPDate(b, d))
if s[:len(b)] != string(b) {
t.Fatalf("unexpected prefix %q. Expecting %q", s[:len(b)], b)
}
s = s[len(b):]
if s != expectedS {
t.Fatalf("unexpected date %q. Expecting %q", s, expectedS)
}
}
func TestParseUintError(t *testing.T) {
t.Parallel()
// empty string
testParseUintError(t, "")
// negative value
testParseUintError(t, "-123")
// non-num
testParseUintError(t, "foobar234")
// non-num chars at the end
testParseUintError(t, "123w")
// floating point num
testParseUintError(t, "1234.545")
// too big num
testParseUintError(t, "12345678901234567890")
testParseUintError(t, "1234567890123456789012")
}
func TestParseUfloatSuccess(t *testing.T) {
t.Parallel()
testParseUfloatSuccess(t, "0", 0)
testParseUfloatSuccess(t, "1.", 1.)
testParseUfloatSuccess(t, ".1", 0.1)
testParseUfloatSuccess(t, "123.456", 123.456)
testParseUfloatSuccess(t, "123", 123)
testParseUfloatSuccess(t, "1234e2", 1234e2)
testParseUfloatSuccess(t, "1234E-5", 1234e-5)
testParseUfloatSuccess(t, "1.234e+3", 1.234e+3)
testParseUfloatSuccess(t, "1234e23", 1234e23)
testParseUfloatSuccess(t, "1.234e+32", 1.234e+32)
testParseUfloatSuccess(t, "123456789123456789.987654321", 123456789123456789.987654321)
testParseUfloatSuccess(t, "1.23456789123456789987654321", 1.23456789123456789987654321)
testParseUfloatSuccess(t, "340282346638528859811704183484516925440", 340282346638528859811704183484516925440)
testParseUfloatSuccess(t, "00000000000000000001", 1)
}
func TestParseUfloatError(t *testing.T) {
t.Parallel()
// empty num
testParseUfloatError(t, "")
// negative num
testParseUfloatError(t, "-123.53")
// non-num chars
testParseUfloatError(t, "123sdfsd")
testParseUfloatError(t, "sdsf234")
testParseUfloatError(t, "sdfdf")
// non-num chars in exponent
testParseUfloatError(t, "123e3s")
testParseUfloatError(t, "12.3e-op")
testParseUfloatError(t, "123E+SS5")
// duplicate point
testParseUfloatError(t, "1.3.4")
// duplicate exponent
testParseUfloatError(t, "123e5e6")
// missing exponent
testParseUfloatError(t, "123534e")
// negative number
testParseUfloatError(t, "-1")
testParseUfloatError(t, "-Inf")
}
func testParseUfloatError(t *testing.T, s string) {
n, err := ParseUfloat([]byte(s))
if err == nil {
t.Fatalf("Expecting error when parsing %q. obtained %f", s, n)
}
if n >= 0 {
t.Fatalf("Expecting negative num instead of %f when parsing %q", n, s)
}
}
func testParseUfloatSuccess(t *testing.T, s string, expectedF float64) {
f, err := ParseUfloat([]byte(s))
if err != nil {
t.Fatalf("Unexpected error when parsing %q: %v", s, err)
}
delta := f - expectedF
if delta < 0 {
delta = -delta
}
if delta > expectedF*1e-10 {
t.Fatalf("Unexpected value when parsing %q: %f. Expected %f", s, f, expectedF)
}
}
func testParseUintError(t *testing.T, s string) {
n, err := ParseUint([]byte(s))
if err == nil {
t.Fatalf("Expecting error when parsing %q. obtained %d", s, n)
}
if n >= 0 {
t.Fatalf("Unexpected n=%d when parsing %q. Expected negative num", n, s)
}
}
func testParseUintSuccess(t *testing.T, s string, expectedN int) {
n, err := ParseUint([]byte(s))
if err != nil {
t.Fatalf("Unexpected error when parsing %q: %v", s, err)
}
if n != expectedN {
t.Fatalf("Unexpected value %d. Expected %d. num=%q", n, expectedN, s)
}
}
func TestAppendUnquotedArg(t *testing.T) {
t.Parallel()
testAppendUnquotedArg(t, "", "")
testAppendUnquotedArg(t, "abc", "abc")
testAppendUnquotedArg(t, "тест.abc", "тест.abc")
testAppendUnquotedArg(t, "%D1%82%D0%B5%D1%81%D1%82%20%=&;:", "тест %=&;:")
}
func testAppendUnquotedArg(t *testing.T, s, expectedS string) {
// test appending to nil
result := AppendUnquotedArg(nil, []byte(s))
if string(result) != expectedS {
t.Fatalf("Unexpected AppendUnquotedArg(%q)=%q, want %q", s, result, expectedS)
}
// test appending to prefix
prefix := "prefix"
dst := []byte(prefix)
dst = AppendUnquotedArg(dst, []byte(s))
if !bytes.HasPrefix(dst, []byte(prefix)) {
t.Fatalf("Unexpected prefix for AppendUnquotedArg(%q)=%q, want %q", s, dst, prefix)
}
result = dst[len(prefix):]
if string(result) != expectedS {
t.Fatalf("Unexpected AppendUnquotedArg(%q)=%q, want %q", s, result, expectedS)
}
// test in-place appending
result = []byte(s)
result = AppendUnquotedArg(result[:0], result)
if string(result) != expectedS {
t.Fatalf("Unexpected AppendUnquotedArg(%q)=%q, want %q", s, result, expectedS)
}
// verify AppendQuotedArg <-> AppendUnquotedArg conversion
quotedS := AppendQuotedArg(nil, []byte(s))
unquotedS := AppendUnquotedArg(nil, quotedS)
if s != string(unquotedS) {
t.Fatalf("Unexpected AppendUnquotedArg(AppendQuotedArg(%q))=%q, want %q", s, unquotedS, s)
}
}
================================================
FILE: bytesconv_timing_test.go
================================================
package fasthttp
import (
"bufio"
"html"
"net"
"testing"
"github.com/valyala/bytebufferpool"
)
func BenchmarkAppendHTMLEscape(b *testing.B) {
sOrig := "<b>foobarbazxxxyyyzzz</b>"
sExpected := string(AppendHTMLEscape(nil, sOrig))
b.RunParallel(func(pb *testing.PB) {
var buf []byte
for pb.Next() {
for range 10 {
buf = AppendHTMLEscape(buf[:0], sOrig)
if string(buf) != sExpected {
b.Fatalf("unexpected escaped string: %q. Expecting %q", buf, sExpected)
}
}
}
})
}
func BenchmarkHTMLEscapeString(b *testing.B) {
sOrig := "<b>foobarbazxxxyyyzzz</b>"
sExpected := html.EscapeString(sOrig)
b.RunParallel(func(pb *testing.PB) {
var s string
for pb.Next() {
for range 10 {
s = html.EscapeString(sOrig)
if s != sExpected {
b.Fatalf("unexpected escaped string: %q. Expecting %q", s, sExpected)
}
}
}
})
}
func BenchmarkParseIPv4(b *testing.B) {
ipStr := []byte("123.145.167.189")
b.RunParallel(func(pb *testing.PB) {
var ip net.IP
var err error
for pb.Next() {
ip, err = ParseIPv4(ip, ipStr)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
}
})
}
func BenchmarkAppendIPv4(b *testing.B) {
ip := net.ParseIP("123.145.167.189")
b.RunParallel(func(pb *testing.PB) {
var buf []byte
for pb.Next() {
buf = AppendIPv4(buf[:0], ip)
}
})
}
func BenchmarkWriteHexInt(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var w bytebufferpool.ByteBuffer
bw := bufio.NewWriter(&w)
i := 0
for pb.Next() {
writeHexInt(bw, i) //nolint:errcheck
i++
if i > 0x7fffffff {
i = 0
}
w.Reset()
bw.Reset(&w)
}
})
}
func BenchmarkParseUint(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
buf := []byte("1234567")
for pb.Next() {
n, err := ParseUint(buf)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
if n != 1234567 {
b.Fatalf("unexpected result: %d. Expecting %q", n, buf)
}
}
})
}
func BenchmarkAppendUint(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var buf []byte
i := 0
for pb.Next() {
buf = AppendUint(buf[:0], i)
i++
if i > 0x7fffffff {
i = 0
}
}
})
}
func BenchmarkLowercaseBytesNoop(b *testing.B) {
src := []byte("foobarbaz_lowercased_all")
b.RunParallel(func(pb *testing.PB) {
s := make([]byte, len(src))
for pb.Next() {
copy(s, src)
lowercaseBytes(s)
}
})
}
func BenchmarkLowercaseBytesAll(b *testing.B) {
src := []byte("FOOBARBAZ_UPPERCASED_ALL")
b.RunParallel(func(pb *testing.PB) {
s := make([]byte, len(src))
for pb.Next() {
copy(s, src)
lowercaseBytes(s)
}
})
}
func BenchmarkLowercaseBytesMixed(b *testing.B) {
src := []byte("Foobarbaz_Uppercased_Mix")
b.RunParallel(func(pb *testing.PB) {
s := make([]byte, len(src))
for pb.Next() {
copy(s, src)
lowercaseBytes(s)
}
})
}
func BenchmarkAppendUnquotedArgFastPath(b *testing.B) {
src := []byte("foobarbaz no quoted chars fdskjsdf jklsdfdfskljd;aflskjdsaf fdsklj fsdkj fsdl kfjsdlk jfsdklj fsdfsdf sdfkflsd")
b.RunParallel(func(pb *testing.PB) {
var dst []byte
for pb.Next() {
dst = AppendUnquotedArg(dst[:0], src)
}
})
}
func BenchmarkAppendUnquotedArgSlowPath(b *testing.B) {
src := []byte("D0%B4%20%D0%B0%D0%B2%D0%BB%D0%B4%D1%84%D1%8B%D0%B0%D0%BE%20%D1%84%D0%B2%D0%B6%D0%BB%D0%B4%D1%8B%20%D0%B0%D0%BE")
b.RunParallel(func(pb *testing.PB) {
var dst []byte
for pb.Next() {
dst = AppendUnquotedArg(dst[:0], src)
}
})
}
func BenchmarkParseUfloat(b *testing.B) {
src := [][]byte{
[]byte("0"),
[]byte("1234566789."),
[]byte(".1234556778"),
[]byte("123.456"),
[]byte("123456789"),
[]byte("1234e23"),
[]byte("1234E-51"),
[]byte("1.234e+32"),
[]byte("123456789123456789.987654321"),
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
for i := range src {
_, err := ParseUfloat(src[i])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
}
}
})
}
================================================
FILE: client.go
================================================
package fasthttp
import (
"bufio"
"bytes"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"strings"
"sync"
"sync/atomic"
"time"
)
// Do performs the given http request and fills the given http response.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func Do(req *Request, resp *Response) error {
return defaultClient.Do(req, resp)
}
// DoTimeout performs the given request and waits for response during
// the given timeout duration.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned during
// the given timeout.
//
// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
return defaultClient.DoTimeout(req, resp, timeout)
}
// DoDeadline performs the given request and waits for response until
// the given deadline.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned until
// the given deadline.
//
// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func DoDeadline(req *Request, resp *Response, deadline time.Time) error {
return defaultClient.DoDeadline(req, resp, deadline)
}
// DoRedirects performs the given http request and fills the given http response,
// following up to maxRedirectsCount redirects. When the redirect count exceeds
// maxRedirectsCount, ErrTooManyRedirects is returned.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// Response is ignored if resp is nil.
//
// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func DoRedirects(req *Request, resp *Response, maxRedirectsCount int) error {
if defaultClient.DisablePathNormalizing {
req.URI().DisablePathNormalizing = true
}
_, _, err := doRequestFollowRedirects(req, resp, req.URI().String(), maxRedirectsCount, &defaultClient)
return err
}
// Get returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
func Get(dst []byte, url string) (statusCode int, body []byte, err error) {
return defaultClient.Get(dst, url)
}
// GetTimeout returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// ErrTimeout error is returned if url contents couldn't be fetched
// during the given timeout.
func GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
return defaultClient.GetTimeout(dst, url, timeout)
}
// GetDeadline returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// ErrTimeout error is returned if url contents couldn't be fetched
// until the given deadline.
func GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
return defaultClient.GetDeadline(dst, url, deadline)
}
// Post sends POST request to the given url with the given POST arguments.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// Empty POST body is sent if postArgs is nil.
func Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) {
return defaultClient.Post(dst, url, postArgs)
}
var defaultClient Client
// Client implements http client.
//
// Copying Client by value is prohibited. Create new instance instead.
//
// It is safe calling Client methods from concurrently running goroutines.
//
// The fields of a Client should not be changed while it is in use.
type Client struct {
noCopy noCopy
readerPool sync.Pool
writerPool sync.Pool
// Transport defines a transport-like mechanism that wraps every request/response.
Transport RoundTripper
// Callback for establishing new connections to hosts.
//
// Default DialTimeout is used if not set.
DialTimeout DialFuncWithTimeout
// Callback for establishing new connections to hosts.
//
// Note that if Dial is set instead of DialTimeout, Dial will ignore Request timeout.
// If you want the tcp dial process to account for request timeouts, use DialTimeout instead.
//
// If not set, DialTimeout is used.
Dial DialFunc
// TLS config for https connections.
//
// Default TLS config is used if not set.
TLSConfig *tls.Config
// RetryIf controls whether a retry should be attempted after an error.
//
// By default will use isIdempotent function.
//
// Deprecated: Use RetryIfErr instead.
// This field is only effective when the `RetryIfErr` field is not set.
RetryIf RetryIfFunc
// When the client encounters an error during a request, the behavior—whether to retry
// and whether to reset the request timeout—should be determined
// based on the return value of this field.
// This field is only effective within the range of MaxIdemponentCallAttempts.
RetryIfErr RetryIfErrFunc
// ConfigureClient configures the fasthttp.HostClient.
ConfigureClient func(hc *HostClient) error
m map[string]*HostClient
ms map[string]*HostClient
// Client name. Used in User-Agent request header.
//
// Default client name is used if not set.
Name string
// Maximum number of connections per each host which may be established.
//
// DefaultMaxConnsPerHost is used if not set.
MaxConnsPerHost int
// Idle keep-alive connections are closed after this duration.
//
// By default idle connections are closed
// after DefaultMaxIdleConnDuration.
MaxIdleConnDuration time.Duration
// Keep-alive connections are closed after this duration.
//
// By default connection duration is unlimited.
MaxConnDuration time.Duration
// Maximum number of attempts for idempotent calls.
//
// DefaultMaxIdemponentCallAttempts is used if not set.
MaxIdemponentCallAttempts int
// Per-connection buffer size for responses' reading.
// This also limits the maximum header size.
//
// Default buffer size is used if 0.
ReadBufferSize int
// Per-connection buffer size for requests' writing.
//
// Default buffer size is used if 0.
WriteBufferSize int
// Maximum duration for full response reading (including body).
//
// By default response read timeout is unlimited.
ReadTimeout time.Duration
// Maximum duration for full request writing (including body).
//
// By default request write timeout is unlimited.
WriteTimeout time.Duration
// Maximum response body size.
//
// The client returns ErrBodyTooLarge if this limit is greater than 0
// and response body is greater than the limit.
//
// By default response body size is unlimited.
MaxResponseBodySize int
// Maximum duration for waiting for a free connection.
//
// By default will not waiting, return ErrNoFreeConns immediately.
MaxConnWaitTimeout time.Duration
// Connection pool strategy. Can be either LIFO or FIFO (default).
ConnPoolStrategy ConnPoolStrategyType
mLock sync.RWMutex
mOnce sync.Once
// NoDefaultUserAgentHeader when set to true, causes the default
// User-Agent header to be excluded from the Request.
NoDefaultUserAgentHeader bool
// Attempt to connect to both ipv4 and ipv6 addresses if set to true.
//
// This option is used only if default TCP dialer is used,
// i.e. if Dial is blank.
//
// By default client connects only to ipv4 addresses,
// since unfortunately ipv6 remains broken in many networks worldwide :)
DialDualStack bool
// Header names are passed as-is without normalization
// if this option is set.
//
// Disabled header names' normalization may be useful only for proxying
// responses to other clients expecting case-sensitive
// header names. See https://github.com/valyala/fasthttp/issues/57
// for details.
//
// By default request and response header names are normalized, i.e.
// The first letter and the first letters following dashes
// are uppercased, while all the other letters are lowercased.
// Examples:
//
// * HOST -> Host
// * content-type -> Content-Type
// * cONTENT-lenGTH -> Content-Length
DisableHeaderNamesNormalizing bool
// Path values are sent as-is without normalization.
//
// Disabled path normalization may be useful for proxying incoming requests
// to servers that are expecting paths to be forwarded as-is.
//
// By default path values are normalized, i.e.
// extra slashes are removed, special characters are encoded.
DisablePathNormalizing bool
// StreamResponseBody enables response body streaming.
StreamResponseBody bool
}
// Get returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
func (c *Client) Get(dst []byte, url string) (statusCode int, body []byte, err error) {
return clientGetURL(dst, url, c)
}
// GetTimeout returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// ErrTimeout error is returned if url contents couldn't be fetched
// during the given timeout.
func (c *Client) GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
return clientGetURLTimeout(dst, url, timeout, c)
}
// GetDeadline returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// ErrTimeout error is returned if url contents couldn't be fetched
// until the given deadline.
func (c *Client) GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
return clientGetURLDeadline(dst, url, deadline, c)
}
// Post sends POST request to the given url with the given POST arguments.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// Empty POST body is sent if postArgs is nil.
func (c *Client) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) {
return clientPostURL(dst, url, postArgs, c)
}
// DoTimeout performs the given request and waits for response during
// the given timeout duration.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned during
// the given timeout.
// Immediately returns ErrTimeout if timeout value is negative.
//
// ErrNoFreeConns is returned if all Client.MaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *Client) DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
req.timeout = timeout
if req.timeout <= 0 {
return ErrTimeout
}
return c.Do(req, resp)
}
// DoDeadline performs the given request and waits for response until
// the given deadline.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned until
// the given deadline.
// Immediately returns ErrTimeout if the deadline has already been reached.
//
// ErrNoFreeConns is returned if all Client.MaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *Client) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
req.timeout = time.Until(deadline)
if req.timeout <= 0 {
return ErrTimeout
}
return c.Do(req, resp)
}
// DoRedirects performs the given http request and fills the given http response,
// following up to maxRedirectsCount redirects. When the redirect count exceeds
// maxRedirectsCount, ErrTooManyRedirects is returned.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// Response is ignored if resp is nil.
//
// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *Client) DoRedirects(req *Request, resp *Response, maxRedirectsCount int) error {
if c.DisablePathNormalizing {
req.URI().DisablePathNormalizing = true
}
_, _, err := doRequestFollowRedirects(req, resp, req.URI().String(), maxRedirectsCount, c)
return err
}
// Do performs the given http request and fills the given http response.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// Response is ignored if resp is nil.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// ErrNoFreeConns is returned if all Client.MaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *Client) Do(req *Request, resp *Response) error {
uri := req.URI()
if uri == nil {
return ErrorInvalidURI
}
host := uri.Host()
if bytes.ContainsRune(host, ',') {
return fmt.Errorf("invalid host %q. Use HostClient for multiple hosts", host)
}
isTLS := false
if uri.isHTTPS() {
isTLS = true
} else if !uri.isHTTP() {
return fmt.Errorf("unsupported protocol %q. http and https are supported", uri.Scheme())
}
c.mOnce.Do(func() {
c.m = make(map[string]*HostClient)
c.ms = make(map[string]*HostClient)
})
hc, err := c.hostClient(host, isTLS)
if err != nil {
return err
}
atomic.AddInt32(&hc.pendingClientRequests, 1)
defer atomic.AddInt32(&hc.pendingClientRequests, -1)
return hc.Do(req, resp)
}
func (c *Client) hostClient(host []byte, isTLS bool) (*HostClient, error) {
m := c.m
if isTLS {
m = c.ms
}
c.mLock.RLock()
hc, exist := m[string(host)]
c.mLock.RUnlock()
if exist {
return hc, nil
}
c.mLock.Lock()
defer c.mLock.Unlock()
hc, exist = m[string(host)]
if exist {
return hc, nil
}
hc = &HostClient{
Addr: AddMissingPort(string(host), isTLS),
Transport: c.Transport,
Name: c.Name,
NoDefaultUserAgentHeader: c.NoDefaultUserAgentHeader,
Dial: c.Dial,
DialTimeout: c.DialTimeout,
DialDualStack: c.DialDualStack,
IsTLS: isTLS,
TLSConfig: c.TLSConfig,
MaxConns: c.MaxConnsPerHost,
MaxIdleConnDuration: c.MaxIdleConnDuration,
MaxConnDuration: c.MaxConnDuration,
MaxIdemponentCallAttempts: c.MaxIdemponentCallAttempts,
ReadBufferSize: c.ReadBufferSize,
WriteBufferSize: c.WriteBufferSize,
ReadTimeout: c.ReadTimeout,
WriteTimeout: c.WriteTimeout,
MaxResponseBodySize: c.MaxResponseBodySize,
DisableHeaderNamesNormalizing: c.DisableHeaderNamesNormalizing,
DisablePathNormalizing: c.DisablePathNormalizing,
MaxConnWaitTimeout: c.MaxConnWaitTimeout,
RetryIf: c.RetryIf,
RetryIfErr: c.RetryIfErr,
ConnPoolStrategy: c.ConnPoolStrategy,
StreamResponseBody: c.StreamResponseBody,
clientReaderPool: &c.readerPool,
clientWriterPool: &c.writerPool,
}
if c.ConfigureClient != nil {
if err := c.ConfigureClient(hc); err != nil {
return nil, err
}
}
m[string(host)] = hc
if len(m) == 1 {
go c.mCleaner(m)
}
return hc, nil
}
// CloseIdleConnections closes any connections which were previously
// connected from previous requests but are now sitting idle in a
// "keep-alive" state. It does not interrupt any connections currently
// in use.
func (c *Client) CloseIdleConnections() {
c.mLock.RLock()
for _, v := range c.m {
v.CloseIdleConnections()
}
for _, v := range c.ms {
v.CloseIdleConnections()
}
c.mLock.RUnlock()
}
func (c *Client) mCleaner(m map[string]*HostClient) {
mustStop := false
sleep := c.MaxIdleConnDuration
if sleep < time.Second {
sleep = time.Second
} else if sleep > 10*time.Second {
sleep = 10 * time.Second
}
for {
time.Sleep(sleep)
c.mLock.Lock()
for k, v := range m {
v.connsLock.Lock()
if v.connsCount == 0 && atomic.LoadInt32(&v.pendingClientRequests) == 0 {
delete(m, k)
}
v.connsLock.Unlock()
}
if len(m) == 0 {
mustStop = true
}
c.mLock.Unlock()
if mustStop {
break
}
}
}
// DefaultMaxConnsPerHost is the maximum number of concurrent connections
// http client may establish per host by default (i.e. if
// Client.MaxConnsPerHost isn't set).
const DefaultMaxConnsPerHost = 512
// DefaultMaxIdleConnDuration is the default duration before idle keep-alive
// connection is closed.
const DefaultMaxIdleConnDuration = 10 * time.Second
// DefaultMaxIdemponentCallAttempts is the default idempotent calls attempts count.
const DefaultMaxIdemponentCallAttempts = 5
// DialFunc must establish connection to addr.
//
// There is no need in establishing TLS (SSL) connection for https.
// The client automatically converts connection to TLS
// if HostClient.IsTLS is set.
//
// TCP address passed to DialFunc always contains host and port.
// Example TCP addr values:
//
// - foobar.com:80
// - foobar.com:443
// - foobar.com:8080
type DialFunc func(addr string) (net.Conn, error)
// DialFuncWithTimeout must establish connection to addr.
// Unlike DialFunc, it also accepts a timeout.
//
// There is no need in establishing TLS (SSL) connection for https.
// The client automatically converts connection to TLS
// if HostClient.IsTLS is set.
//
// TCP address passed to DialFuncWithTimeout always contains host and port.
// Example TCP addr values:
//
// - foobar.com:80
// - foobar.com:443
// - foobar.com:8080
type DialFuncWithTimeout func(addr string, timeout time.Duration) (net.Conn, error)
// RetryIfFunc defines the signature of the retry if function.
// Request argument passed to RetryIfFunc, if there are any request errors.
type RetryIfFunc func(request *Request) bool
// RetryIfErrFunc defines an interface used for implementing the following functionality:
// When the client encounters an error during a request, the behavior—whether to retry
// and whether to reset the request timeout—should be determined
// based on the return value of this interface.
//
// attempt indicates which attempt the current retry is due to a failure of.
// The first request counts as the first attempt.
//
// err represents the error encountered while attempting the `attempts`-th request.
//
// resetTimeout indicates whether to reuse the `Request`'s timeout as the timeout interval,
// rather than using the timeout after subtracting the time spent on previous failed requests.
// This return value is meaningful only when you use `Request.SetTimeout`, `DoTimeout`, or `DoDeadline`.
//
// retry indicates whether to retry the current request. If it is false,
// the request function will immediately return with the `err`.
type RetryIfErrFunc func(request *Request, attempts int, err error) (resetTimeout bool, retry bool)
// RoundTripper wraps every request/response.
type RoundTripper interface {
RoundTrip(hc *HostClient, req *Request, resp *Response) (retry bool, err error)
}
// ConnPoolStrategyType define strategy of connection pool enqueue/dequeue.
type ConnPoolStrategyType int
const (
FIFO ConnPoolStrategyType = iota
LIFO
)
// HostClient balances http requests among hosts listed in Addr.
//
// HostClient may be used for balancing load among multiple upstream hosts.
// While multiple addresses passed to HostClient.Addr may be used for balancing
// load among them, it would be better using LBClient instead, since HostClient
// may unevenly balance load among upstream hosts.
//
// It is forbidden copying HostClient instances. Create new instances instead.
//
// It is safe calling HostClient methods from concurrently running goroutines.
type HostClient struct {
noCopy noCopy
readerPool sync.Pool
writerPool sync.Pool
// Transport defines a transport-like mechanism that wraps every request/response.
Transport RoundTripper
// Callback for establishing new connections to hosts.
//
// Default DialTimeout is used if not set.
DialTimeout DialFuncWithTimeout
// Callback for establishing new connections to hosts.
//
// Note that if Dial is set instead of DialTimeout, Dial will ignore Request timeout.
// If you want the tcp dial process to account for request timeouts, use DialTimeout instead.
//
// If not set, DialTimeout is used.
Dial DialFunc
// Optional TLS config.
TLSConfig *tls.Config
// RetryIf controls whether a retry should be attempted after an error.
// By default, it uses the isIdempotent function.
//
// Deprecated: Use RetryIfErr instead.
// This field is only effective when the `RetryIfErr` field is not set.
RetryIf RetryIfFunc
// When the client encounters an error during a request, the behavior—whether to retry
// and whether to reset the request timeout—should be determined
// based on the return value of this field.
// This field is only effective within the range of MaxIdemponentCallAttempts.
RetryIfErr RetryIfErrFunc
connsWait *wantConnQueue
tlsConfigMap map[string]*tls.Config
clientReaderPool *sync.Pool
clientWriterPool *sync.Pool
// Comma-separated list of upstream HTTP server host addresses,
// which are passed to Dial or DialTimeout in a round-robin manner.
//
// Each address may contain port if default dialer is used.
// For example,
//
// - foobar.com:80
// - foobar.com:443
// - foobar.com:8080
Addr string
// Client name. Used in User-Agent request header.
Name string
conns []*clientConn
addrs []string
// Maximum number of connections which may be established to all hosts
// listed in Addr.
//
// You can change this value while the HostClient is being used
// with HostClient.SetMaxConns(value)
//
// DefaultMaxConnsPerHost is used if not set.
MaxConns int
// Keep-alive connections are closed after this duration.
//
// By default connection duration is unlimited.
MaxConnDuration time.Duration
// Idle keep-alive connections are closed after this duration.
//
// By default idle connections are closed
// after DefaultMaxIdleConnDuration.
MaxIdleConnDuration time.Duration
// Maximum number of attempts for idempotent calls.
//
// A value of 0 or a negative value represents using DefaultMaxIdemponentCallAttempts.
// For example, a value of 1 means the request will be executed only once,
// while 2 means the request will be executed at most twice.
// The RetryIfErr and RetryIf fields can invalidate remaining attempts.
MaxIdemponentCallAttempts int
// Per-connection buffer size for responses' reading.
// This also limits the maximum header size.
//
// Default buffer size is used if 0.
ReadBufferSize int
// Per-connection buffer size for requests' writing.
//
// Default buffer size is used if 0.
WriteBufferSize int
// Maximum duration for full response reading (including body).
//
// By default response read timeout is unlimited.
ReadTimeout time.Duration
// Maximum duration for full request writing (including body).
//
// By default request write timeout is unlimited.
WriteTimeout time.Duration
// Maximum response body size.
//
// The client returns ErrBodyTooLarge if this limit is greater than 0
// and response body is greater than the limit.
//
// By default response body size is unlimited.
MaxResponseBodySize int
// Maximum duration for waiting for a free connection.
//
// By default will not waiting, return ErrNoFreeConns immediately
MaxConnWaitTimeout time.Duration
// Connection pool strategy. Can be either LIFO or FIFO (default).
ConnPoolStrategy ConnPoolStrategyType
connsCount int
connsLock sync.Mutex
addrsLock sync.Mutex
tlsConfigMapLock sync.Mutex
addrIdx uint32
lastUseTime uint32
pendingRequests int32
// pendingClientRequests counts the number of requests that a Client is currently running using this HostClient.
// It will be incremented earlier than pendingRequests and will be used by Client to see if the HostClient is still in use.
pendingClientRequests int32
// NoDefaultUserAgentHeader when set to true, causes the default
// User-Agent header to be excluded from the Request.
NoDefaultUserAgentHeader bool
// Attempt to connect to both ipv4 and ipv6 host addresses
// if set to true.
//
// This option is used only if default TCP dialer is used,
// i.e. if Dial and DialTimeout are blank.
//
// By default client connects only to ipv4 addresses,
// since unfortunately ipv6 remains broken in many networks worldwide :)
DialDualStack bool
// Whether to use TLS (aka SSL or HTTPS) for host connections.
IsTLS bool
// Header names are passed as-is without normalization
// if this option is set.
//
// Disabled header names' normalization may be useful only for proxying
// responses to other clients expecting case-sensitive
// header names. See https://github.com/valyala/fasthttp/issues/57
// for details.
//
// By default request and response header names are normalized, i.e.
// The first letter and the first letters following dashes
// are uppercased, while all the other letters are lowercased.
// Examples:
//
// * HOST -> Host
// * content-type -> Content-Type
// * cONTENT-lenGTH -> Content-Length
DisableHeaderNamesNormalizing bool
// Path values are sent as-is without normalization.
//
// Disabled path normalization may be useful for proxying incoming requests
// to servers that are expecting paths to be forwarded as-is.
//
// By default path values are normalized, i.e.
// extra slashes are removed, special characters are encoded.
DisablePathNormalizing bool
// Will not log potentially sensitive content in error logs.
//
// This option is useful for servers that handle sensitive data
// in the request/response.
//
// Client logs full errors by default.
SecureErrorLogMessage bool
// StreamResponseBody enables response body streaming.
StreamResponseBody bool
connsCleanerRun bool
}
type clientConn struct {
c net.Conn
createdTime time.Time
lastUseTime time.Time
}
// Conn returns the underlying net.Conn associated with the client connection.
func (cc *clientConn) Conn() net.Conn {
return cc.c
}
// CreatedTime returns time the client was created.
func (cc *clientConn) CreatedTime() time.Time {
return cc.createdTime
}
// LastUseTime returns time the client was last used.
func (cc *clientConn) LastUseTime() time.Time {
return cc.lastUseTime
}
var startTimeUnix = time.Now().Unix()
// LastUseTime returns time the client was last used.
func (c *HostClient) LastUseTime() time.Time {
n := atomic.LoadUint32(&c.lastUseTime)
return time.Unix(startTimeUnix+int64(n), 0)
}
// Get returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
func (c *HostClient) Get(dst []byte, url string) (statusCode int, body []byte, err error) {
return clientGetURL(dst, url, c)
}
// GetTimeout returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// ErrTimeout error is returned if url contents couldn't be fetched
// during the given timeout.
func (c *HostClient) GetTimeout(dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
return clientGetURLTimeout(dst, url, timeout, c)
}
// GetDeadline returns the status code and body of url.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// ErrTimeout error is returned if url contents couldn't be fetched
// until the given deadline.
func (c *HostClient) GetDeadline(dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
return clientGetURLDeadline(dst, url, deadline, c)
}
// Post sends POST request to the given url with the given POST arguments.
//
// The contents of dst will be replaced by the body and returned, if the dst
// is too small a new slice will be allocated.
//
// The function follows redirects. Use Do* for manually handling redirects.
//
// Empty POST body is sent if postArgs is nil.
func (c *HostClient) Post(dst []byte, url string, postArgs *Args) (statusCode int, body []byte, err error) {
return clientPostURL(dst, url, postArgs, c)
}
type clientDoer interface {
Do(req *Request, resp *Response) error
}
func clientGetURL(dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) {
req := AcquireRequest()
statusCode, body, err = doRequestFollowRedirectsBuffer(req, dst, url, c)
ReleaseRequest(req)
return statusCode, body, err
}
func clientGetURLTimeout(dst []byte, url string, timeout time.Duration, c clientDoer) (statusCode int, body []byte, err error) {
deadline := time.Now().Add(timeout)
return clientGetURLDeadline(dst, url, deadline, c)
}
type clientURLResponse struct {
err error
body []byte
statusCode int
}
func clientGetURLDeadline(dst []byte, url string, deadline time.Time, c clientDoer) (statusCode int, body []byte, err error) {
timeout := time.Until(deadline)
if timeout <= 0 {
return 0, dst, ErrTimeout
}
var ch chan clientURLResponse
chv := clientURLResponseChPool.Get()
if chv == nil {
chv = make(chan clientURLResponse, 1)
}
ch = chv.(chan clientURLResponse)
// Note that the request continues execution on ErrTimeout until
// client-specific ReadTimeout exceeds. This helps limiting load
// on slow hosts by MaxConns* concurrent requests.
//
// Without this 'hack' the load on slow host could exceed MaxConns*
// concurrent requests, since timed out requests on client side
// usually continue execution on the host.
var mu sync.Mutex
var timedout, responded bool
go func() {
req := AcquireRequest()
statusCodeCopy, bodyCopy, errCopy := doRequestFollowRedirectsBuffer(req, dst, url, c)
mu.Lock()
if !timedout {
ch <- clientURLResponse{
statusCode: statusCodeCopy,
body: bodyCopy,
err: errCopy,
}
responded = true
}
mu.Unlock()
ReleaseRequest(req)
}()
tc := AcquireTimer(timeout)
select {
case resp := <-ch:
statusCode = resp.statusCode
body = resp.body
err = resp.err
case <-tc.C:
mu.Lock()
if responded {
resp := <-ch
statusCode = resp.statusCode
body = resp.body
err = resp.err
} else {
timedout = true
err = ErrTimeout
body = dst
}
mu.Unlock()
}
ReleaseTimer(tc)
clientURLResponseChPool.Put(chv)
return statusCode, body, err
}
var clientURLResponseChPool sync.Pool
func clientPostURL(dst []byte, url string, postArgs *Args, c clientDoer) (statusCode int, body []byte, err error) {
req := AcquireRequest()
defer ReleaseRequest(req)
req.Header.SetMethod(MethodPost)
req.Header.SetContentTypeBytes(strPostArgsContentType)
if postArgs != nil {
if _, err := postArgs.WriteTo(req.BodyWriter()); err != nil {
return 0, nil, err
}
}
statusCode, body, err = doRequestFollowRedirectsBuffer(req, dst, url, c)
return statusCode, body, err
}
var (
// ErrMissingLocation is returned by clients when the Location header is missing on
// an HTTP response with a redirect status code.
ErrMissingLocation = errors.New("missing Location header for http redirect")
// ErrTooManyRedirects is returned by clients when the number of redirects followed
// exceed the max count.
ErrTooManyRedirects = errors.New("too many redirects detected when doing the request")
// ErrHostClientRedirectToDifferentScheme is returned when a HostClient follows a redirect to a different protocol.
ErrHostClientRedirectToDifferentScheme = errors.New("HostClient can't follow redirects to a different protocol," +
" please use Client instead")
)
const defaultMaxRedirectsCount = 16
func doRequestFollowRedirectsBuffer(req *Request, dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) {
resp := AcquireResponse()
bodyBuf := resp.bodyBuffer()
resp.keepBodyBuffer = true
oldBody := bodyBuf.B
bodyBuf.B = dst
statusCode, _, err = doRequestFollowRedirects(req, resp, url, defaultMaxRedirectsCount, c)
body = bodyBuf.B
bodyBuf.B = oldBody
resp.keepBodyBuffer = false
ReleaseResponse(resp)
return statusCode, body, err
}
func doRequestFollowRedirects(
req *Request, resp *Response, url string, maxRedirectsCount int, c clientDoer,
) (statusCode int, body []byte, err error) {
redirectsCount := 0
for {
req.SetRequestURI(url)
if err := req.parseURI(); err != nil {
return 0, nil, err
}
if err = c.Do(req, resp); err != nil {
break
}
statusCode = resp.Header.StatusCode()
if !StatusCodeIsRedirect(statusCode) {
break
}
redirectsCount++
if redirectsCount > maxRedirectsCount {
err = ErrTooManyRedirects
break
}
location := resp.Header.peek(strLocation)
if len(location) == 0 {
err = ErrMissingLocation
break
}
url = getRedirectURL(url, location, req.DisableRedirectPathNormalizing)
if string(req.Header.Method()) == "POST" && (statusCode == 301 || statusCode == 302) {
req.Header.SetMethod(MethodGet)
}
}
return statusCode, body, err
}
func getRedirectURL(baseURL string, location []byte, disablePathNormalizing bool) string {
u := AcquireURI()
u.Update(baseURL)
u.UpdateBytes(location)
u.DisablePathNormalizing = disablePathNormalizing
redirectURL := u.String()
ReleaseURI(u)
return redirectURL
}
// StatusCodeIsRedirect returns true if the status code indicates a redirect.
func StatusCodeIsRedirect(statusCode int) bool {
return statusCode == StatusMovedPermanently ||
statusCode == StatusFound ||
statusCode == StatusSeeOther ||
statusCode == StatusTemporaryRedirect ||
statusCode == StatusPermanentRedirect
}
var (
requestPool sync.Pool
responsePool sync.Pool
)
// AcquireRequest returns an empty Request instance from request pool.
//
// The returned Request instance may be passed to ReleaseRequest when it is
// no longer needed. This allows Request recycling, reduces GC pressure
// and usually improves performance.
func AcquireRequest() *Request {
v := requestPool.Get()
if v == nil {
return &Request{}
}
return v.(*Request)
}
// ReleaseRequest returns req acquired via AcquireRequest to request pool.
//
// It is forbidden accessing req and/or its' members after returning
// it to request pool.
func ReleaseRequest(req *Request) {
req.Reset()
requestPool.Put(req)
}
// AcquireResponse returns an empty Response instance from response pool.
//
// The returned Response instance may be passed to ReleaseResponse when it is
// no longer needed. This allows Response recycling, reduces GC pressure
// and usually improves performance.
func AcquireResponse() *Response {
v := responsePool.Get()
if v == nil {
return &Response{}
}
return v.(*Response)
}
// ReleaseResponse return resp acquired via AcquireResponse to response pool.
//
// It is forbidden accessing resp and/or its' members after returning
// it to response pool.
func ReleaseResponse(resp *Response) {
resp.Reset()
responsePool.Put(resp)
}
// DoTimeout performs the given request and waits for response during
// the given timeout duration.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned during
// the given timeout.
// Immediately returns ErrTimeout if timeout value is negative.
//
// ErrNoFreeConns is returned if all HostClient.MaxConns connections
// to the host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *HostClient) DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
req.timeout = timeout
if req.timeout <= 0 {
return ErrTimeout
}
return c.Do(req, resp)
}
// DoDeadline performs the given request and waits for response until
// the given deadline.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned until
// the given deadline.
// Immediately returns ErrTimeout if the deadline has already been reached.
//
// ErrNoFreeConns is returned if all HostClient.MaxConns connections
// to the host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *HostClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
req.timeout = time.Until(deadline)
if req.timeout <= 0 {
return ErrTimeout
}
return c.Do(req, resp)
}
// DoRedirects performs the given http request and fills the given http response,
// following up to maxRedirectsCount redirects. When the redirect count exceeds
// maxRedirectsCount, ErrTooManyRedirects is returned.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// Client determines the server to be requested in the following order:
//
// - from RequestURI if it contains full url with scheme and host;
// - from Host header otherwise.
//
// Response is ignored if resp is nil.
//
// ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
// to the requested host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *HostClient) DoRedirects(req *Request, resp *Response, maxRedirectsCount int) error {
if c.DisablePathNormalizing {
req.URI().DisablePathNormalizing = true
}
_, _, err := doRequestFollowRedirects(req, resp, req.URI().String(), maxRedirectsCount, c)
return err
}
// Do performs the given http request and sets the corresponding response.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// The function doesn't follow redirects. Use Get* for following redirects.
//
// Response is ignored if resp is nil.
//
// ErrNoFreeConns is returned if all HostClient.MaxConns connections
// to the host are busy.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *HostClient) Do(req *Request, resp *Response) error {
var (
err error
retry bool
resetTimeout bool
)
maxAttempts := c.MaxIdemponentCallAttempts
if maxAttempts <= 0 {
maxAttempts = DefaultMaxIdemponentCallAttempts
}
attempts := 0
hasBodyStream := req.IsBodyStream()
// If a request has a timeout we store the timeout
// and calculate a deadline so we can keep updating the
// timeout on each retry.
deadline := time.Time{}
timeout := req.timeout
if timeout > 0 {
deadline = time.Now().Add(timeout)
}
retryFunc := c.RetryIf
if retryFunc == nil {
retryFunc = isIdempotent
}
atomic.AddInt32(&c.pendingRequests, 1)
for {
// If the original timeout was set, we need to update
// the one set on the request to reflect the remaining time.
if timeout > 0 {
req.timeout = time.Until(deadline)
if req.timeout <= 0 {
err = ErrTimeout
break
}
}
retry, err = c.do(req, resp)
if err == nil || !retry {
break
}
if hasBodyStream {
break
}
// Path prioritization based on ease of computation
attempts++
if attempts >= maxAttempts {
break
}
if c.RetryIfErr != nil {
resetTimeout, retry = c.RetryIfErr(req, attempts, err)
} else {
retry = retryFunc(req)
}
if !retry {
break
}
if timeout > 0 && resetTimeout {
deadline = time.Now().Add(timeout)
}
}
atomic.AddInt32(&c.pendingRequests, -1)
// Restore the original timeout.
req.timeout = timeout
if err == io.EOF {
err = ErrConnectionClosed
}
return err
}
// PendingRequests returns the current number of requests the client
// is executing.
//
// This function may be used for balancing load among multiple HostClient
// instances.
func (c *HostClient) PendingRequests() int {
return int(atomic.LoadInt32(&c.pendingRequests))
}
func isIdempotent(req *Request) bool {
return req.Header.IsGet() || req.Header.IsHead() || req.Header.IsPut()
}
func (c *HostClient) do(req *Request, resp *Response) (bool, error) {
if resp == nil {
resp = AcquireResponse()
defer ReleaseResponse(resp)
}
return c.doNonNilReqResp(req, resp)
}
func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) {
if req == nil {
// for debugging purposes
panic("BUG: req cannot be nil")
}
if resp == nil {
// for debugging purposes
panic("BUG: resp cannot be nil")
}
// Secure header error logs configuration
resp.secureErrorLogMessage = c.SecureErrorLogMessage
resp.Header.secureErrorLogMessage = c.SecureErrorLogMessage
req.secureErrorLogMessage = c.SecureErrorLogMessage
req.Header.secureErrorLogMessage = c.SecureErrorLogMessage
if c.IsTLS != req.URI().isHTTPS() {
return false, ErrHostClientRedirectToDifferentScheme
}
atomic.StoreUint32(&c.lastUseTime, uint32(time.Now().Unix()-startTimeUnix)) // #nosec G115
// Free up resources occupied by response before sending the request,
// so the GC may reclaim these resources (e.g. response body).
// backing up SkipBody in case it was set explicitly
customSkipBody := resp.SkipBody
customStreamBody := resp.StreamBody || c.StreamResponseBody
resp.Reset()
resp.SkipBody = customSkipBody
resp.StreamBody = customStreamBody
req.URI().DisablePathNormalizing = c.DisablePathNormalizing
userAgentOld := req.Header.UserAgent()
if len(userAgentOld) == 0 {
userAgent := c.Name
if userAgent == "" && !c.NoDefaultUserAgentHeader {
userAgent = defaultUserAgent
}
if userAgent != "" {
req.Header.userAgent = append(req.Header.userAgent[:0], userAgent...)
}
}
return c.transport().RoundTrip(c, req, resp)
}
func (c *HostClient) transport() RoundTripper {
if c.Transport == nil {
return DefaultTransport
}
return c.Transport
}
var (
// ErrNoFreeConns is returned when no free connections available
// to the given host.
//
// Increase the allowed number of connections per host if you
// see this error.
ErrNoFreeConns = errors.New("no free connections available to host")
// ErrConnectionClosed may be returned from client methods if the server
// closes connection before returning the first response byte.
//
// If you see this error, then either fix the server by returning
// 'Connection: close' response header before closing the connection
// or add 'Connection: close' request header before sending requests
// to broken server.
ErrConnectionClosed = errors.New("the server closed connection before returning the first response byte. " +
"Make sure the server returns 'Connection: close' response header before closing the connection")
// ErrConnPoolStrategyNotImpl is returned when HostClient.ConnPoolStrategy is not implement yet.
// If you see this error, then you need to check your HostClient configuration.
ErrConnPoolStrategyNotImpl = errors.New("connection pool strategy is not implement")
)
type timeoutError struct{}
func (e *timeoutError) Error() string {
return "timeout"
}
// Timeout implements the Timeout behavior of the net.Error interface.
// This allows for checks like:
//
// if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
func (e *timeoutError) Timeout() bool {
return true
}
// ErrTimeout is returned from timed out calls.
var ErrTimeout = &timeoutError{}
// SetMaxConns sets up the maximum number of connections which may be established to all hosts listed in Addr.
func (c *HostClient) SetMaxConns(newMaxConns int) {
c.connsLock.Lock()
c.MaxConns = newMaxConns
c.connsLock.Unlock()
}
func (c *HostClient) AcquireConn(reqTimeout time.Duration, connectionClose bool) (cc *clientConn, err error) {
createConn := false
startCleaner := false
var n int
c.connsLock.Lock()
n = len(c.conns)
if n == 0 {
maxConns := c.MaxConns
if maxConns <= 0 {
maxConns = DefaultMaxConnsPerHost
}
if c.connsCount < maxConns {
c.connsCount++
createConn = true
if !c.connsCleanerRun && !connectionClose {
startCleaner = true
c.connsCleanerRun = true
}
}
} else {
switch c.ConnPoolStrategy {
case LIFO:
n--
cc = c.conns[n]
c.conns[n] = nil
c.conns = c.conns[:n]
case FIFO:
cc = c.conns[0]
copy(c.conns, c.conns[1:])
c.conns[n-1] = nil
c.conns = c.conns[:n-1]
default:
c.connsLock.Unlock()
return nil, ErrConnPoolStrategyNotImpl
}
}
c.connsLock.Unlock()
if cc != nil {
return cc, nil
}
if !createConn {
if c.MaxConnWaitTimeout <= 0 {
return nil, ErrNoFreeConns
}
//nolint:dupword
// reqTimeout c.MaxConnWaitTimeout wait duration
// d1 d2 min(d1, d2)
// 0(not set) d2 d2
// d1 0(don't wait) 0(don't wait)
// 0(not set) d2 d2
timeout := c.MaxConnWaitTimeout
timeoutOverridden := false
// reqTimeout == 0 means not set
if reqTimeout > 0 && reqTimeout < timeout {
timeout = reqTimeout
timeoutOverridden = true
}
// wait for a free connection
tc := AcquireTimer(timeout)
defer ReleaseTimer(tc)
w := &wantConn{
ready: make(chan struct{}, 1),
}
defer func() {
if err != nil {
w.cancel(c, err)
}
}()
c.queueForIdle(w)
select {
case <-w.ready:
return w.conn, w.err
case <-tc.C:
c.connsWait.failedWaiters.Add(1)
if timeoutOverridden {
return nil, ErrTimeout
}
return nil, ErrNoFreeConns
}
}
if startCleaner {
go c.connsCleaner()
}
conn, err := c.dialHostHard(reqTimeout)
if err != nil {
c.decConnsCount()
return nil, err
}
cc = acquireClientConn(conn)
return cc, nil
}
func (c *HostClient) queueForIdle(w *wantConn) {
c.connsLock.Lock()
defer c.connsLock.Unlock()
if c.connsWait == nil {
c.connsWait = &wantConnQueue{}
}
c.connsWait.clearFront()
c.connsWait.pushBack(w)
}
func (c *HostClient) dialConnFor(w *wantConn) {
conn, err := c.dialHostHard(0)
if err != nil {
w.tryDeliver(nil, err)
c.decConnsCount()
return
}
cc := acquireClientConn(conn)
if !w.tryDeliver(cc, nil) {
// not delivered, return idle connection
c.ReleaseConn(cc)
}
}
// CloseIdleConnections closes any connections which were previously
// connected from previous requests but are now sitting idle in a
// "keep-alive" state. It does not interrupt any connections currently
// in use.
func (c *HostClient) CloseIdleConnections() {
c.connsLock.Lock()
scratch := append([]*clientConn{}, c.conns...)
for i := range c.conns {
c.conns[i] = nil
}
c.conns = c.conns[:0]
c.connsLock.Unlock()
for _, cc := range scratch {
c.CloseConn(cc)
}
}
func (c *HostClient) connsCleaner() {
var (
scratch []*clientConn
maxIdleConnDuration = c.MaxIdleConnDuration
)
if maxIdleConnDuration <= 0 {
maxIdleConnDuration = DefaultMaxIdleConnDuration
}
for {
currentTime := time.Now()
// Determine idle connections to be closed.
c.connsLock.Lock()
conns := c.conns
n := len(conns)
i := 0
for i < n && currentTime.Sub(conns[i].lastUseTime) > maxIdleConnDuration {
i++
}
sleepFor := maxIdleConnDuration
if i < n {
// + 1 so we actually sleep past the expiration time and not up to it.
// Otherwise the > check above would still fail.
sleepFor = maxIdleConnDuration - currentTime.Sub(conns[i].lastUseTime) + 1
}
scratch = append(scratch[:0], conns[:i]...)
if i > 0 {
m := copy(conns, conns[i:])
for i = m; i < n; i++ {
conns[i] = nil
}
c.conns = conns[:m]
}
c.connsLock.Unlock()
// Close idle connections.
for i, cc := range scratch {
c.CloseConn(cc)
scratch[i] = nil
}
// Determine whether to stop the connsCleaner.
c.connsLock.Lock()
mustStop := c.connsCount == 0
if mustStop {
c.connsCleanerRun = false
}
c.connsLock.Unlock()
if mustStop {
break
}
time.Sleep(sleepFor)
}
}
func (c *HostClient) CloseConn(cc *clientConn) {
c.decConnsCount()
cc.c.Close()
releaseClientConn(cc)
}
func (c *HostClient) decConnsCount() {
if c.MaxConnWaitTimeout <= 0 {
c.connsLock.Lock()
c.connsCount--
c.connsLock.Unlock()
return
}
c.connsLock.Lock()
defer c.connsLock.Unlock()
dialed := false
if q := c.connsWait; q != nil && q.len() > 0 {
for q.len() > 0 {
w := q.popFront()
if w.waiting() {
go c.dialConnFor(w)
dialed = true
break
}
c.connsWait.failedWaiters.Add(-1)
}
}
if !dialed {
c.connsCount--
}
}
// ConnsCount returns connection count of HostClient.
func (c *HostClient) ConnsCount() int {
c.connsLock.Lock()
defer c.connsLock.Unlock()
return c.connsCount
}
func acquireClientConn(conn net.Conn) *clientConn {
v := clientConnPool.Get()
if v == nil {
v = &clientConn{}
}
cc := v.(*clientConn)
cc.c = conn
cc.createdTime = time.Now()
return cc
}
func releaseClientConn(cc *clientConn) {
// Reset all fields.
*cc = clientConn{}
clientConnPool.Put(cc)
}
var clientConnPool sync.Pool
func (c *HostClient) ReleaseConn(cc *clientConn) {
cc.lastUseTime = time.Now()
if c.MaxConnWaitTimeout <= 0 {
c.connsLock.Lock()
c.conns = append(c.conns, cc)
c.connsLock.Unlock()
return
}
// try to deliver an idle connection to a *wantConn
c.connsLock.Lock()
defer c.connsLock.Unlock()
delivered := false
if q := c.connsWait; q != nil && q.len() > 0 {
for q.len() > 0 {
w := q.popFront()
if w.waiting() {
delivered = w.tryDeliver(cc, nil)
// This is the last resort to hand over conCount sema.
// We must ensure that there are no valid waiters in connsWait
// when we exit this loop.
//
// We did not apply the same looping pattern in the decConnsCount
// method because it needs to create a new time-spent connection,
// and the decConnsCount call chain will inevitably reach this point.
// When MaxConnWaitTimeout>0.
if delivered {
break
}
}
c.connsWait.failedWaiters.Add(-1)
}
}
if !delivered {
c.conns = append(c.conns, cc)
}
}
func (c *HostClient) AcquireWriter(conn net.Conn) *bufio.Writer {
var v any
if c.clientWriterPool != nil {
v = c.clientWriterPool.Get()
} else {
v = c.writerPool.Get()
}
if v == nil {
n := c.WriteBufferSize
if n <= 0 {
n = defaultWriteBufferSize
}
return bufio.NewWriterSize(conn, n)
}
bw := v.(*bufio.Writer)
bw.Reset(conn)
return bw
}
func (c *HostClient) ReleaseWriter(bw *bufio.Writer) {
if c.clientWriterPool != nil {
c.clientWriterPool.Put(bw)
} else {
c.writerPool.Put(bw)
}
}
func (c *HostClient) AcquireReader(conn net.Conn) *bufio.Reader {
var v any
if c.clientReaderPool != nil {
v = c.clientReaderPool.Get()
} else {
v = c.readerPool.Get()
}
if v == nil {
n := c.ReadBufferSize
if n <= 0 {
n = defaultReadBufferSize
}
return bufio.NewReaderSize(conn, n)
}
br := v.(*bufio.Reader)
br.Reset(conn)
return br
}
func (c *HostClient) ReleaseReader(br *bufio.Reader) {
if c.clientReaderPool != nil {
c.clientReaderPool.Put(br)
} else {
c.readerPool.Put(br)
}
}
func newClientTLSConfig(c *tls.Config, addr string) *tls.Config {
if c == nil {
c = &tls.Config{}
} else {
c = c.Clone()
}
if c.ServerName == "" {
serverName := tlsServerName(addr)
if serverName == "*" {
c.InsecureSkipVerify = true
} else {
c.ServerName = serverName
}
}
return c
}
func tlsServerName(addr string) string {
if !strings.Contains(addr, ":") {
return addr
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
return "*"
}
return host
}
func (c *HostClient) nextAddr() string {
c.addrsLock.Lock()
if c.addrs == nil {
c.addrs = strings.Split(c.Addr, ",")
}
addr := c.addrs[0]
if len(c.addrs) > 1 {
addr = c.addrs[c.addrIdx%uint32(len(c.addrs))] // #nosec G115
c.addrIdx++
}
c.addrsLock.Unlock()
return addr
}
func (c *HostClient) dialHostHard(dialTimeout time.Duration) (conn net.Conn, err error) {
// use dialTimeout to control the timeout of each dial. It does not work if dialTimeout is 0 or if
// c.DialTimeout has not been set and c.Dial has been set.
// attempt to dial all the available hosts before giving up.
c.addrsLock.Lock()
n := len(c.addrs)
c.addrsLock.Unlock()
if n == 0 {
// It looks like c.addrs isn't initialized yet.
n = 1
}
timeout := c.ReadTimeout + c.WriteTimeout
if timeout <= 0 {
timeout = DefaultDialTimeout
}
deadline := time.Now().Add(timeout)
for n > 0 {
addr := c.nextAddr()
tlsConfig := c.cachedTLSConfig(addr)
conn, err = dialAddr(addr, c.Dial, c.DialTimeout, c.DialDualStack, c.IsTLS, tlsConfig, dialTimeout, c.WriteTimeout)
if err == nil {
return conn, nil
}
if time.Since(deadline) >= 0 {
break
}
n--
}
return nil, err
}
func (c *HostClient) cachedTLSConfig(addr string) *tls.Config {
if !c.IsTLS {
return nil
}
c.tlsConfigMapLock.Lock()
if c.tlsConfigMap == nil {
c.tlsConfigMap = make(map[string]*tls.Config)
}
cfg := c.tlsConfigMap[addr]
if cfg == nil {
cfg = newClientTLSConfig(c.TLSConfig, addr)
c.tlsConfigMap[addr] = cfg
}
c.tlsConfigMapLock.Unlock()
return cfg
}
// ErrTLSHandshakeTimeout indicates there is a timeout from tls handshake.
var ErrTLSHandshakeTimeout = errors.New("tls handshake timed out")
func tlsClientHandshake(rawConn net.Conn, tlsConfig *tls.Config, deadline time.Time) (_ net.Conn, retErr error) {
defer func() {
if retErr != nil {
rawConn.Close()
}
}()
conn := tls.Client(rawConn, tlsConfig)
err := conn.SetDeadline(deadline)
if err != nil {
return nil, err
}
err = conn.Handshake()
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
return nil, ErrTLSHandshakeTimeout
}
if err != nil {
return nil, err
}
err = conn.SetDeadline(time.Time{})
if err != nil {
return nil, err
}
return conn, nil
}
func dialAddr(
addr string, dial DialFunc, dialWithTimeout DialFuncWithTimeout, dialDualStack, isTLS bool,
tlsConfig *tls.Config, dialTimeout, writeTimeout time.Duration,
) (net.Conn, error) {
deadline := time.Now().Add(writeTimeout)
conn, err := callDialFunc(addr, dial, dialWithTimeout, dialDualStack, isTLS, dialTimeout)
if err != nil {
return nil, err
}
if conn == nil {
return nil, errors.New("dialling unsuccessful. Please report this bug")
}
// We assume that any conn that has the Handshake() method is a TLS conn already.
// This doesn't cover just tls.Conn but also other TLS implementations.
_, isTLSAlready := conn.(interface{ Handshake() error })
if isTLS && !isTLSAlready {
if writeTimeout == 0 {
return tls.Client(conn, tlsConfig), nil
}
return tlsClientHandshake(conn, tlsConfig, deadline)
}
return conn, nil
}
func callDialFunc(
addr string, dial DialFunc, dialWithTimeout DialFuncWithTimeout, dialDualStack, isTLS bool, timeout time.Duration,
) (net.Conn, error) {
if dialWithTimeout != nil {
return dialWithTimeout(addr, timeout)
}
if dial != nil {
return dial(addr)
}
addr = AddMissingPort(addr, isTLS)
if timeout > 0 {
if dialDualStack {
return DialDualStackTimeout(addr, timeout)
}
return DialTimeout(addr, timeout)
}
if dialDualStack {
return DialDualStack(addr)
}
return Dial(addr)
}
// AddMissingPort adds a port to a host if it is missing.
// A literal IPv6 address in hostport must be enclosed in square
// brackets, as in "[::1]:80", "[::1%lo0]:80".
func AddMissingPort(addr string, isTLS bool) string {
addrLen := len(addr)
if addrLen == 0 {
return addr
}
isIP6 := addr[0] == '['
if isIP6 {
// if the IPv6 has opening bracket but closing bracket is the last char then it doesn't have a port
isIP6WithoutPort := addr[addrLen-1] == ']'
if !isIP6WithoutPort {
return addr
}
} else { // IPv4
columnPos := strings.LastIndexByte(addr, ':')
if columnPos > 0 {
return addr
}
}
port := ":80"
if isTLS {
port = ":443"
}
return addr + port
}
// A wantConn records state about a wanted connection
// (that is, an active call to getConn).
// The conn may be gotten by dialing or by finding an idle connection,
// or a cancellation may make the conn no longer wanted.
// These three options are racing against each other and use
// wantConn to coordinate and agree about the winning outcome.
//
// Inspired by net/http/transport.go.
type wantConn struct {
err error
ready chan struct{}
conn *clientConn
mu sync.Mutex // protects conn, err, close(ready)
}
// waiting reports whether w is still waiting for an answer (connection or error).
func (w *wantConn) waiting() bool {
select {
case <-w.ready:
return false
default:
return true
}
}
// tryDeliver attempts to deliver conn, err to w and reports whether it succeeded.
func (w *wantConn) tryDeliver(conn *clientConn, err error) bool {
w.mu.Lock()
defer w.mu.Unlock()
if w.conn != nil || w.err != nil {
return false
}
w.conn = conn
w.err = err
if w.conn == nil && w.err == nil {
panic("fasthttp: internal error: misuse of tryDeliver")
}
close(w.ready)
return true
}
// cancel marks w as no longer wanting a result (for example, due to cancellation).
// If a connection has been delivered already, cancel returns it with c.releaseConn.
func (w *wantConn) cancel(c *HostClient, err error) {
w.mu.Lock()
if w.conn == nil && w.err == nil {
close(w.ready) // catch misbehavior in future delivery
}
conn := w.conn
w.conn = nil
w.err = err
w.mu.Unlock()
if conn != nil {
c.ReleaseConn(conn)
}
}
// A wantConnQueue is a queue of wantConns.
//
// Inspired by net/http/transport.go.
type wantConnQueue struct {
// This is a queue, not a dequeue.
// It is split into two stages - head[headPos:] and tail.
// popFront is trivial (headPos++) on the first stage, and
// pushBack is trivial (append) on the second stage.
// If the first stage is empty, popFront can swap the
// first and second stages to remedy the situation.
//
// This two-stage split is analogous to the use of two lists
// in Okasaki's purely functional queue but without the
// overhead of reversing the list when swapping stages.
head []*wantConn
tail []*wantConn
headPos int
// failedWaiters is the number of waiters in the head or tail queue,
// but is invalid.
// These state waiters cannot truly be considered as waiters; the current
// implementation does not immediately remove them when they become
// invalid but instead only marks them.
failedWaiters atomic.Int64
}
// len returns the number of items in the queue.
func (q *wantConnQueue) len() int {
return len(q.head) - q.headPos + len(q.tail) - int(q.failedWaiters.Load())
}
// pushBack adds w to the back of the queue.
func (q *wantConnQueue) pushBack(w *wantConn) {
q.tail = append(q.tail, w)
}
// popFront removes and returns the wantConn at the front of the queue.
func (q *wantConnQueue) popFront() *wantConn {
if q.headPos >= len(q.head) {
if len(q.tail) == 0 {
return nil
}
// Pick up tail as new head, clear tail.
q.head, q.headPos, q.tail = q.tail, 0, q.head[:0]
}
w := q.head[q.headPos]
q.head[q.headPos] = nil
q.headPos++
return w
}
// peekFront returns the wantConn at the front of the queue without removing it.
func (q *wantConnQueue) peekFront() *wantConn {
if q.headPos < len(q.head) {
return q.head[q.headPos]
}
if len(q.tail) > 0 {
return q.tail[0]
}
return nil
}
// clearFront pops any wantConns that are no longer waiting from the head of the
// queue, reporting whether any were popped.
func (q *wantConnQueue) clearFront() (cleaned bool) {
for {
w := q.peekFront()
if w == nil || w.waiting() {
return cleaned
}
q.popFront()
q.failedWaiters.Add(-1)
cleaned = true
}
}
// PipelineClient pipelines requests over a limited set of concurrent
// connections to the given Addr.
//
// This client may be used in highly loaded HTTP-based RPC systems for reducing
// context switches and network level overhead.
// See https://en.wikipedia.org/wiki/HTTP_pipelining for details.
//
// It is forbidden copying PipelineClient instances. Create new instances
// instead.
//
// It is safe calling PipelineClient methods from concurrently running
// goroutines.
type PipelineClient struct {
noCopy noCopy
// Logger for logging client errors.
//
// By default standard logger from log package is used.
Logger Logger
// Callback for connection establishing to the host.
//
// Default Dial is used if not set.
Dial DialFunc
// Optional TLS config.
TLSConfig *tls.Config
// Address of the host to connect to.
Addr string
// PipelineClient name. Used in User-Agent request header.
Name string
connClients []*pipelineConnClient
// The maximum number of concurrent connections to the Addr.
//
// A single connection is used by default.
MaxConns int
// The maximum number of pending pipelined requests over
// a single connection to Addr.
//
// DefaultMaxPendingRequests is used by default.
MaxPendingRequests int
// The maximum delay before sending pipelined requests as a batch
// to the server.
//
// By default requests are sent immediately to the server.
MaxBatchDelay time.Duration
// Idle connection to the host is closed after this duration.
//
// By default idle connection is closed after
// DefaultMaxIdleConnDuration.
MaxIdleConnDuration time.Duration
// Buffer size for responses' reading.
// This also limits the maximum header size.
//
// Default buffer size is used if 0.
ReadBufferSize int
// Buffer size for requests' writing.
//
// Default buffer size is used if 0.
WriteBufferSize int
// Maximum duration for full response reading (including body).
//
// By default response read timeout is unlimited.
ReadTimeout time.Duration
// Maximum duration for full request writing (including body).
//
// By default request write timeout is unlimited.
WriteTimeout time.Duration
connClientsLock sync.Mutex
// NoDefaultUserAgentHeader when set to true, causes the default
// User-Agent header to be excluded from the Request.
NoDefaultUserAgentHeader bool
// Attempt to connect to both ipv4 and ipv6 host addresses
// if set to true.
//
// This option is used only if default TCP dialer is used,
// i.e. if Dial is blank.
//
// By default client connects only to ipv4 addresses,
// since unfortunately ipv6 remains broken in many networks worldwide :)
DialDualStack bool
// Response header names are passed as-is without normalization
// if this option is set.
//
// Disabled header names' normalization may be useful only for proxying
// responses to other clients expecting case-sensitive
// header names. See https://github.com/valyala/fasthttp/issues/57
// for details.
//
// By default request and response header names are normalized, i.e.
// The first letter and the first letters following dashes
// are uppercased, while all the other letters are lowercased.
// Examples:
//
// * HOST -> Host
// * content-type -> Content-Type
// * cONTENT-lenGTH -> Content-Length
DisableHeaderNamesNormalizing bool
// Path values are sent as-is without normalization
//
// Disabled path normalization may be useful for proxying incoming requests
// to servers that are expecting paths to be forwarded as-is.
//
// By default path values are normalized, i.e.
// extra slashes are removed, special characters are encoded.
DisablePathNormalizing bool
// Whether to use TLS (aka SSL or HTTPS) for host connections.
IsTLS bool
}
type pipelineConnClient struct {
noCopy noCopy
workPool sync.Pool
Logger Logger
Dial DialFunc
TLSConfig *tls.Config
chW chan *pipelineWork
chR chan *pipelineWork
tlsConfig *tls.Config
Addr string
Name string
MaxPendingRequests int
MaxBatchDelay time.Duration
MaxIdleConnDuration time.Duration
ReadBufferSize int
WriteBufferSize int
ReadTimeout time.Duration
WriteTimeout time.Duration
chLock sync.Mutex
tlsConfigLock sync.Mutex
NoDefaultUserAgentHeader bool
DialDualStack bool
DisableHeaderNamesNormalizing bool
DisablePathNormalizing bool
IsTLS bool
}
type pipelineWork struct {
respCopy Response
deadline time.Time
err error
req *Request
resp *Response
t *time.Timer
done chan struct{}
reqCopy Request
}
// DoTimeout performs the given request and waits for response during
// the given timeout duration.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// The function doesn't follow redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned during
// the given timeout.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *PipelineClient) DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
return c.DoDeadline(req, resp, time.Now().Add(timeout))
}
// DoDeadline performs the given request and waits for response until
// the given deadline.
//
// Request must contain at least non-zero RequestURI with full url (including
// scheme and host) or non-zero Host header + RequestURI.
//
// The function doesn't follow redirects.
//
// Response is ignored if resp is nil.
//
// ErrTimeout is returned if the response wasn't returned until
// the given deadline.
//
// It is recommended obtaining req and resp via AcquireRequest
// and AcquireResponse in performance-critical code.
func (c *PipelineClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
return c.getConnClient().DoDeadline(req, resp, deadline)
}
func (c *pipelineConnClient) DoDeadline(req *Request, resp *Response, deadline time.Time) error {
c.init()
timeout := time.Until(deadline)
if timeout <= 0 {
return ErrTimeout
}
if c.DisablePathNormalizing {
req.URI().DisablePathNormalizing = true
}
userAgentOld := req.Header.UserAgent()
if len(userAgentOld) == 0 {
userAgent := c.Name
if userAgent == "" && !c.NoDefaultUserAgentHeader {
userAgent = defaultUserAgent
}
if userAgent != "" {
req.Header.userAgent = append(req.Header.userAgent[:0], userAgent...)
}
}
w := c.acquirePipelineWork(timeout)
w.respCopy.Header.disableNormalizing = c.DisableHeaderNam
gitextract_z0m1bue7/ ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── cifuzz.yml │ ├── lint.yml │ ├── security.yml │ └── test.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── README.md ├── SECURITY.md ├── TODO ├── allocation_test.go ├── args.go ├── args_test.go ├── args_timing_test.go ├── b2s.go ├── brotli.go ├── brotli_test.go ├── bytesconv.go ├── bytesconv_32.go ├── bytesconv_32_test.go ├── bytesconv_64.go ├── bytesconv_64_test.go ├── bytesconv_table.go ├── bytesconv_table_gen.go ├── bytesconv_test.go ├── bytesconv_timing_test.go ├── client.go ├── client_example_test.go ├── client_test.go ├── client_timing_test.go ├── coarsetime.go ├── compress.go ├── compress_test.go ├── cookie.go ├── cookie_test.go ├── cookie_timing_test.go ├── doc.go ├── examples/ │ ├── README.md │ ├── host_client/ │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── README.md │ │ └── hostclient.go │ ├── letsencrypt/ │ │ └── letsencryptserver.go │ └── multidomain/ │ ├── Makefile │ ├── README.md │ └── multidomain.go ├── expvarhandler/ │ ├── expvar.go │ └── expvar_test.go ├── fasthttpadaptor/ │ ├── adaptor.go │ ├── adaptor_test.go │ ├── b2s.go │ ├── request.go │ └── request_test.go ├── fasthttpproxy/ │ ├── dialer.go │ ├── dialer_test.go │ ├── doc.go │ ├── http.go │ ├── proxy_env.go │ └── socks5.go ├── fasthttputil/ │ ├── doc.go │ ├── inmemory_listener.go │ ├── inmemory_listener_test.go │ ├── inmemory_listener_timing_test.go │ ├── pipeconns.go │ ├── pipeconns_test.go │ └── s2b.go ├── fs.go ├── fs_example_test.go ├── fs_fs_test.go ├── fs_handler_example_test.go ├── fs_test.go ├── fuzz_test.go ├── go.mod ├── go.sum ├── header.go ├── header_regression_test.go ├── header_test.go ├── header_timing_test.go ├── headers.go ├── headerscanner.go ├── http.go ├── http_test.go ├── http_timing_test.go ├── ipv6.go ├── ipv6_test.go ├── lbclient.go ├── lbclient_example_test.go ├── methods.go ├── nocopy.go ├── peripconn.go ├── peripconn_test.go ├── pprofhandler/ │ └── pprof.go ├── prefork/ │ ├── README.md │ ├── prefork.go │ └── prefork_test.go ├── requestctx_setbodystreamwriter_example_test.go ├── reuseport/ │ ├── LICENSE │ ├── reuseport.go │ ├── reuseport_aix.go │ ├── reuseport_error.go │ ├── reuseport_example_test.go │ ├── reuseport_solaris.go │ ├── reuseport_test.go │ └── reuseport_windows.go ├── round2_32.go ├── round2_32_test.go ├── round2_64.go ├── round2_64_test.go ├── s2b.go ├── server.go ├── server_example_test.go ├── server_race_test.go ├── server_test.go ├── server_timing_test.go ├── stackless/ │ ├── doc.go │ ├── func.go │ ├── func_test.go │ ├── func_timing_test.go │ ├── s2b.go │ ├── writer.go │ └── writer_test.go ├── status.go ├── status_test.go ├── status_timing_test.go ├── stream.go ├── stream_test.go ├── stream_timing_test.go ├── streaming.go ├── streaming_test.go ├── strings.go ├── tcpdialer.go ├── tcplisten/ │ ├── README.md │ ├── socket.go │ ├── socket_darwin.go │ ├── socket_other.go │ ├── socket_zos_s390x.go │ ├── tcplisten.go │ ├── tcplisten_js_wasm.go │ ├── tcplisten_linux.go │ ├── tcplisten_other.go │ └── tcplisten_test.go ├── timer.go ├── tls.go ├── uri.go ├── uri_test.go ├── uri_timing_test.go ├── uri_unix.go ├── uri_windows.go ├── uri_windows_test.go ├── userdata.go ├── userdata_test.go ├── userdata_timing_test.go ├── workerpool.go ├── workerpool_test.go ├── zstd.go └── zstd_test.go
Showing preview only (242K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2602 symbols across 129 files)
FILE: allocation_test.go
function TestAllocationServeConn (line 10) | func TestAllocationServeConn(t *testing.T) {
function TestAllocationClient (line 40) | func TestAllocationClient(t *testing.T) {
function TestAllocationURI (line 78) | func TestAllocationURI(t *testing.T) {
function TestAllocationFS (line 92) | func TestAllocationFS(t *testing.T) {
function TestAllocationsHeaderScanner (line 120) | func TestAllocationsHeaderScanner(t *testing.T) {
FILE: args.go
constant argsNoValue (line 13) | argsNoValue = true
constant argsHasValue (line 14) | argsHasValue = false
function AcquireArgs (line 21) | func AcquireArgs() *Args {
function ReleaseArgs (line 28) | func ReleaseArgs(a *Args) {
type Args (line 45) | type Args struct
method Reset (line 59) | func (a *Args) Reset() {
method CopyTo (line 64) | func (a *Args) CopyTo(dst *Args) {
method All (line 75) | func (a *Args) All() iter.Seq2[[]byte, []byte] {
method VisitAll (line 91) | func (a *Args) VisitAll(f func(key, value []byte)) {
method Len (line 99) | func (a *Args) Len() int {
method Parse (line 104) | func (a *Args) Parse(s string) {
method ParseBytes (line 110) | func (a *Args) ParseBytes(b []byte) {
method String (line 127) | func (a *Args) String() string {
method QueryString (line 135) | func (a *Args) QueryString() []byte {
method Sort (line 143) | func (a *Args) Sort(f func(x, y []byte) int) {
method SortKeys (line 156) | func (a *Args) SortKeys(f func(x, y []byte) int) {
method AppendBytes (line 163) | func (a *Args) AppendBytes(dst []byte) []byte {
method WriteTo (line 183) | func (a *Args) WriteTo(w io.Writer) (int64, error) {
method Del (line 189) | func (a *Args) Del(key string) {
method DelBytes (line 194) | func (a *Args) DelBytes(key []byte) {
method Add (line 201) | func (a *Args) Add(key, value string) {
method AddBytesK (line 208) | func (a *Args) AddBytesK(key []byte, value string) {
method AddBytesV (line 215) | func (a *Args) AddBytesV(key string, value []byte) {
method AddBytesKV (line 222) | func (a *Args) AddBytesKV(key, value []byte) {
method AddNoValue (line 229) | func (a *Args) AddNoValue(key string) {
method AddBytesKNoValue (line 236) | func (a *Args) AddBytesKNoValue(key []byte) {
method Set (line 241) | func (a *Args) Set(key, value string) {
method SetBytesK (line 246) | func (a *Args) SetBytesK(key []byte, value string) {
method SetBytesV (line 251) | func (a *Args) SetBytesV(key string, value []byte) {
method SetBytesKV (line 256) | func (a *Args) SetBytesKV(key, value []byte) {
method SetNoValue (line 263) | func (a *Args) SetNoValue(key string) {
method SetBytesKNoValue (line 268) | func (a *Args) SetBytesKNoValue(key []byte) {
method Peek (line 276) | func (a *Args) Peek(key string) []byte {
method PeekBytes (line 284) | func (a *Args) PeekBytes(key []byte) []byte {
method PeekMulti (line 289) | func (a *Args) PeekMulti(key string) [][]byte {
method PeekMultiBytes (line 300) | func (a *Args) PeekMultiBytes(key []byte) [][]byte {
method Has (line 305) | func (a *Args) Has(key string) bool {
method HasBytes (line 310) | func (a *Args) HasBytes(key []byte) bool {
method GetUint (line 318) | func (a *Args) GetUint(key string) (int, error) {
method SetUint (line 327) | func (a *Args) SetUint(key string, value int) {
method SetUintBytes (line 333) | func (a *Args) SetUintBytes(key []byte, value int) {
method GetUintOrZero (line 340) | func (a *Args) GetUintOrZero(key string) int {
method GetUfloat (line 349) | func (a *Args) GetUfloat(key string) (float64, error) {
method GetUfloatOrZero (line 360) | func (a *Args) GetUfloatOrZero(key string) float64 {
method GetBool (line 372) | func (a *Args) GetBool(key string) bool {
type argsKV (line 52) | type argsKV struct
function copyArgs (line 384) | func copyArgs(dst, src []argsKV) []argsKV {
function delAllArgsStable (line 413) | func delAllArgsStable(args []argsKV, key string) []argsKV {
function delAllArgs (line 428) | func delAllArgs(args []argsKV, key string) []argsKV {
function setArgBytes (line 440) | func setArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
function setArg (line 444) | func setArg(h []argsKV, key, value string, noValue bool) []argsKV {
function appendArgBytes (line 461) | func appendArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
function appendArg (line 465) | func appendArg(args []argsKV, key, value string, noValue bool) []argsKV {
function allocArg (line 478) | func allocArg(h []argsKV) ([]argsKV, *argsKV) {
function releaseArg (line 490) | func releaseArg(h []argsKV) []argsKV {
function hasArg (line 494) | func hasArg(h []argsKV, key string) bool {
function peekArgBytes (line 504) | func peekArgBytes(h []argsKV, k []byte) []byte {
function peekArgStr (line 514) | func peekArgStr(h []argsKV, k string) []byte {
type argsScanner (line 524) | type argsScanner struct
method next (line 528) | func (s *argsScanner) next(kv *argsKV) bool {
function decodeArgAppend (line 568) | func decodeArgAppend(dst, src []byte) []byte {
function decodeArgAppendNoPlus (line 620) | func decodeArgAppendNoPlus(dst, src []byte) []byte {
function peekAllArgBytesToDst (line 650) | func peekAllArgBytesToDst(dst [][]byte, h []argsKV, k []byte) [][]byte {
FILE: args_test.go
function TestDecodeArgAppend (line 15) | func TestDecodeArgAppend(t *testing.T) {
function testDecodeArgAppend (line 31) | func testDecodeArgAppend(t *testing.T, s, expectedResult string) {
function TestArgsAdd (line 38) | func TestArgsAdd(t *testing.T) {
function TestArgsSortKeys (line 104) | func TestArgsSortKeys(t *testing.T) {
function TestArgsAcquireReleaseSequential (line 120) | func TestArgsAcquireReleaseSequential(t *testing.T) {
function TestArgsAcquireReleaseConcurrent (line 124) | func TestArgsAcquireReleaseConcurrent(t *testing.T) {
function testArgsAcquireRelease (line 141) | func testArgsAcquireRelease(t *testing.T) {
function TestArgsPeekMulti (line 166) | func TestArgsPeekMulti(t *testing.T) {
function TestArgsEscape (line 194) | func TestArgsEscape(t *testing.T) {
function testArgsEscape (line 210) | func testArgsEscape(t *testing.T, k, v, expectedS string) {
function TestPathEscape (line 219) | func TestPathEscape(t *testing.T) {
function testPathEscape (line 236) | func testPathEscape(t *testing.T, s string) {
function TestArgsWriteTo (line 245) | func TestArgsWriteTo(t *testing.T) {
function TestArgsGetBool (line 267) | func TestArgsGetBool(t *testing.T) {
function testArgsGetBool (line 282) | func testArgsGetBool(t *testing.T, value string, expectedResult bool) {
function TestArgsUint (line 292) | func TestArgsUint(t *testing.T) {
function TestArgsCopyTo (line 327) | func TestArgsCopyTo(t *testing.T) {
function testCopyTo (line 346) | func testCopyTo(t *testing.T, a *Args) {
function TestArgsVisitAll (line 370) | func TestArgsVisitAll(t *testing.T) {
function TestArgsStringCompose (line 391) | func TestArgsStringCompose(t *testing.T) {
function TestArgsString (line 410) | func TestArgsString(t *testing.T) {
function testArgsString (line 424) | func testArgsString(t *testing.T, a *Args, s string) {
function TestArgsSetGetDel (line 432) | func TestArgsSetGetDel(t *testing.T) {
function TestArgsParse (line 499) | func TestArgsParse(t *testing.T) {
function TestArgsHas (line 547) | func TestArgsHas(t *testing.T) {
function testArgsHas (line 569) | func testArgsHas(t *testing.T, a *Args, s string, expectedKeys ...string) {
function testArgsHasNot (line 578) | func testArgsHasNot(t *testing.T, a *Args, s string, unexpectedKeys ...s...
function testArgsParse (line 587) | func testArgsParse(t *testing.T, a *Args, s string, expectedLen int, exp...
function TestArgsDeleteAll (line 603) | func TestArgsDeleteAll(t *testing.T) {
function TestIssue932 (line 617) | func TestIssue932(t *testing.T) {
FILE: args_timing_test.go
function BenchmarkArgsParse (line 8) | func BenchmarkArgsParse(b *testing.B) {
function BenchmarkArgsPeek (line 18) | func BenchmarkArgsPeek(b *testing.B) {
FILE: b2s.go
function b2s (line 7) | func b2s(b []byte) string {
FILE: brotli.go
constant CompressBrotliNoCompression (line 16) | CompressBrotliNoCompression = 0
constant CompressBrotliBestSpeed (line 17) | CompressBrotliBestSpeed = brotli.BestSpeed
constant CompressBrotliBestCompression (line 18) | CompressBrotliBestCompression = brotli.BestCompression
constant CompressBrotliDefaultCompression (line 23) | CompressBrotliDefaultCompression = 4
function acquireBrotliReader (line 26) | func acquireBrotliReader(r io.Reader) (*brotli.Reader, error) {
function releaseBrotliReader (line 38) | func releaseBrotliReader(zr *brotli.Reader) {
function acquireStacklessBrotliWriter (line 44) | func acquireStacklessBrotliWriter(w io.Writer, level int) stackless.Writ...
function releaseStacklessBrotliWriter (line 58) | func releaseStacklessBrotliWriter(sw stackless.Writer, level int) {
function acquireRealBrotliWriter (line 65) | func acquireRealBrotliWriter(w io.Writer, level int) *brotli.Writer {
function releaseRealBrotliWriter (line 78) | func releaseRealBrotliWriter(zw *brotli.Writer, level int) {
function AppendBrotliBytesLevel (line 99) | func AppendBrotliBytesLevel(dst, src []byte, level int) []byte {
function WriteBrotliLevel (line 114) | func WriteBrotliLevel(w io.Writer, p []byte, level int) (int, error) {
function stacklessWriteBrotli (line 140) | func stacklessWriteBrotli(ctx any) {
function nonblockingWriteBrotli (line 147) | func nonblockingWriteBrotli(ctxv any) {
function WriteBrotli (line 158) | func WriteBrotli(w io.Writer, p []byte) (int, error) {
function AppendBrotliBytes (line 163) | func AppendBrotliBytes(dst, src []byte) []byte {
function WriteUnbrotli (line 169) | func WriteUnbrotli(w io.Writer, p []byte) (int, error) {
function writeUnbrotli (line 173) | func writeUnbrotli(w io.Writer, p []byte, maxBodySize int) (int, error) {
function AppendUnbrotliBytes (line 189) | func AppendUnbrotliBytes(dst, src []byte) ([]byte, error) {
function normalizeBrotliCompressLevel (line 197) | func normalizeBrotliCompressLevel(level int) int {
FILE: brotli_test.go
function TestBrotliBytesSerial (line 11) | func TestBrotliBytesSerial(t *testing.T) {
function TestBrotliBytesConcurrent (line 19) | func TestBrotliBytesConcurrent(t *testing.T) {
function testBrotliBytes (line 27) | func testBrotliBytes() error {
function testBrotliBytesSingleCase (line 36) | func testBrotliBytesSingleCase(s string) error {
function TestBrotliCompressSerial (line 57) | func TestBrotliCompressSerial(t *testing.T) {
function TestBrotliCompressConcurrent (line 65) | func TestBrotliCompressConcurrent(t *testing.T) {
function testBrotliCompress (line 73) | func testBrotliCompress() error {
function testBrotliCompressSingleCase (line 82) | func testBrotliCompressSingleCase(s string) error {
function TestCompressHandlerBrotliLevel (line 105) | func TestCompressHandlerBrotliLevel(t *testing.T) {
FILE: bytesconv.go
function AppendHTMLEscape (line 18) | func AppendHTMLEscape(dst []byte, s string) []byte {
function AppendHTMLEscapeBytes (line 49) | func AppendHTMLEscapeBytes(dst, s []byte) []byte {
function AppendIPv4 (line 55) | func AppendIPv4(dst []byte, ip net.IP) []byte {
function ParseIPv4 (line 72) | func ParseIPv4(dst net.IP, ipStr []byte) (net.IP, error) {
function AppendHTTPDate (line 112) | func AppendHTTPDate(dst []byte, date time.Time) []byte {
function ParseHTTPDate (line 119) | func ParseHTTPDate(date []byte) (time.Time, error) {
function AppendUint (line 124) | func AppendUint(dst []byte, n int) []byte {
function ParseUint (line 134) | func ParseUint(buf []byte) (int, error) {
function parseUintBuf (line 150) | func parseUintBuf(b []byte) (int, int, error) {
function parseIPv4Octet (line 175) | func parseIPv4Octet(b []byte) (byte, int, error) {
function ParseUfloat (line 203) | func ParseUfloat(buf []byte) (float64, error) {
function readHexInt (line 222) | func readHexInt(r *bufio.Reader) (int, error) {
function writeHexInt (line 252) | func writeHexInt(w *bufio.Writer, n int) error {
constant upperhex (line 278) | upperhex = "0123456789ABCDEF"
constant lowerhex (line 279) | lowerhex = "0123456789abcdef"
function lowercaseBytes (line 282) | func lowercaseBytes(b []byte) {
function AppendUnquotedArg (line 292) | func AppendUnquotedArg(dst, src []byte) []byte {
function AppendQuotedArg (line 297) | func AppendQuotedArg(dst, src []byte) []byte {
function appendQuotedPath (line 311) | func appendQuotedPath(dst, src []byte) []byte {
FILE: bytesconv_32.go
constant maxHexIntChars (line 6) | maxHexIntChars = 7
FILE: bytesconv_32_test.go
function TestWriteHexInt (line 9) | func TestWriteHexInt(t *testing.T) {
function TestAppendUint (line 18) | func TestAppendUint(t *testing.T) {
function TestReadHexIntSuccess (line 30) | func TestReadHexIntSuccess(t *testing.T) {
function TestParseUintError32 (line 41) | func TestParseUintError32(t *testing.T) {
function TestParseUintSuccess (line 50) | func TestParseUintSuccess(t *testing.T) {
FILE: bytesconv_64.go
constant maxHexIntChars (line 6) | maxHexIntChars = 15
FILE: bytesconv_64_test.go
function TestWriteHexInt (line 9) | func TestWriteHexInt(t *testing.T) {
function TestAppendUint (line 18) | func TestAppendUint(t *testing.T) {
function TestReadHexIntSuccess (line 30) | func TestReadHexIntSuccess(t *testing.T) {
function TestParseUintError64 (line 42) | func TestParseUintError64(t *testing.T) {
function TestParseUintSuccess (line 51) | func TestParseUintSuccess(t *testing.T) {
FILE: bytesconv_table.go
constant hex2intTable (line 6) | hex2intTable = "\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10...
constant toLowerTable (line 7) | toLowerTable = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x...
constant toUpperTable (line 8) | toUpperTable = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x...
constant quotedArgShouldEscapeTable (line 9) | quotedArgShouldEscapeTable = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x...
constant quotedPathShouldEscapeTable (line 10) | quotedPathShouldEscapeTable = "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\...
constant validHeaderFieldByteTable (line 11) | validHeaderFieldByteTable = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0...
constant validHeaderValueByteTable (line 12) | validHeaderValueByteTable = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x0...
constant validMethodValueByteTable (line 13) | validMethodValueByteTable = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0...
FILE: bytesconv_table_gen.go
constant toLower (line 13) | toLower = 'a' - 'A'
function main (line 16) | func main() {
constant pre (line 259) | pre = `package fasthttp
FILE: bytesconv_test.go
function TestAppendQuotedArg (line 16) | func TestAppendQuotedArg(t *testing.T) {
function TestAppendHTMLEscape (line 31) | func TestAppendHTMLEscape(t *testing.T) {
function testAppendHTMLEscape (line 52) | func testAppendHTMLEscape(t *testing.T, s, expectedS string) {
function TestParseIPv4 (line 59) | func TestParseIPv4(t *testing.T) {
function testParseIPv4 (line 81) | func testParseIPv4(t *testing.T, dst net.IP, ipStr string, isValid bool) {
function TestAppendIPv4 (line 96) | func TestAppendIPv4(t *testing.T) {
function testAppendIPv4 (line 108) | func testAppendIPv4(t *testing.T, ipStr string, isValid bool) {
function testAppendUint (line 126) | func testAppendUint(t *testing.T, n int) {
function testWriteHexInt (line 134) | func testWriteHexInt(t *testing.T, n int, expectedS string) {
function TestReadHexIntError (line 149) | func TestReadHexIntError(t *testing.T) {
function testReadHexIntError (line 158) | func testReadHexIntError(t *testing.T, s string) {
function testReadHexIntSuccess (line 170) | func testReadHexIntSuccess(t *testing.T, s string, expectedN int) {
function TestAppendHTTPDate (line 182) | func TestAppendHTTPDate(t *testing.T) {
function TestParseUintError (line 203) | func TestParseUintError(t *testing.T) {
function TestParseUfloatSuccess (line 226) | func TestParseUfloatSuccess(t *testing.T) {
function TestParseUfloatError (line 245) | func TestParseUfloatError(t *testing.T) {
function testParseUfloatError (line 278) | func testParseUfloatError(t *testing.T, s string) {
function testParseUfloatSuccess (line 288) | func testParseUfloatSuccess(t *testing.T, s string, expectedF float64) {
function testParseUintError (line 302) | func testParseUintError(t *testing.T, s string) {
function testParseUintSuccess (line 312) | func testParseUintSuccess(t *testing.T, s string, expectedN int) {
function TestAppendUnquotedArg (line 322) | func TestAppendUnquotedArg(t *testing.T) {
function testAppendUnquotedArg (line 331) | func testAppendUnquotedArg(t *testing.T, s, expectedS string) {
FILE: bytesconv_timing_test.go
function BenchmarkAppendHTMLEscape (line 12) | func BenchmarkAppendHTMLEscape(b *testing.B) {
function BenchmarkHTMLEscapeString (line 28) | func BenchmarkHTMLEscapeString(b *testing.B) {
function BenchmarkParseIPv4 (line 44) | func BenchmarkParseIPv4(b *testing.B) {
function BenchmarkAppendIPv4 (line 58) | func BenchmarkAppendIPv4(b *testing.B) {
function BenchmarkWriteHexInt (line 68) | func BenchmarkWriteHexInt(b *testing.B) {
function BenchmarkParseUint (line 85) | func BenchmarkParseUint(b *testing.B) {
function BenchmarkAppendUint (line 100) | func BenchmarkAppendUint(b *testing.B) {
function BenchmarkLowercaseBytesNoop (line 114) | func BenchmarkLowercaseBytesNoop(b *testing.B) {
function BenchmarkLowercaseBytesAll (line 125) | func BenchmarkLowercaseBytesAll(b *testing.B) {
function BenchmarkLowercaseBytesMixed (line 136) | func BenchmarkLowercaseBytesMixed(b *testing.B) {
function BenchmarkAppendUnquotedArgFastPath (line 147) | func BenchmarkAppendUnquotedArgFastPath(b *testing.B) {
function BenchmarkAppendUnquotedArgSlowPath (line 157) | func BenchmarkAppendUnquotedArgSlowPath(b *testing.B) {
function BenchmarkParseUfloat (line 167) | func BenchmarkParseUfloat(b *testing.B) {
FILE: client.go
function Do (line 36) | func Do(req *Request, resp *Response) error {
function DoTimeout (line 63) | func DoTimeout(req *Request, resp *Response, timeout time.Duration) error {
function DoDeadline (line 90) | func DoDeadline(req *Request, resp *Response, deadline time.Time) error {
function DoRedirects (line 113) | func DoRedirects(req *Request, resp *Response, maxRedirectsCount int) er...
function Get (line 127) | func Get(dst []byte, url string) (statusCode int, body []byte, err error) {
function GetTimeout (line 140) | func GetTimeout(dst []byte, url string, timeout time.Duration) (statusCo...
function GetDeadline (line 153) | func GetDeadline(dst []byte, url string, deadline time.Time) (statusCode...
function Post (line 165) | func Post(dst []byte, url string, postArgs *Args) (statusCode int, body ...
type Client (line 178) | type Client struct
method Get (line 341) | func (c *Client) Get(dst []byte, url string) (statusCode int, body []b...
method GetTimeout (line 354) | func (c *Client) GetTimeout(dst []byte, url string, timeout time.Durat...
method GetDeadline (line 367) | func (c *Client) GetDeadline(dst []byte, url string, deadline time.Tim...
method Post (line 379) | func (c *Client) Post(dst []byte, url string, postArgs *Args) (statusC...
method DoTimeout (line 407) | func (c *Client) DoTimeout(req *Request, resp *Response, timeout time....
method DoDeadline (line 439) | func (c *Client) DoDeadline(req *Request, resp *Response, deadline tim...
method DoRedirects (line 466) | func (c *Client) DoRedirects(req *Request, resp *Response, maxRedirect...
method Do (line 493) | func (c *Client) Do(req *Request, resp *Response) error {
method hostClient (line 526) | func (c *Client) hostClient(host []byte, isTLS bool) (*HostClient, err...
method CloseIdleConnections (line 591) | func (c *Client) CloseIdleConnections() {
method mCleaner (line 602) | func (c *Client) mCleaner(m map[string]*HostClient) {
constant DefaultMaxConnsPerHost (line 636) | DefaultMaxConnsPerHost = 512
constant DefaultMaxIdleConnDuration (line 640) | DefaultMaxIdleConnDuration = 10 * time.Second
constant DefaultMaxIdemponentCallAttempts (line 643) | DefaultMaxIdemponentCallAttempts = 5
type DialFunc (line 657) | type DialFunc
type DialFuncWithTimeout (line 672) | type DialFuncWithTimeout
type RetryIfFunc (line 676) | type RetryIfFunc
type RetryIfErrFunc (line 694) | type RetryIfErrFunc
type RoundTripper (line 697) | type RoundTripper interface
type ConnPoolStrategyType (line 702) | type ConnPoolStrategyType
constant FIFO (line 705) | FIFO ConnPoolStrategyType = iota
constant LIFO (line 706) | LIFO
type HostClient (line 719) | type HostClient struct
method LastUseTime (line 945) | func (c *HostClient) LastUseTime() time.Time {
method Get (line 956) | func (c *HostClient) Get(dst []byte, url string) (statusCode int, body...
method GetTimeout (line 969) | func (c *HostClient) GetTimeout(dst []byte, url string, timeout time.D...
method GetDeadline (line 982) | func (c *HostClient) GetDeadline(dst []byte, url string, deadline time...
method Post (line 994) | func (c *HostClient) Post(dst []byte, url string, postArgs *Args) (sta...
method DoTimeout (line 1268) | func (c *HostClient) DoTimeout(req *Request, resp *Response, timeout t...
method DoDeadline (line 1295) | func (c *HostClient) DoDeadline(req *Request, resp *Response, deadline...
method DoRedirects (line 1322) | func (c *HostClient) DoRedirects(req *Request, resp *Response, maxRedi...
method Do (line 1344) | func (c *HostClient) Do(req *Request, resp *Response) error {
method PendingRequests (line 1424) | func (c *HostClient) PendingRequests() int {
method do (line 1432) | func (c *HostClient) do(req *Request, resp *Response) (bool, error) {
method doNonNilReqResp (line 1441) | func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bo...
method transport (line 1489) | func (c *HostClient) transport() RoundTripper {
method SetMaxConns (line 1537) | func (c *HostClient) SetMaxConns(newMaxConns int) {
method AcquireConn (line 1543) | func (c *HostClient) AcquireConn(reqTimeout time.Duration, connectionC...
method queueForIdle (line 1645) | func (c *HostClient) queueForIdle(w *wantConn) {
method dialConnFor (line 1655) | func (c *HostClient) dialConnFor(w *wantConn) {
method CloseIdleConnections (line 1674) | func (c *HostClient) CloseIdleConnections() {
method connsCleaner (line 1688) | func (c *HostClient) connsCleaner() {
method CloseConn (line 1744) | func (c *HostClient) CloseConn(cc *clientConn) {
method decConnsCount (line 1750) | func (c *HostClient) decConnsCount() {
method ConnsCount (line 1778) | func (c *HostClient) ConnsCount() int {
method ReleaseConn (line 1804) | func (c *HostClient) ReleaseConn(cc *clientConn) {
method AcquireWriter (line 1842) | func (c *HostClient) AcquireWriter(conn net.Conn) *bufio.Writer {
method ReleaseWriter (line 1862) | func (c *HostClient) ReleaseWriter(bw *bufio.Writer) {
method AcquireReader (line 1870) | func (c *HostClient) AcquireReader(conn net.Conn) *bufio.Reader {
method ReleaseReader (line 1890) | func (c *HostClient) ReleaseReader(br *bufio.Reader) {
method nextAddr (line 1927) | func (c *HostClient) nextAddr() string {
method dialHostHard (line 1941) | func (c *HostClient) dialHostHard(dialTimeout time.Duration) (conn net...
method cachedTLSConfig (line 1975) | func (c *HostClient) cachedTLSConfig(addr string) *tls.Config {
type clientConn (line 920) | type clientConn struct
method Conn (line 928) | func (cc *clientConn) Conn() net.Conn {
method CreatedTime (line 933) | func (cc *clientConn) CreatedTime() time.Time {
method LastUseTime (line 938) | func (cc *clientConn) LastUseTime() time.Time {
type clientDoer (line 998) | type clientDoer interface
function clientGetURL (line 1002) | func clientGetURL(dst []byte, url string, c clientDoer) (statusCode int,...
function clientGetURLTimeout (line 1011) | func clientGetURLTimeout(dst []byte, url string, timeout time.Duration, ...
type clientURLResponse (line 1016) | type clientURLResponse struct
function clientGetURLDeadline (line 1022) | func clientGetURLDeadline(dst []byte, url string, deadline time.Time, c ...
function clientPostURL (line 1093) | func clientPostURL(dst []byte, url string, postArgs *Args, c clientDoer)...
constant defaultMaxRedirectsCount (line 1123) | defaultMaxRedirectsCount = 16
function doRequestFollowRedirectsBuffer (line 1125) | func doRequestFollowRedirectsBuffer(req *Request, dst []byte, url string...
function doRequestFollowRedirects (line 1142) | func doRequestFollowRedirects(
function getRedirectURL (line 1181) | func getRedirectURL(baseURL string, location []byte, disablePathNormaliz...
function StatusCodeIsRedirect (line 1192) | func StatusCodeIsRedirect(statusCode int) bool {
function AcquireRequest (line 1210) | func AcquireRequest() *Request {
function ReleaseRequest (line 1222) | func ReleaseRequest(req *Request) {
function AcquireResponse (line 1232) | func AcquireResponse() *Response {
function ReleaseResponse (line 1244) | func ReleaseResponse(resp *Response) {
function isIdempotent (line 1428) | func isIdempotent(req *Request) bool {
type timeoutError (line 1519) | type timeoutError struct
method Error (line 1521) | func (e *timeoutError) Error() string {
method Timeout (line 1529) | func (e *timeoutError) Timeout() bool {
function acquireClientConn (line 1785) | func acquireClientConn(conn net.Conn) *clientConn {
function releaseClientConn (line 1796) | func releaseClientConn(cc *clientConn) {
function newClientTLSConfig (line 1898) | func newClientTLSConfig(c *tls.Config, addr string) *tls.Config {
function tlsServerName (line 1916) | func tlsServerName(addr string) string {
function tlsClientHandshake (line 1997) | func tlsClientHandshake(rawConn net.Conn, tlsConfig *tls.Config, deadlin...
function dialAddr (line 2022) | func dialAddr(
function callDialFunc (line 2048) | func callDialFunc(
function AddMissingPort (line 2073) | func AddMissingPort(addr string, isTLS bool) string {
type wantConn (line 2107) | type wantConn struct
method waiting (line 2115) | func (w *wantConn) waiting() bool {
method tryDeliver (line 2125) | func (w *wantConn) tryDeliver(conn *clientConn, err error) bool {
method cancel (line 2143) | func (w *wantConn) cancel(c *HostClient, err error) {
type wantConnQueue (line 2162) | type wantConnQueue struct
method len (line 2185) | func (q *wantConnQueue) len() int {
method pushBack (line 2190) | func (q *wantConnQueue) pushBack(w *wantConn) {
method popFront (line 2195) | func (q *wantConnQueue) popFront() *wantConn {
method peekFront (line 2211) | func (q *wantConnQueue) peekFront() *wantConn {
method clearFront (line 2223) | func (q *wantConnQueue) clearFront() (cleaned bool) {
type PipelineClient (line 2247) | type PipelineClient struct
method DoTimeout (line 2422) | func (c *PipelineClient) DoTimeout(req *Request, resp *Response, timeo...
method DoDeadline (line 2441) | func (c *PipelineClient) DoDeadline(req *Request, resp *Response, dead...
method Do (line 2553) | func (c *PipelineClient) Do(req *Request, resp *Response) error {
method getConnClient (line 2612) | func (c *PipelineClient) getConnClient() *pipelineConnClient {
method getConnClientUnlocked (line 2619) | func (c *PipelineClient) getConnClientUnlocked() *pipelineConnClient {
method newConnClient (line 2652) | func (c *PipelineClient) newConnClient() *pipelineConnClient {
method PendingRequests (line 2949) | func (c *PipelineClient) PendingRequests() int {
type pipelineConnClient (line 2362) | type pipelineConnClient struct
method DoDeadline (line 2445) | func (c *pipelineConnClient) DoDeadline(req *Request, resp *Response, ...
method acquirePipelineWork (line 2508) | func (c *pipelineConnClient) acquirePipelineWork(timeout time.Duration...
method releasePipelineWork (line 2530) | func (c *pipelineConnClient) releasePipelineWork(w *pipelineWork) {
method Do (line 2557) | func (c *pipelineConnClient) Do(req *Request, resp *Response) error {
method init (line 2684) | func (c *pipelineConnClient) init() {
method worker (line 2723) | func (c *pipelineConnClient) worker() error {
method cachedTLSConfig (line 2764) | func (c *pipelineConnClient) cachedTLSConfig() *tls.Config {
method writer (line 2780) | func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struc...
method reader (line 2887) | func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struc...
method logger (line 2933) | func (c *pipelineConnClient) logger() Logger {
method PendingRequests (line 2959) | func (c *pipelineConnClient) PendingRequests() int {
type pipelineWork (line 2396) | type pipelineWork struct
constant DefaultMaxPendingRequests (line 2682) | DefaultMaxPendingRequests = 1024
type transport (line 2972) | type transport struct
method RoundTrip (line 2974) | func (t *transport) RoundTrip(hc *HostClient, req *Request, resp *Resp...
FILE: client_example_test.go
function ExampleHostClient (line 9) | func ExampleHostClient() {
function useResponseBody (line 37) | func useResponseBody(body []byte) {
FILE: client_test.go
function TestCloseIdleConnections (line 27) | func TestCloseIdleConnections(t *testing.T) {
function TestPipelineClientSetUserAgent (line 77) | func TestPipelineClientSetUserAgent(t *testing.T) {
function TestPipelineClientSetUserAgentTimeout (line 83) | func TestPipelineClientSetUserAgentTimeout(t *testing.T) {
function testPipelineClientSetUserAgent (line 89) | func testPipelineClientSetUserAgent(t *testing.T, timeout time.Duration) {
function TestHostClientNegativeTimeout (line 127) | func TestHostClientNegativeTimeout(t *testing.T) {
function TestDoDeadlineRetry (line 153) | func TestDoDeadlineRetry(t *testing.T) {
function TestPipelineClientIssue832 (line 197) | func TestPipelineClientIssue832(t *testing.T) {
function TestClientInvalidURI (line 252) | func TestClientInvalidURI(t *testing.T) {
function TestClientGetWithBody (line 284) | func TestClientGetWithBody(t *testing.T) {
function TestClientURLAuth (line 317) | func TestClientURLAuth(t *testing.T) {
function TestClientNilResp (line 357) | func TestClientNilResp(t *testing.T) {
function TestClientNegativeTimeout (line 383) | func TestClientNegativeTimeout(t *testing.T) {
function TestPipelineClientNilResp (line 409) | func TestPipelineClientNilResp(t *testing.T) {
function TestClientParseConn (line 437) | func TestClientParseConn(t *testing.T) {
function TestClientPostArgs (line 471) | func TestClientPostArgs(t *testing.T) {
function TestClientRedirectSameSchema (line 509) | func TestClientRedirectSameSchema(t *testing.T) {
function TestClientRedirectClientChangingSchemaHttp2Https (line 552) | func TestClientRedirectClientChangingSchemaHttp2Https(t *testing.T) {
function TestClientRedirectHostClientChangingSchemaHttp2Https (line 587) | func TestClientRedirectHostClientChangingSchemaHttp2Https(t *testing.T) {
function testClientRedirectListener (line 623) | func testClientRedirectListener(t *testing.T, isTLS bool) net.Listener {
function testClientRedirectChangingSchemaServer (line 654) | func testClientRedirectChangingSchemaServer(t *testing.T, https, http ne...
function TestClientHeaderCase (line 688) | func TestClientHeaderCase(t *testing.T) {
function TestClientReadTimeout (line 730) | func TestClientReadTimeout(t *testing.T) {
function TestClientDefaultUserAgent (line 802) | func TestClientDefaultUserAgent(t *testing.T) {
function TestClientSetUserAgent (line 834) | func TestClientSetUserAgent(t *testing.T) {
function TestClientNoUserAgent (line 868) | func TestClientNoUserAgent(t *testing.T) {
function TestClientDoWithCustomHeaders (line 899) | func TestClientDoWithCustomHeaders(t *testing.T) {
function TestPipelineClientDoSerial (line 996) | func TestPipelineClientDoSerial(t *testing.T) {
function TestPipelineClientDoConcurrent (line 1002) | func TestPipelineClientDoConcurrent(t *testing.T) {
function TestPipelineClientDoBatchDelayConcurrent (line 1008) | func TestPipelineClientDoBatchDelayConcurrent(t *testing.T) {
function TestPipelineClientDoBatchDelayConcurrentMultiConn (line 1014) | func TestPipelineClientDoBatchDelayConcurrentMultiConn(t *testing.T) {
function testPipelineClientDoConcurrent (line 1020) | func testPipelineClientDoConcurrent(t *testing.T, concurrency int, maxBa...
function testPipelineClientDo (line 1077) | func testPipelineClientDo(t *testing.T, c *PipelineClient) {
function TestPipelineClientDoDisableHeaderNamesNormalizing (line 1112) | func TestPipelineClientDoDisableHeaderNamesNormalizing(t *testing.T) {
function TestPipelineClientDoTimeoutDisableHeaderNamesNormalizing (line 1118) | func TestPipelineClientDoTimeoutDisableHeaderNamesNormalizing(t *testing...
function testPipelineClientDisableHeaderNamesNormalizing (line 1124) | func testPipelineClientDisableHeaderNamesNormalizing(t *testing.T, timeo...
function TestClientDoTimeoutDisableHeaderNamesNormalizing (line 1182) | func TestClientDoTimeoutDisableHeaderNamesNormalizing(t *testing.T) {
function TestClientDoTimeoutDisablePathNormalizing (line 1236) | func TestClientDoTimeoutDisablePathNormalizing(t *testing.T) {
function TestHostClientPendingRequests (line 1289) | func TestHostClientPendingRequests(t *testing.T) {
function TestHostClientMaxConnsWithDeadline (line 1385) | func TestHostClientMaxConnsWithDeadline(t *testing.T) {
function TestHostClientMaxConnDuration (line 1468) | func TestHostClientMaxConnDuration(t *testing.T) {
function TestHostClientMultipleAddrs (line 1526) | func TestHostClientMultipleAddrs(t *testing.T) {
function TestClientFollowRedirects (line 1586) | func TestClientFollowRedirects(t *testing.T) {
function TestClientGetTimeoutSuccess (line 1764) | func TestClientGetTimeoutSuccess(t *testing.T) {
function TestClientGetTimeoutSuccessConcurrent (line 1773) | func TestClientGetTimeoutSuccessConcurrent(t *testing.T) {
function TestClientDoTimeoutSuccess (line 1790) | func TestClientDoTimeoutSuccess(t *testing.T) {
function TestClientDoTimeoutSuccessConcurrent (line 1800) | func TestClientDoTimeoutSuccessConcurrent(t *testing.T) {
function TestClientGetTimeoutError (line 1818) | func TestClientGetTimeoutError(t *testing.T) {
function TestClientGetTimeoutErrorConcurrent (line 1834) | func TestClientGetTimeoutErrorConcurrent(t *testing.T) {
function TestClientDoTimeoutError (line 1859) | func TestClientDoTimeoutError(t *testing.T) {
function TestClientDoTimeoutErrorConcurrent (line 1876) | func TestClientDoTimeoutErrorConcurrent(t *testing.T) {
function testClientDoTimeoutError (line 1901) | func testClientDoTimeoutError(t *testing.T, c *Client, n int) {
function testClientGetTimeoutError (line 1916) | func testClientGetTimeoutError(t *testing.T, c *Client, n int) {
function testClientRequestSetTimeoutError (line 1932) | func testClientRequestSetTimeoutError(t *testing.T, c *Client, n int) {
type readTimeoutConn (line 1948) | type readTimeoutConn struct
method Read (line 1956) | func (r *readTimeoutConn) Read(p []byte) (int, error) {
method Write (line 1961) | func (r *readTimeoutConn) Write(p []byte) (int, error) {
method Close (line 1966) | func (r *readTimeoutConn) Close() error {
method LocalAddr (line 1970) | func (r *readTimeoutConn) LocalAddr() net.Addr {
method RemoteAddr (line 1974) | func (r *readTimeoutConn) RemoteAddr() net.Addr {
method SetReadDeadline (line 1978) | func (r *readTimeoutConn) SetReadDeadline(d time.Time) error {
method SetWriteDeadline (line 1987) | func (r *readTimeoutConn) SetWriteDeadline(d time.Time) error {
function TestClientNonIdempotentRetry_BodyStream (line 1996) | func TestClientNonIdempotentRetry_BodyStream(t *testing.T) {
function TestClientIdempotentRequest (line 2032) | func TestClientIdempotentRequest(t *testing.T) {
function TestClientRetryRequestWithCustomDecider (line 2087) | func TestClientRetryRequestWithCustomDecider(t *testing.T) {
type TransportDemo (line 2138) | type TransportDemo struct
method RoundTrip (line 2143) | func (t TransportDemo) RoundTrip(hc *HostClient, req *Request, res *Re...
function TestHostClientTransport (line 2154) | func TestHostClientTransport(t *testing.T) {
type writeErrorConn (line 2208) | type writeErrorConn struct
method Write (line 2212) | func (w *writeErrorConn) Write(p []byte) (int, error) {
method Close (line 2216) | func (w *writeErrorConn) Close() error {
method LocalAddr (line 2220) | func (w *writeErrorConn) LocalAddr() net.Addr {
method RemoteAddr (line 2224) | func (w *writeErrorConn) RemoteAddr() net.Addr {
method SetReadDeadline (line 2228) | func (w *writeErrorConn) SetReadDeadline(_ time.Time) error {
method SetWriteDeadline (line 2232) | func (w *writeErrorConn) SetWriteDeadline(_ time.Time) error {
type readErrorConn (line 2236) | type readErrorConn struct
method Read (line 2240) | func (r *readErrorConn) Read(p []byte) (int, error) {
method Write (line 2244) | func (r *readErrorConn) Write(p []byte) (int, error) {
method Close (line 2248) | func (r *readErrorConn) Close() error {
method LocalAddr (line 2252) | func (r *readErrorConn) LocalAddr() net.Addr {
method RemoteAddr (line 2256) | func (r *readErrorConn) RemoteAddr() net.Addr {
method SetReadDeadline (line 2260) | func (r *readErrorConn) SetReadDeadline(_ time.Time) error {
method SetWriteDeadline (line 2264) | func (r *readErrorConn) SetWriteDeadline(_ time.Time) error {
type singleReadConn (line 2268) | type singleReadConn struct
method Read (line 2275) | func (r *singleReadConn) Read(p []byte) (int, error) {
method Write (line 2284) | func (r *singleReadConn) Write(p []byte) (int, error) {
method Close (line 2288) | func (r *singleReadConn) Close() error {
method LocalAddr (line 2292) | func (r *singleReadConn) LocalAddr() net.Addr {
method RemoteAddr (line 2296) | func (r *singleReadConn) RemoteAddr() net.Addr {
method SetReadDeadline (line 2300) | func (r *singleReadConn) SetReadDeadline(_ time.Time) error {
method SetWriteDeadline (line 2304) | func (r *singleReadConn) SetWriteDeadline(_ time.Time) error {
type singleEchoConn (line 2308) | type singleEchoConn struct
method Read (line 2315) | func (r *singleEchoConn) Read(p []byte) (int, error) {
method Write (line 2324) | func (r *singleEchoConn) Write(p []byte) (int, error) {
method Close (line 2329) | func (r *singleEchoConn) Close() error {
method LocalAddr (line 2333) | func (r *singleEchoConn) LocalAddr() net.Addr {
method RemoteAddr (line 2337) | func (r *singleEchoConn) RemoteAddr() net.Addr {
method SetReadDeadline (line 2341) | func (r *singleEchoConn) SetReadDeadline(_ time.Time) error {
method SetWriteDeadline (line 2345) | func (r *singleEchoConn) SetWriteDeadline(_ time.Time) error {
function TestSingleEchoConn (line 2349) | func TestSingleEchoConn(t *testing.T) {
function TestClientHTTPSInvalidServerName (line 2382) | func TestClientHTTPSInvalidServerName(t *testing.T) {
function TestClientHTTPSConcurrent (line 2398) | func TestClientHTTPSConcurrent(t *testing.T) {
function TestClientManyServers (line 2429) | func TestClientManyServers(t *testing.T) {
function TestClientGet (line 2452) | func TestClientGet(t *testing.T) {
function TestClientPost (line 2461) | func TestClientPost(t *testing.T) {
function TestClientConcurrent (line 2470) | func TestClientConcurrent(t *testing.T) {
function skipIfNotUnix (line 2489) | func skipIfNotUnix(tb testing.TB) {
function TestHostClientGet (line 2499) | func TestHostClientGet(t *testing.T) {
function TestHostClientPost (line 2511) | func TestHostClientPost(t *testing.T) {
function TestHostClientConcurrent (line 2523) | func TestHostClientConcurrent(t *testing.T) {
function testClientGet (line 2544) | func testClientGet(t *testing.T, c clientGetter, addr string, n int) {
function testClientDoTimeoutSuccess (line 2563) | func testClientDoTimeoutSuccess(t *testing.T, c *Client, addr string, n ...
function testClientRequestSetTimeoutSuccess (line 2586) | func testClientRequestSetTimeoutSuccess(t *testing.T, c *Client, addr st...
function testClientGetTimeoutSuccess (line 2610) | func testClientGetTimeoutSuccess(t *testing.T, c *Client, addr string, n...
function testClientPost (line 2632) | func testClientPost(t *testing.T, c clientPoster, addr string, n int) {
function testHostClientGet (line 2655) | func testHostClientGet(t *testing.T, c *HostClient, n int) {
function testHostClientPost (line 2659) | func testHostClientPost(t *testing.T, c *HostClient, n int) {
type clientPoster (line 2663) | type clientPoster interface
type clientGetter (line 2667) | type clientGetter interface
function createEchoClient (line 2671) | func createEchoClient(network, addr string) *HostClient {
type testEchoServer (line 2680) | type testEchoServer struct
method Stop (line 2687) | func (s *testEchoServer) Stop() {
method Addr (line 2696) | func (s *testEchoServer) Addr() string {
function startEchoServerTLS (line 2700) | func startEchoServerTLS(t *testing.T, network, addr string) *testEchoSer...
function startEchoServer (line 2704) | func startEchoServer(t *testing.T, network, addr string) *testEchoServer {
function startEchoServerExt (line 2708) | func startEchoServerExt(t *testing.T, network, addr string, isTLS bool) ...
function TestClientTLSHandshakeTimeout (line 2762) | func TestClientTLSHandshakeTimeout(t *testing.T) {
function TestClientConfigureClientFailed (line 2801) | func TestClientConfigureClientFailed(t *testing.T) {
function TestHostClientMaxConnWaitTimeoutSuccess (line 2830) | func TestHostClientMaxConnWaitTimeoutSuccess(t *testing.T) {
function TestHostClientMaxConnWaitTimeoutError (line 2908) | func TestHostClientMaxConnWaitTimeoutError(t *testing.T) {
function TestHostClientMaxConnWaitTimeoutWithEarlierDeadline (line 2997) | func TestHostClientMaxConnWaitTimeoutWithEarlierDeadline(t *testing.T) {
type TransportEmpty (line 3097) | type TransportEmpty struct
method RoundTrip (line 3099) | func (t TransportEmpty) RoundTrip(hc *HostClient, req *Request, res *R...
function TestHttpsRequestWithoutParsedURL (line 3103) | func TestHttpsRequestWithoutParsedURL(t *testing.T) {
function TestHostClientErrConnPoolStrategyNotImpl (line 3121) | func TestHostClientErrConnPoolStrategyNotImpl(t *testing.T) {
function Test_AddMissingPort (line 3162) | func Test_AddMissingPort(t *testing.T) {
type TransportWrapper (line 3224) | type TransportWrapper struct
method RoundTrip (line 3230) | func (tw *TransportWrapper) RoundTrip(hc *HostClient, req *Request, re...
method transport (line 3240) | func (tw *TransportWrapper) transport() RoundTripper {
method assertRequestLog (line 3247) | func (tw *TransportWrapper) assertRequestLog(reqLog string) {
method assertResponseLog (line 3253) | func (tw *TransportWrapper) assertResponseLog(respLog string) {
function TestClientTransportEx (line 3259) | func TestClientTransportEx(t *testing.T) {
function Test_getRedirectURL (line 3296) | func Test_getRedirectURL(t *testing.T) {
type clientDoTimeOuter (line 3353) | type clientDoTimeOuter interface
function TestDialTimeout (line 3357) | func TestDialTimeout(t *testing.T) {
function TestClientHeadWithBody (line 3444) | func TestClientHeadWithBody(t *testing.T) {
function TestRevertPull1233 (line 3493) | func TestRevertPull1233(t *testing.T) {
type F (line 3546) | type F struct
method Read (line 3550) | func (f F) Read(p []byte) (n int, err error) {
function TestTCPDialerFlushDNSCache (line 3560) | func TestTCPDialerFlushDNSCache(t *testing.T) {
type testResolver (line 3609) | type testResolver struct
method LookupIPAddr (line 3614) | func (r *testResolver) LookupIPAddr(ctx context.Context, host string) ...
FILE: client_timing_test.go
type fakeClientConn (line 19) | type fakeClientConn struct
method SetWriteDeadline (line 27) | func (c *fakeClientConn) SetWriteDeadline(t time.Time) error {
method SetReadDeadline (line 31) | func (c *fakeClientConn) SetReadDeadline(t time.Time) error {
method Write (line 35) | func (c *fakeClientConn) Write(b []byte) (int, error) {
method Read (line 40) | func (c *fakeClientConn) Read(b []byte) (int, error) {
method Close (line 58) | func (c *fakeClientConn) Close() error {
method LocalAddr (line 63) | func (c *fakeClientConn) LocalAddr() net.Addr {
method RemoteAddr (line 70) | func (c *fakeClientConn) RemoteAddr() net.Addr {
function releaseFakeServerConn (line 77) | func releaseFakeServerConn(c *fakeClientConn) {
function acquireFakeServerConn (line 82) | func acquireFakeServerConn(s []byte) *fakeClientConn {
function BenchmarkClientGetTimeoutFastServer (line 96) | func BenchmarkClientGetTimeoutFastServer(b *testing.B) {
function fasthttpEchoHandler (line 126) | func fasthttpEchoHandler(ctx *RequestCtx) {
function nethttpEchoHandler (line 130) | func nethttpEchoHandler(w http.ResponseWriter, r *http.Request) {
function BenchmarkClientGetEndToEnd1TCP (line 135) | func BenchmarkClientGetEndToEnd1TCP(b *testing.B) {
function BenchmarkClientGetEndToEnd10TCP (line 139) | func BenchmarkClientGetEndToEnd10TCP(b *testing.B) {
function BenchmarkClientGetEndToEnd100TCP (line 143) | func BenchmarkClientGetEndToEnd100TCP(b *testing.B) {
function benchmarkClientGetEndToEndTCP (line 147) | func benchmarkClientGetEndToEndTCP(b *testing.B, parallelism int) {
function BenchmarkNetHTTPClientGetEndToEnd1TCP (line 195) | func BenchmarkNetHTTPClientGetEndToEnd1TCP(b *testing.B) {
function BenchmarkNetHTTPClientGetEndToEnd10TCP (line 199) | func BenchmarkNetHTTPClientGetEndToEnd10TCP(b *testing.B) {
function BenchmarkNetHTTPClientGetEndToEnd100TCP (line 203) | func BenchmarkNetHTTPClientGetEndToEnd100TCP(b *testing.B) {
function benchmarkNetHTTPClientGetEndToEndTCP (line 207) | func benchmarkNetHTTPClientGetEndToEndTCP(b *testing.B, parallelism int) {
function BenchmarkClientGetEndToEnd1Inmemory (line 261) | func BenchmarkClientGetEndToEnd1Inmemory(b *testing.B) {
function BenchmarkClientGetEndToEnd10Inmemory (line 265) | func BenchmarkClientGetEndToEnd10Inmemory(b *testing.B) {
function BenchmarkClientGetEndToEnd100Inmemory (line 269) | func BenchmarkClientGetEndToEnd100Inmemory(b *testing.B) {
function BenchmarkClientGetEndToEnd1000Inmemory (line 273) | func BenchmarkClientGetEndToEnd1000Inmemory(b *testing.B) {
function BenchmarkClientGetEndToEnd10KInmemory (line 277) | func BenchmarkClientGetEndToEnd10KInmemory(b *testing.B) {
function benchmarkClientGetEndToEndInmemory (line 281) | func benchmarkClientGetEndToEndInmemory(b *testing.B, parallelism int) {
function BenchmarkNetHTTPClientGetEndToEnd1Inmemory (line 325) | func BenchmarkNetHTTPClientGetEndToEnd1Inmemory(b *testing.B) {
function BenchmarkNetHTTPClientGetEndToEnd10Inmemory (line 329) | func BenchmarkNetHTTPClientGetEndToEnd10Inmemory(b *testing.B) {
function BenchmarkNetHTTPClientGetEndToEnd100Inmemory (line 333) | func BenchmarkNetHTTPClientGetEndToEnd100Inmemory(b *testing.B) {
function BenchmarkNetHTTPClientGetEndToEnd1000Inmemory (line 337) | func BenchmarkNetHTTPClientGetEndToEnd1000Inmemory(b *testing.B) {
function benchmarkNetHTTPClientGetEndToEndInmemory (line 341) | func benchmarkNetHTTPClientGetEndToEndInmemory(b *testing.B, parallelism...
function BenchmarkClientEndToEndBigResponse1Inmemory (line 391) | func BenchmarkClientEndToEndBigResponse1Inmemory(b *testing.B) {
function BenchmarkClientEndToEndBigResponse10Inmemory (line 395) | func BenchmarkClientEndToEndBigResponse10Inmemory(b *testing.B) {
function benchmarkClientEndToEndBigResponseInmemory (line 399) | func benchmarkClientEndToEndBigResponseInmemory(b *testing.B, parallelis...
function BenchmarkNetHTTPClientEndToEndBigResponse1Inmemory (line 450) | func BenchmarkNetHTTPClientEndToEndBigResponse1Inmemory(b *testing.B) {
function BenchmarkNetHTTPClientEndToEndBigResponse10Inmemory (line 454) | func BenchmarkNetHTTPClientEndToEndBigResponse10Inmemory(b *testing.B) {
function benchmarkNetHTTPClientEndToEndBigResponseInmemory (line 458) | func benchmarkNetHTTPClientEndToEndBigResponseInmemory(b *testing.B, par...
function BenchmarkPipelineClient1 (line 518) | func BenchmarkPipelineClient1(b *testing.B) {
function BenchmarkPipelineClient10 (line 522) | func BenchmarkPipelineClient10(b *testing.B) {
function BenchmarkPipelineClient100 (line 526) | func BenchmarkPipelineClient100(b *testing.B) {
function BenchmarkPipelineClient1000 (line 530) | func BenchmarkPipelineClient1000(b *testing.B) {
function benchmarkPipelineClient (line 534) | func benchmarkPipelineClient(b *testing.B, parallelism int) {
FILE: coarsetime.go
function CoarseTimeNow (line 11) | func CoarseTimeNow() time.Time {
FILE: compress.go
constant CompressNoCompression (line 19) | CompressNoCompression = flate.NoCompression
constant CompressBestSpeed (line 20) | CompressBestSpeed = flate.BestSpeed
constant CompressBestCompression (line 21) | CompressBestCompression = flate.BestCompression
constant CompressDefaultCompression (line 22) | CompressDefaultCompression = 6
constant CompressHuffmanOnly (line 23) | CompressHuffmanOnly = -2
function acquireGzipReader (line 26) | func acquireGzipReader(r io.Reader) (*gzip.Reader, error) {
function releaseGzipReader (line 38) | func releaseGzipReader(zr *gzip.Reader) {
function acquireFlateReader (line 45) | func acquireFlateReader(r io.Reader) (io.ReadCloser, error) {
function releaseFlateReader (line 61) | func releaseFlateReader(zr io.ReadCloser) {
function resetFlateReader (line 66) | func resetFlateReader(zr io.ReadCloser, r io.Reader) error {
function acquireStacklessGzipWriter (line 77) | func acquireStacklessGzipWriter(w io.Writer, level int) stackless.Writer {
function releaseStacklessGzipWriter (line 91) | func releaseStacklessGzipWriter(sw stackless.Writer, level int) {
function acquireRealGzipWriter (line 98) | func acquireRealGzipWriter(w io.Writer, level int) *gzip.Writer {
function releaseRealGzipWriter (line 121) | func releaseRealGzipWriter(zw *gzip.Writer, level int) {
function AppendGzipBytesLevel (line 143) | func AppendGzipBytesLevel(dst, src []byte, level int) []byte {
function WriteGzipLevel (line 159) | func WriteGzipLevel(w io.Writer, p []byte, level int) (int, error) {
function stacklessWriteGzip (line 185) | func stacklessWriteGzip(ctx any) {
function nonblockingWriteGzip (line 192) | func nonblockingWriteGzip(ctxv any) {
function WriteGzip (line 203) | func WriteGzip(w io.Writer, p []byte) (int, error) {
function AppendGzipBytes (line 208) | func AppendGzipBytes(dst, src []byte) []byte {
function WriteGunzip (line 214) | func WriteGunzip(w io.Writer, p []byte) (int, error) {
function writeGunzip (line 218) | func writeGunzip(w io.Writer, p []byte, maxBodySize int) (int, error) {
function AppendGunzipBytes (line 234) | func AppendGunzipBytes(dst, src []byte) ([]byte, error) {
function AppendDeflateBytesLevel (line 250) | func AppendDeflateBytesLevel(dst, src []byte, level int) []byte {
function WriteDeflateLevel (line 266) | func WriteDeflateLevel(w io.Writer, p []byte, level int) (int, error) {
function stacklessWriteDeflate (line 292) | func stacklessWriteDeflate(ctx any) {
function nonblockingWriteDeflate (line 299) | func nonblockingWriteDeflate(ctxv any) {
type compressCtx (line 308) | type compressCtx struct
function WriteDeflate (line 316) | func WriteDeflate(w io.Writer, p []byte) (int, error) {
function AppendDeflateBytes (line 321) | func AppendDeflateBytes(dst, src []byte) []byte {
function WriteInflate (line 327) | func WriteInflate(w io.Writer, p []byte) (int, error) {
function writeInflate (line 331) | func writeInflate(w io.Writer, p []byte, maxBodySize int) (int, error) {
function AppendInflateBytes (line 347) | func AppendInflateBytes(dst, src []byte) ([]byte, error) {
type byteSliceWriter (line 353) | type byteSliceWriter struct
method Write (line 357) | func (w *byteSliceWriter) Write(p []byte) (int, error) {
method WriteString (line 362) | func (w *byteSliceWriter) WriteString(s string) (int, error) {
type byteSliceReader (line 367) | type byteSliceReader struct
method Read (line 371) | func (r *byteSliceReader) Read(p []byte) (int, error) {
method ReadByte (line 380) | func (r *byteSliceReader) ReadByte() (byte, error) {
function acquireStacklessDeflateWriter (line 389) | func acquireStacklessDeflateWriter(w io.Writer, level int) stackless.Wri...
function releaseStacklessDeflateWriter (line 403) | func releaseStacklessDeflateWriter(sw stackless.Writer, level int) {
function acquireRealDeflateWriter (line 410) | func acquireRealDeflateWriter(w io.Writer, level int) *zlib.Writer {
function releaseRealDeflateWriter (line 433) | func releaseRealDeflateWriter(zw *zlib.Writer, level int) {
function newCompressWriterPoolMap (line 445) | func newCompressWriterPoolMap() []*sync.Pool {
function isFileCompressible (line 457) | func isFileCompressible(f fs.File, minCompressRatio float64) bool {
function normalizeCompressLevel (line 486) | func normalizeCompressLevel(level int) int {
FILE: compress_test.go
function TestGzipBytesSerial (line 24) | func TestGzipBytesSerial(t *testing.T) {
function TestGzipBytesConcurrent (line 32) | func TestGzipBytesConcurrent(t *testing.T) {
function TestDeflateBytesSerial (line 40) | func TestDeflateBytesSerial(t *testing.T) {
function TestDeflateBytesConcurrent (line 48) | func TestDeflateBytesConcurrent(t *testing.T) {
function testGzipBytes (line 56) | func testGzipBytes() error {
function testDeflateBytes (line 65) | func testDeflateBytes() error {
function testGzipBytesSingleCase (line 74) | func testGzipBytesSingleCase(s string) error {
function testDeflateBytesSingleCase (line 95) | func testDeflateBytesSingleCase(s string) error {
function TestGzipCompressSerial (line 116) | func TestGzipCompressSerial(t *testing.T) {
function TestGzipCompressConcurrent (line 124) | func TestGzipCompressConcurrent(t *testing.T) {
function TestFlateCompressSerial (line 132) | func TestFlateCompressSerial(t *testing.T) {
function TestFlateCompressConcurrent (line 140) | func TestFlateCompressConcurrent(t *testing.T) {
function testGzipCompress (line 148) | func testGzipCompress() error {
function testFlateCompress (line 157) | func testFlateCompress() error {
function testGzipCompressSingleCase (line 166) | func testGzipCompressSingleCase(s string) error {
function testFlateCompressSingleCase (line 189) | func testFlateCompressSingleCase(s string) error {
function testConcurrent (line 212) | func testConcurrent(concurrency int, f func() error) error {
FILE: cookie.go
type CookieSameSite (line 23) | type CookieSameSite
constant CookieSameSiteDisabled (line 27) | CookieSameSiteDisabled CookieSameSite = iota
constant CookieSameSiteDefaultMode (line 29) | CookieSameSiteDefaultMode
constant CookieSameSiteLaxMode (line 31) | CookieSameSiteLaxMode
constant CookieSameSiteStrictMode (line 33) | CookieSameSiteStrictMode
constant CookieSameSiteNoneMode (line 36) | CookieSameSiteNoneMode
function AcquireCookie (line 43) | func AcquireCookie() *Cookie {
function ReleaseCookie (line 51) | func ReleaseCookie(c *Cookie) {
type Cookie (line 67) | type Cookie struct
method CopyTo (line 92) | func (c *Cookie) CopyTo(src *Cookie) {
method HTTPOnly (line 107) | func (c *Cookie) HTTPOnly() bool {
method SetHTTPOnly (line 112) | func (c *Cookie) SetHTTPOnly(httpOnly bool) {
method Secure (line 117) | func (c *Cookie) Secure() bool {
method SetSecure (line 122) | func (c *Cookie) SetSecure(secure bool) {
method SameSite (line 127) | func (c *Cookie) SameSite() CookieSameSite {
method SetSameSite (line 133) | func (c *Cookie) SetSameSite(mode CookieSameSite) {
method Partitioned (line 141) | func (c *Cookie) Partitioned() bool {
method SetPartitioned (line 147) | func (c *Cookie) SetPartitioned(partitioned bool) {
method Path (line 156) | func (c *Cookie) Path() []byte {
method SetPath (line 161) | func (c *Cookie) SetPath(path string) {
method SetPathBytes (line 167) | func (c *Cookie) SetPathBytes(path []byte) {
method Domain (line 176) | func (c *Cookie) Domain() []byte {
method SetDomain (line 181) | func (c *Cookie) SetDomain(domain string) {
method SetDomainBytes (line 186) | func (c *Cookie) SetDomainBytes(domain []byte) {
method MaxAge (line 192) | func (c *Cookie) MaxAge() int {
method SetMaxAge (line 203) | func (c *Cookie) SetMaxAge(seconds int) {
method Expire (line 210) | func (c *Cookie) Expire() time.Time {
method SetExpire (line 224) | func (c *Cookie) SetExpire(expire time.Time) {
method Value (line 232) | func (c *Cookie) Value() []byte {
method SetValue (line 237) | func (c *Cookie) SetValue(value string) {
method SetValueBytes (line 242) | func (c *Cookie) SetValueBytes(value []byte) {
method Key (line 250) | func (c *Cookie) Key() []byte {
method SetKey (line 255) | func (c *Cookie) SetKey(key string) {
method SetKeyBytes (line 260) | func (c *Cookie) SetKeyBytes(key []byte) {
method Reset (line 265) | func (c *Cookie) Reset() {
method AppendBytes (line 280) | func (c *Cookie) AppendBytes(dst []byte) []byte {
method Cookie (line 349) | func (c *Cookie) Cookie() []byte {
method String (line 355) | func (c *Cookie) String() string {
method WriteTo (line 362) | func (c *Cookie) WriteTo(w io.Writer) (int64, error) {
method Parse (line 370) | func (c *Cookie) Parse(src string) error {
method ParseBytes (line 376) | func (c *Cookie) ParseBytes(src []byte) error {
function appendCookiePart (line 472) | func appendCookiePart(dst, key, value []byte) []byte {
function getCookieKey (line 479) | func getCookieKey(dst, src []byte) []byte {
function appendRequestCookieBytes (line 487) | func appendRequestCookieBytes(dst []byte, cookies []argsKV) []byte {
function appendResponseCookieBytes (line 504) | func appendResponseCookieBytes(dst []byte, cookies []argsKV) []byte {
function parseRequestCookies (line 515) | func parseRequestCookies(cookies []argsKV, src []byte) []argsKV {
type cookieScanner (line 528) | type cookieScanner struct
method next (line 532) | func (s *cookieScanner) next(key, val *[]byte) bool {
function decodeCookieArg (line 566) | func decodeCookieArg(dst, src []byte, skipQuotes bool) []byte {
function caseInsensitiveCompare (line 583) | func caseInsensitiveCompare(a, b []byte) bool {
FILE: cookie_test.go
function TestCookiePanic (line 9) | func TestCookiePanic(t *testing.T) {
function TestCookieValueWithEqualAndSpaceChars (line 18) | func TestCookieValueWithEqualAndSpaceChars(t *testing.T) {
function testCookieValueWithEqualAndSpaceChars (line 26) | func testCookieValueWithEqualAndSpaceChars(t *testing.T, expectedName, e...
function TestCookieSecureHttpOnly (line 52) | func TestCookieSecureHttpOnly(t *testing.T) {
function TestCookieSecure (line 75) | func TestCookieSecure(t *testing.T) {
function TestCookieSameSite (line 103) | func TestCookieSameSite(t *testing.T) {
function TestCookieMaxAge (line 176) | func TestCookieMaxAge(t *testing.T) {
function TestCookieHttpOnly (line 225) | func TestCookieHttpOnly(t *testing.T) {
function TestCookiePartitioned (line 253) | func TestCookiePartitioned(t *testing.T) {
function TestCookieAcquireReleaseSequential (line 282) | func TestCookieAcquireReleaseSequential(t *testing.T) {
function TestCookieAcquireReleaseConcurrent (line 288) | func TestCookieAcquireReleaseConcurrent(t *testing.T) {
function testCookieAcquireRelease (line 307) | func testCookieAcquireRelease(t *testing.T) {
function TestCookieParse (line 344) | func TestCookieParse(t *testing.T) {
function testCookieParse (line 358) | func testCookieParse(t *testing.T, s, expectedS string) {
function TestCookieAppendBytes (line 369) | func TestCookieAppendBytes(t *testing.T) {
function testCookieAppendBytes (line 388) | func testCookieAppendBytes(t *testing.T, c *Cookie, key, value, expected...
function TestParseRequestCookies (line 397) | func TestParseRequestCookies(t *testing.T) {
function testParseRequestCookies (line 410) | func testParseRequestCookies(t *testing.T, s, expectedS string) {
function TestAppendRequestCookieBytes (line 418) | func TestAppendRequestCookieBytes(t *testing.T) {
function testAppendRequestCookieBytes (line 427) | func testAppendRequestCookieBytes(t *testing.T, s, expectedS string) {
FILE: cookie_timing_test.go
function BenchmarkCookieParseMin (line 7) | func BenchmarkCookieParseMin(b *testing.B) {
function BenchmarkCookieParseNoExpires (line 17) | func BenchmarkCookieParseNoExpires(b *testing.B) {
function BenchmarkCookieParseFull (line 27) | func BenchmarkCookieParseFull(b *testing.B) {
FILE: examples/host_client/hostclient.go
function main (line 10) | func main() {
FILE: examples/letsencrypt/letsencryptserver.go
function requestHandler (line 12) | func requestHandler(ctx *fasthttp.RequestCtx) {
function main (line 16) | func main() {
FILE: examples/multidomain/multidomain.go
function main (line 11) | func main() {
FILE: expvarhandler/expvar.go
function ExpvarHandler (line 25) | func ExpvarHandler(ctx *fasthttp.RequestCtx) {
function getExpvarRegexp (line 54) | func getExpvarRegexp(ctx *fasthttp.RequestCtx) (*regexp.Regexp, error) {
FILE: expvarhandler/expvar_test.go
function TestExpvarHandlerBasic (line 15) | func TestExpvarHandlerBasic(t *testing.T) {
function TestExpvarHandlerRegexp (line 65) | func TestExpvarHandlerRegexp(t *testing.T) {
FILE: fasthttpadaptor/adaptor.go
function NewFastHTTPHandlerFunc (line 33) | func NewFastHTTPHandlerFunc(h http.HandlerFunc) fasthttp.RequestHandler {
function NewFastHTTPHandler (line 53) | func NewFastHTTPHandler(h http.Handler) fasthttp.RequestHandler {
constant modeDone (line 193) | modeDone = iota + 1
constant modeFlushed (line 194) | modeFlushed
constant modeHijacked (line 195) | modeHijacked
constant modePanicked (line 196) | modePanicked
type writer (line 200) | type writer struct
method Header (line 243) | func (w *writer) Header() http.Header {
method WriteHeader (line 247) | func (w *writer) WriteHeader(code int) {
method Write (line 255) | func (w *writer) Write(p []byte) (int, error) {
method Flush (line 273) | func (w *writer) Flush() {
method Hijack (line 298) | func (w *writer) Hijack() (net.Conn, *bufio.ReadWriter, error) {
method Close (line 331) | func (w *writer) Close() error {
method status (line 340) | func (w *writer) status() int {
method consumePreflush (line 349) | func (w *writer) consumePreflush() []byte {
function acquireWriter (line 222) | func acquireWriter(ctx *fasthttp.RequestCtx) *writer {
function releaseWriter (line 235) | func releaseWriter(w *writer) {
type wrappedConn (line 283) | type wrappedConn struct
method Close (line 290) | func (c *wrappedConn) Close() (err error) {
FILE: fasthttpadaptor/adaptor_test.go
function TestNewFastHTTPHandler (line 20) | func TestNewFastHTTPHandler(t *testing.T) {
function TestNewFastHTTPHandlerWithCookies (line 150) | func TestNewFastHTTPHandlerWithCookies(t *testing.T) {
function setContextValueMiddleware (line 197) | func setContextValueMiddleware(next fasthttp.RequestHandler, key string,...
function TestHijack (line 204) | func TestHijack(t *testing.T) {
function TestFlushHandler (line 275) | func TestFlushHandler(t *testing.T) {
function TestFlushHandlerClosed (line 358) | func TestFlushHandlerClosed(t *testing.T) {
function TestHijackFlush (line 444) | func TestHijackFlush(t *testing.T) {
function TestResourceRecyclingUnderLoad_OneEndpoint (line 518) | func TestResourceRecyclingUnderLoad_OneEndpoint(t *testing.T) {
function TestResourceRecyclingUnderLoad_MultipleEndpoints (line 553) | func TestResourceRecyclingUnderLoad_MultipleEndpoints(t *testing.T) {
function sendRequest (line 646) | func sendRequest(ln *fasthttputil.InmemoryListener, req *http.Request, r...
function TestNewFastHTTPHandlerPanic (line 679) | func TestNewFastHTTPHandlerPanic(t *testing.T) {
FILE: fasthttpadaptor/b2s.go
function b2s (line 7) | func b2s(b []byte) string {
FILE: fasthttpadaptor/request.go
function ConvertRequest (line 18) | func ConvertRequest(ctx *fasthttp.RequestCtx, r *http.Request, forServer...
FILE: fasthttpadaptor/request_test.go
function BenchmarkConvertRequest (line 10) | func BenchmarkConvertRequest(b *testing.B) {
FILE: fasthttpproxy/dialer.go
type Dialer (line 27) | type Dialer struct
method GetDialFunc (line 74) | func (d *Dialer) GetDialFunc(useEnv bool) (fasthttp.DialFunc, error) {
method Dial (line 153) | func (d *Dialer) Dial(network, addr string) (net.Conn, error) {
method connectTimeout (line 170) | func (d *Dialer) connectTimeout() time.Duration {
type httpProxyDialer (line 177) | type httpProxyDialer interface
type DialerFunc (line 183) | type DialerFunc
method Dial (line 185) | func (d DialerFunc) Dial(network, addr string) (net.Conn, error) {
function httpProxyDial (line 190) | func httpProxyDial(dialer proxy.Dialer, network, addr, proxyAddr, auth s...
type proxyInfo (line 236) | type proxyInfo struct
function addrAndAuth (line 241) | func addrAndAuth(pu *url.URL, authCache *sync.Map) (proxyAddr, auth stri...
FILE: fasthttpproxy/dialer_test.go
function TestDialer_GetDialFunc (line 15) | func TestDialer_GetDialFunc(t *testing.T) {
function startProxyServer (line 242) | func startProxyServer(t *testing.T, ports []string, counts []atomic.Int6...
function getDialer (line 279) | func getDialer(httpProxy, httpsProxy, noProxy string) *Dialer {
function getCounts (line 289) | func getCounts(counts []atomic.Int64) (r []int64) {
function countsEqual (line 296) | func countsEqual(a, b []int64) bool {
FILE: fasthttpproxy/http.go
function FasthttpHTTPDialer (line 18) | func FasthttpHTTPDialer(proxy string) fasthttp.DialFunc {
function FasthttpHTTPDialerTimeout (line 31) | func FasthttpHTTPDialerTimeout(proxy string, timeout time.Duration) fast...
function FasthttpHTTPDialerDualStack (line 45) | func FasthttpHTTPDialerDualStack(proxy string) fasthttp.DialFunc {
function FasthttpHTTPDialerDualStackTimeout (line 58) | func FasthttpHTTPDialerDualStackTimeout(proxy string, timeout time.Durat...
FILE: fasthttpproxy/proxy_env.go
constant httpsScheme (line 10) | httpsScheme = "https"
constant httpScheme (line 11) | httpScheme = "http"
function FasthttpProxyHTTPDialer (line 22) | func FasthttpProxyHTTPDialer() fasthttp.DialFunc {
function FasthttpProxyHTTPDialerTimeout (line 35) | func FasthttpProxyHTTPDialerTimeout(timeout time.Duration) fasthttp.Dial...
FILE: fasthttpproxy/socks5.go
function FasthttpSocksDialer (line 16) | func FasthttpSocksDialer(proxyAddr string) fasthttp.DialFunc {
function FasthttpSocksDialerDualStack (line 30) | func FasthttpSocksDialerDualStack(proxyAddr string) fasthttp.DialFunc {
FILE: fasthttputil/inmemory_listener.go
type InmemoryListener (line 16) | type InmemoryListener struct
method SetLocalAddr (line 37) | func (ln *InmemoryListener) SetLocalAddr(localAddr net.Addr) {
method Accept (line 49) | func (ln *InmemoryListener) Accept() (net.Conn, error) {
method Close (line 59) | func (ln *InmemoryListener) Close() error {
method Addr (line 84) | func (ln *InmemoryListener) Addr() net.Addr {
method Dial (line 100) | func (ln *InmemoryListener) Dial() (net.Conn, error) {
method DialWithLocalAddr (line 110) | func (ln *InmemoryListener) DialWithLocalAddr(local net.Addr) (net.Con...
type acceptConn (line 24) | type acceptConn struct
function NewInmemoryListener (line 30) | func NewInmemoryListener() *InmemoryListener {
type inmemoryAddr (line 73) | type inmemoryAddr
method Network (line 75) | func (inmemoryAddr) Network() string {
method String (line 79) | func (inmemoryAddr) String() string {
FILE: fasthttputil/inmemory_listener_test.go
function TestInmemoryListener (line 15) | func TestInmemoryListener(t *testing.T) {
type echoServerHandler (line 100) | type echoServerHandler struct
method ServeHTTP (line 104) | func (s *echoServerHandler) ServeHTTP(w http.ResponseWriter, r *http.R...
function testInmemoryListenerHTTP (line 112) | func testInmemoryListenerHTTP(t *testing.T, f func(t *testing.T, client ...
function testInmemoryListenerHTTPSingle (line 142) | func testInmemoryListenerHTTPSingle(t *testing.T, client *http.Client, c...
function TestInmemoryListenerHTTPSingle (line 158) | func TestInmemoryListenerHTTPSingle(t *testing.T) {
function TestInmemoryListenerHTTPSerial (line 164) | func TestInmemoryListenerHTTPSerial(t *testing.T) {
function TestInmemoryListenerHTTPConcurrent (line 172) | func TestInmemoryListenerHTTPConcurrent(t *testing.T) {
function acceptLoop (line 186) | func acceptLoop(ln net.Listener) {
function TestInmemoryListenerAddrDefault (line 197) | func TestInmemoryListenerAddrDefault(t *testing.T) {
function verifyAddr (line 230) | func verifyAddr(t *testing.T, got, expected net.Addr) {
function TestInmemoryListenerAddrCustom (line 236) | func TestInmemoryListenerAddrCustom(t *testing.T) {
FILE: fasthttputil/inmemory_listener_timing_test.go
function BenchmarkPlainStreaming (line 65) | func BenchmarkPlainStreaming(b *testing.B) {
function BenchmarkPlainHandshake (line 73) | func BenchmarkPlainHandshake(b *testing.B) {
function BenchmarkTLSStreaming (line 81) | func BenchmarkTLSStreaming(b *testing.B) {
function benchmark (line 85) | func benchmark(b *testing.B, h fasthttp.RequestHandler, isTLS bool) {
function streamingHandler (line 128) | func streamingHandler(ctx *fasthttp.RequestCtx) {
function handshakeHandler (line 132) | func handshakeHandler(ctx *fasthttp.RequestCtx) {
function runRequests (line 139) | func runRequests(b *testing.B, pb *testing.PB, c *fasthttp.HostClient, i...
FILE: fasthttputil/pipeconns.go
function NewPipeConns (line 14) | func NewPipeConns() *PipeConns {
type PipeConns (line 44) | type PipeConns struct
method SetAddresses (line 52) | func (pc *PipeConns) SetAddresses(localAddr1, remoteAddr1, localAddr2,...
method Conn1 (line 70) | func (pc *PipeConns) Conn1() net.Conn {
method Conn2 (line 78) | func (pc *PipeConns) Conn2() net.Conn {
method Close (line 83) | func (pc *PipeConns) Close() error {
type pipeConn (line 95) | type pipeConn struct
method Write (line 117) | func (c *pipeConn) Write(p []byte) (int, error) {
method WriteString (line 145) | func (c *pipeConn) WriteString(s string) (int, error) {
method Read (line 149) | func (c *pipeConn) Read(p []byte) (int, error) {
method read (line 168) | func (c *pipeConn) read(p []byte, mayBlock bool) (int, error) {
method readNextByteBuffer (line 180) | func (c *pipeConn) readNextByteBuffer(mayBlock bool) error {
method Close (line 243) | func (c *pipeConn) Close() error {
method LocalAddr (line 247) | func (c *pipeConn) LocalAddr() net.Addr {
method RemoteAddr (line 258) | func (c *pipeConn) RemoteAddr() net.Addr {
method SetDeadline (line 269) | func (c *pipeConn) SetDeadline(deadline time.Time) error {
method SetReadDeadline (line 275) | func (c *pipeConn) SetReadDeadline(deadline time.Time) error {
method SetWriteDeadline (line 286) | func (c *pipeConn) SetWriteDeadline(deadline time.Time) error {
type timeoutError (line 226) | type timeoutError struct
method Error (line 228) | func (e *timeoutError) Error() string {
method Timeout (line 236) | func (e *timeoutError) Timeout() bool {
function updateTimer (line 294) | func updateTimer(t *time.Timer, deadline time.Time) <-chan time.Time {
type pipeAddr (line 318) | type pipeAddr
method Network (line 320) | func (pipeAddr) Network() string {
method String (line 324) | func (pipeAddr) String() string {
type byteBuffer (line 328) | type byteBuffer struct
function acquireByteBuffer (line 332) | func acquireByteBuffer() *byteBuffer {
function releaseByteBuffer (line 336) | func releaseByteBuffer(b *byteBuffer) {
FILE: fasthttputil/pipeconns_test.go
function TestPipeConnsWriteTimeout (line 12) | func TestPipeConnsWriteTimeout(t *testing.T) {
function TestPipeConnsPositiveReadTimeout (line 70) | func TestPipeConnsPositiveReadTimeout(t *testing.T) {
function TestPipeConnsNegativeReadTimeout (line 76) | func TestPipeConnsNegativeReadTimeout(t *testing.T) {
function testPipeConnsReadTimeout (line 84) | func testPipeConnsReadTimeout(t *testing.T, timeout time.Duration) {
function TestPipeConnsCloseWhileReadWriteConcurrent (line 123) | func TestPipeConnsCloseWhileReadWriteConcurrent(t *testing.T) {
function TestPipeConnsCloseWhileReadWriteSerial (line 144) | func TestPipeConnsCloseWhileReadWriteSerial(t *testing.T) {
function testPipeConnsCloseWhileReadWriteSerial (line 150) | func testPipeConnsCloseWhileReadWriteSerial(t *testing.T) {
function testPipeConnsCloseWhileReadWrite (line 156) | func testPipeConnsCloseWhileReadWrite(t *testing.T) {
function TestPipeConnsReadWriteSerial (line 216) | func TestPipeConnsReadWriteSerial(t *testing.T) {
function TestPipeConnsReadWriteConcurrent (line 222) | func TestPipeConnsReadWriteConcurrent(t *testing.T) {
function testPipeConnsReadWriteSerial (line 228) | func testPipeConnsReadWriteSerial(t *testing.T) {
function testPipeConnsReadWrite (line 236) | func testPipeConnsReadWrite(t *testing.T, c1, c2 net.Conn) {
function TestPipeConnsCloseSerial (line 277) | func TestPipeConnsCloseSerial(t *testing.T) {
function TestPipeConnsCloseConcurrent (line 283) | func TestPipeConnsCloseConcurrent(t *testing.T) {
function testPipeConnsCloseSerial (line 289) | func testPipeConnsCloseSerial(t *testing.T) {
function testPipeConnsClose (line 297) | func testPipeConnsClose(t *testing.T, c1, c2 net.Conn) {
function testConcurrency (line 343) | func testConcurrency(t *testing.T, concurrency int, f func(*testing.T)) {
function TestPipeConnsAddrDefault (line 361) | func TestPipeConnsAddrDefault(t *testing.T) {
function TestPipeConnsAddrCustom (line 376) | func TestPipeConnsAddrCustom(t *testing.T) {
FILE: fasthttputil/s2b.go
function s2b (line 6) | func s2b(s string) []byte {
FILE: fs.go
function ServeFileBytesUncompressed (line 40) | func ServeFileBytesUncompressed(ctx *RequestCtx, path []byte) {
function ServeFileUncompressed (line 57) | func ServeFileUncompressed(ctx *RequestCtx, path string) {
function ServeFileBytes (line 80) | func ServeFileBytes(ctx *RequestCtx, path []byte) {
function ServeFile (line 101) | func ServeFile(ctx *RequestCtx, path string) {
function ServeFS (line 154) | func ServeFS(ctx *RequestCtx, filesystem fs.FS, path string) {
type PathRewriteFunc (line 181) | type PathRewriteFunc
function NewVHostPathRewriter (line 194) | func NewVHostPathRewriter(slashesCount int) PathRewriteFunc {
function NewPathSlashesStripper (line 227) | func NewPathSlashesStripper(slashesCount int) PathRewriteFunc {
function NewPathPrefixStripper (line 243) | func NewPathPrefixStripper(prefixSize int) PathRewriteFunc {
type FS (line 257) | type FS struct
method NewRequestHandler (line 437) | func (fs *FS) NewRequestHandler() RequestHandler {
method normalizeRoot (line 442) | func (fs *FS) normalizeRoot(root string) string {
method initRequestHandler (line 481) | func (fs *FS) initRequestHandler() {
constant FSCompressedFileSuffix (line 378) | FSCompressedFileSuffix = ".fasthttp.gz"
constant FSHandlerCacheDuration (line 391) | FSHandlerCacheDuration = 10 * time.Second
function FSHandler (line 415) | func FSHandler(root string, stripSlashes int) RequestHandler {
type fsHandler (line 531) | type fsHandler struct
method pathToFilePath (line 1024) | func (h *fsHandler) pathToFilePath(path []byte, hasTrailingSlash bool)...
method filePathToCompressed (line 1081) | func (h *fsHandler) filePathToCompressed(filePath string) string {
method handleRequest (line 1091) | func (h *fsHandler) handleRequest(ctx *RequestCtx) {
method openIndexFile (line 1309) | func (h *fsHandler) openIndexFile(ctx *RequestCtx, dirPath string, mus...
method createDirIndex (line 1343) | func (h *fsHandler) createDirIndex(ctx *RequestCtx, dirPath string, mu...
method compressAndOpenFSFile (line 1448) | func (h *fsHandler) compressAndOpenFSFile(filePath, fileEncoding strin...
method compressFileNolock (line 1498) | func (h *fsHandler) compressFileNolock(
method newCompressedFSFileCache (line 1560) | func (h *fsHandler) newCompressedFSFileCache(f fs.File, fileInfo fs.Fi...
method newCompressedFSFile (line 1630) | func (h *fsHandler) newCompressedFSFile(filePath, fileEncoding string)...
method openFSFile (line 1643) | func (h *fsHandler) openFSFile(filePath string, mustCompress bool, fil...
method newFSFile (line 1698) | func (h *fsHandler) newFSFile(f fs.File, fileInfo fs.FileInfo, compres...
type fsFile (line 551) | type fsFile struct
method NewReader (line 570) | func (ff *fsFile) NewReader() (io.Reader, error) {
method smallFileReader (line 577) | func (ff *fsFile) smallFileReader() io.Reader {
method isBig (line 594) | func (ff *fsFile) isBig() bool {
method bigFileReader (line 601) | func (ff *fsFile) bigFileReader() (io.Reader, error) {
method Release (line 631) | func (ff *fsFile) Release() {
method decReadersCount (line 645) | func (ff *fsFile) decReadersCount() {
constant maxSmallFileSize (line 592) | maxSmallFileSize = 2 * 4096
type bigFileReader (line 656) | type bigFileReader struct
method UpdateByteRange (line 663) | func (r *bigFileReader) UpdateByteRange(startPos, endPos int) error {
method Read (line 677) | func (r *bigFileReader) Read(p []byte) (int, error) {
method WriteTo (line 681) | func (r *bigFileReader) WriteTo(w io.Writer) (int64, error) {
method Close (line 691) | func (r *bigFileReader) Close() error {
type fsSmallFileReader (line 716) | type fsSmallFileReader struct
method Close (line 722) | func (r *fsSmallFileReader) Close() error {
method UpdateByteRange (line 732) | func (r *fsSmallFileReader) UpdateByteRange(startPos, endPos int) error {
method Read (line 738) | func (r *fsSmallFileReader) Read(p []byte) (int, error) {
method WriteTo (line 763) | func (r *fsSmallFileReader) WriteTo(w io.Writer) (int64, error) {
type cacheManager (line 810) | type cacheManager interface
type CacheKind (line 822) | type CacheKind
constant defaultCacheKind (line 825) | defaultCacheKind CacheKind = iota
constant brotliCacheKind (line 826) | brotliCacheKind
constant gzipCacheKind (line 827) | gzipCacheKind
constant zstdCacheKind (line 828) | zstdCacheKind
function newCacheManager (line 831) | func newCacheManager(fs *FS) cacheManager {
type noopCacheManager (line 854) | type noopCacheManager struct
method Lock (line 858) | func (n *noopCacheManager) Lock() {
method Unlock (line 862) | func (n *noopCacheManager) Unlock() {
method GetFileFromCache (line 866) | func (*noopCacheManager) GetFileFromCache(cacheKind CacheKind, path []...
method SetFileToCache (line 870) | func (n *noopCacheManager) SetFileToCache(cacheKind CacheKind, path []...
type inMemoryCacheManager (line 877) | type inMemoryCacheManager struct
method Lock (line 886) | func (cm *inMemoryCacheManager) Lock() {
method Unlock (line 890) | func (cm *inMemoryCacheManager) Unlock() {
method getFsCache (line 894) | func (cm *inMemoryCacheManager) getFsCache(cacheKind CacheKind) map[st...
method GetFileFromCache (line 908) | func (cm *inMemoryCacheManager) GetFileFromCache(cacheKind CacheKind, ...
method SetFileToCache (line 921) | func (cm *inMemoryCacheManager) SetFileToCache(cacheKind CacheKind, pa...
method handleCleanCache (line 945) | func (cm *inMemoryCacheManager) handleCleanCache(cleanStop chan struct...
method cleanCache (line 973) | func (cm *inMemoryCacheManager) cleanCache(pendingFiles []*fsFile) []*...
function cleanCacheNolock (line 1004) | func cleanCacheNolock(
type byteRangeUpdater (line 1252) | type byteRangeUpdater interface
function ParseByteRange (line 1259) | func ParseByteRange(byteRange []byte, contentLength int) (startPos, endP...
constant fsMinCompressRatio (line 1444) | fsMinCompressRatio = 0.8
constant fsMaxCompressibleFileSize (line 1445) | fsMaxCompressibleFileSize = 8 * 1024 * 1024
function readFileHeader (line 1733) | func readFileHeader(f io.Reader, compressed bool, fileEncoding string) (...
function stripLeadingSlashes (line 1789) | func stripLeadingSlashes(path []byte, stripSlashes int) []byte {
function fileExtension (line 1806) | func fileExtension(path string, compressed bool, compressedFileSuffix st...
function FileLastModified (line 1818) | func FileLastModified(path string) (time.Time, error) {
function fsModTime (line 1831) | func fsModTime(t time.Time) time.Time {
function getFileLock (line 1837) | func getFileLock(absPath string) *sync.Mutex {
type osFS (line 1845) | type osFS struct
method Open (line 1847) | func (o *osFS) Open(name string) (fs.File, error) { return os.Open...
method Stat (line 1848) | func (o *osFS) Stat(name string) (fs.FileInfo, error) { return os.Stat...
FILE: fs_example_test.go
function ExampleFS (line 9) | func ExampleFS() {
FILE: fs_fs_test.go
function TestFSServeFileHead (line 20) | func TestFSServeFileHead(t *testing.T) {
function TestFSServeFileCompressed (line 59) | func TestFSServeFileCompressed(t *testing.T) {
function TestFSServeFileUncompressed (line 171) | func TestFSServeFileUncompressed(t *testing.T) {
function TestFSFSByteRangeConcurrent (line 213) | func TestFSFSByteRangeConcurrent(t *testing.T) {
function TestFSFSByteRangeSingleThread (line 248) | func TestFSFSByteRangeSingleThread(t *testing.T) {
function TestFSFSCompressConcurrent (line 266) | func TestFSFSCompressConcurrent(t *testing.T) {
function TestFSFSCompressSingleThread (line 309) | func TestFSFSCompressSingleThread(t *testing.T) {
function testFSFSCompress (line 331) | func testFSFSCompress(t *testing.T, h RequestHandler, filePath string) {
function TestFSServeFileContentType (line 462) | func TestFSServeFileContentType(t *testing.T) {
function TestFSServeFileDirectoryRedirect (line 486) | func TestFSServeFileDirectoryRedirect(t *testing.T) {
function TestDirFSServeFileHead (line 518) | func TestDirFSServeFileHead(t *testing.T) {
function TestDirFSServeFileCompressed (line 557) | func TestDirFSServeFileCompressed(t *testing.T) {
function TestDirFSFSByteRangeConcurrent (line 669) | func TestDirFSFSByteRangeConcurrent(t *testing.T) {
function TestDirFSFSByteRangeSingleThread (line 704) | func TestDirFSFSByteRangeSingleThread(t *testing.T) {
function TestDirFSFSCompressConcurrent (line 722) | func TestDirFSFSCompressConcurrent(t *testing.T) {
function TestDirFSFSCompressSingleThread (line 761) | func TestDirFSFSCompressSingleThread(t *testing.T) {
function TestDirFSServeFileContentType (line 783) | func TestDirFSServeFileContentType(t *testing.T) {
function TestDirFSServeFileDirectoryRedirect (line 807) | func TestDirFSServeFileDirectoryRedirect(t *testing.T) {
function TestFSFSGenerateIndexOsDirFS (line 837) | func TestFSFSGenerateIndexOsDirFS(t *testing.T) {
function TestFSRootEnforcement (line 919) | func TestFSRootEnforcement(t *testing.T) {
FILE: fs_handler_example_test.go
function requestHandler (line 31) | func requestHandler(ctx *fasthttp.RequestCtx) {
function ExampleFSHandler (line 43) | func ExampleFSHandler() {
FILE: fs_test.go
type TestLogger (line 18) | type TestLogger struct
method Printf (line 22) | func (t TestLogger) Printf(format string, args ...any) {
function TestNewVHostPathRewriter (line 26) | func TestNewVHostPathRewriter(t *testing.T) {
function TestNewVHostPathRewriterMaliciousHost (line 52) | func TestNewVHostPathRewriterMaliciousHost(t *testing.T) {
function testPathNotFound (line 69) | func testPathNotFound(t *testing.T, pathNotFoundFunc RequestHandler) {
function TestPathNotFound (line 102) | func TestPathNotFound(t *testing.T) {
function TestPathNotFoundFunc (line 108) | func TestPathNotFoundFunc(t *testing.T) {
function TestServeFileHead (line 116) | func TestServeFileHead(t *testing.T) {
function TestServeFileSmallNoReadFrom (line 155) | func TestServeFileSmallNoReadFrom(t *testing.T) {
type pureWriter (line 195) | type pureWriter struct
method Write (line 199) | func (pw pureWriter) Write(p []byte) (nn int, err error) {
function TestServeFileCompressed (line 203) | func TestServeFileCompressed(t *testing.T) {
function TestServeFileUncompressed (line 315) | func TestServeFileUncompressed(t *testing.T) {
function TestFSByteRangeConcurrent (line 357) | func TestFSByteRangeConcurrent(t *testing.T) {
function TestFSByteRangeConcurrentSkipCache (line 370) | func TestFSByteRangeConcurrentSkipCache(t *testing.T) {
function runFSByteRangeConcurrent (line 384) | func runFSByteRangeConcurrent(t *testing.T, fs *FS) {
function TestFSByteRangeSingleThread (line 410) | func TestFSByteRangeSingleThread(t *testing.T) {
function TestFSByteRangeSingleThreadSkipCache (line 423) | func TestFSByteRangeSingleThreadSkipCache(t *testing.T) {
function runFSByteRangeSingleThread (line 437) | func runFSByteRangeSingleThread(t *testing.T, fs *FS) {
function testFSByteRange (line 446) | func testFSByteRange(t *testing.T, h RequestHandler, filePath string) {
function getFileContents (line 497) | func getFileContents(path string) ([]byte, error) {
function TestParseByteRangeSuccess (line 507) | func TestParseByteRangeSuccess(t *testing.T) {
function testParseByteRangeSuccess (line 527) | func testParseByteRangeSuccess(t *testing.T, v string, contentLength, st...
function TestParseByteRangeError (line 542) | func TestParseByteRangeError(t *testing.T) {
function testParseByteRangeError (line 569) | func testParseByteRangeError(t *testing.T, v string, contentLength int) {
function TestFSCompressConcurrent (line 578) | func TestFSCompressConcurrent(t *testing.T) {
function TestFSCompressConcurrentSkipCache (line 598) | func TestFSCompressConcurrentSkipCache(t *testing.T) {
function runFSCompressConcurrent (line 619) | func runFSCompressConcurrent(t *testing.T, fs *FS) {
function TestFSCompressSingleThread (line 646) | func TestFSCompressSingleThread(t *testing.T) {
function TestFSCompressSingleThreadSkipCache (line 662) | func TestFSCompressSingleThreadSkipCache(t *testing.T) {
function runFSCompressSingleThread (line 679) | func runFSCompressSingleThread(t *testing.T, fs *FS) {
function testFSCompress (line 689) | func testFSCompress(t *testing.T, h RequestHandler, filePath string) {
function TestFSHandlerSingleThread (line 827) | func TestFSHandlerSingleThread(t *testing.T) {
function TestFSHandlerConcurrent (line 849) | func TestFSHandlerConcurrent(t *testing.T) {
function fsHandlerTest (line 886) | func fsHandlerTest(t *testing.T, requestHandler RequestHandler, filename...
function TestStripPathSlashes (line 945) | func TestStripPathSlashes(t *testing.T) {
function testStripPathSlashes (line 959) | func testStripPathSlashes(t *testing.T, path string, stripSlashes int, e...
function TestFileExtension (line 968) | func TestFileExtension(t *testing.T) {
function testFileExtension (line 984) | func testFileExtension(t *testing.T, path string, compressed bool, compr...
function TestServeFileContentType (line 993) | func TestServeFileContentType(t *testing.T) {
function TestServeFileDirectoryRedirect (line 1017) | func TestServeFileDirectoryRedirect(t *testing.T) {
function TestFileCacheForZstd (line 1051) | func TestFileCacheForZstd(t *testing.T) {
FILE: fuzz_test.go
function FuzzCookieParse (line 16) | func FuzzCookieParse(f *testing.F) {
function FuzzVisitHeaderParams (line 33) | func FuzzVisitHeaderParams(f *testing.F) {
function FuzzResponseReadLimitBody (line 49) | func FuzzResponseReadLimitBody(f *testing.F) {
function FuzzRequestReadLimitBody (line 77) | func FuzzRequestReadLimitBody(f *testing.F) {
function FuzzURIUpdateBytes (line 96) | func FuzzURIUpdateBytes(f *testing.F) {
function FuzzURIParse (line 114) | func FuzzURIParse(f *testing.F) {
function FuzzTestHeaderScanner (line 153) | func FuzzTestHeaderScanner(f *testing.F) {
function FuzzRequestReadLimitBodyAllocations (line 209) | func FuzzRequestReadLimitBodyAllocations(f *testing.F) {
FILE: header.go
constant rChar (line 16) | rChar = byte('\r')
constant nChar (line 17) | nChar = byte('\n')
type header (line 20) | type header struct
method ConnectionClose (line 161) | func (h *header) ConnectionClose() bool {
method SetConnectionClose (line 166) | func (h *header) SetConnectionClose() {
method ResetConnectionClose (line 171) | func (h *header) ResetConnectionClose() {
method SetContentType (line 298) | func (h *header) SetContentType(contentType string) {
method SetContentTypeBytes (line 303) | func (h *header) SetContentTypeBytes(contentType []byte) {
method SetTrailer (line 419) | func (h *header) SetTrailer(trailer string) error {
method SetTrailerBytes (line 440) | func (h *header) SetTrailerBytes(trailer []byte) error {
method AddTrailer (line 462) | func (h *header) AddTrailer(trailer string) error {
method AddTrailerBytes (line 500) | func (h *header) AddTrailerBytes(trailer []byte) (err error) {
method Protocol (line 760) | func (h *header) Protocol() []byte {
method IsHTTP11 (line 848) | func (h *header) IsHTTP11() bool {
method DisableNormalizing (line 933) | func (h *header) DisableNormalizing() bool {
method EnableNormalizing (line 952) | func (h *header) EnableNormalizing() bool {
method SetNoDefaultContentType (line 959) | func (h *header) SetNoDefaultContentType(noDefaultContentType bool) {
method copyTo (line 1022) | func (h *header) copyTo(dst *header) {
method Trailers (line 1127) | func (h *header) Trailers() iter.Seq[[]byte] {
method VisitAllTrailer (line 1142) | func (h *header) VisitAllTrailer(f func(value []byte)) {
method setNonSpecial (line 1455) | func (h *header) setNonSpecial(key, value []byte) {
method PeekTrailerKeys (line 2095) | func (h *header) PeekTrailerKeys() [][]byte {
method ReadTrailer (line 2180) | func (h *header) ReadTrailer(r *bufio.Reader) error {
method tryReadTrailer (line 2194) | func (h *header) tryReadTrailer(r *bufio.Reader, n int) error {
type ResponseHeader (line 49) | type ResponseHeader struct
method SetContentRange (line 90) | func (h *ResponseHeader) SetContentRange(startPos, endPos, contentLeng...
method StatusCode (line 127) | func (h *ResponseHeader) StatusCode() int {
method SetStatusCode (line 135) | func (h *ResponseHeader) SetStatusCode(statusCode int) {
method StatusMessage (line 140) | func (h *ResponseHeader) StatusMessage() []byte {
method SetStatusMessage (line 145) | func (h *ResponseHeader) SetStatusMessage(statusMessage []byte) {
method SetProtocol (line 150) | func (h *ResponseHeader) SetProtocol(protocol []byte) {
method SetLastModified (line 155) | func (h *ResponseHeader) SetLastModified(t time.Time) {
method ConnectionUpgrade (line 179) | func (h *ResponseHeader) ConnectionUpgrade() bool {
method PeekCookie (line 189) | func (h *ResponseHeader) PeekCookie(key string) []byte {
method ContentLength (line 198) | func (h *ResponseHeader) ContentLength() int {
method SetContentLength (line 233) | func (h *ResponseHeader) SetContentLength(contentLength int) {
method mustSkipContentLength (line 250) | func (h *ResponseHeader) mustSkipContentLength() bool {
method isCompressibleContentType (line 278) | func (h *ResponseHeader) isCompressibleContentType() bool {
method ContentType (line 289) | func (h *ResponseHeader) ContentType() []byte {
method ContentEncoding (line 308) | func (h *ResponseHeader) ContentEncoding() []byte {
method SetContentEncoding (line 313) | func (h *ResponseHeader) SetContentEncoding(contentEncoding string) {
method SetContentEncodingBytes (line 318) | func (h *ResponseHeader) SetContentEncodingBytes(contentEncoding []byt...
method addVaryBytes (line 323) | func (h *ResponseHeader) addVaryBytes(value []byte) {
method Server (line 335) | func (h *ResponseHeader) Server() []byte {
method SetServer (line 340) | func (h *ResponseHeader) SetServer(server string) {
method SetServerBytes (line 345) | func (h *ResponseHeader) SetServerBytes(server []byte) {
method Len (line 879) | func (h *ResponseHeader) Len() int {
method Reset (line 964) | func (h *ResponseHeader) Reset() {
method resetSkipNormalize (line 971) | func (h *ResponseHeader) resetSkipNormalize() {
method CopyTo (line 1038) | func (h *ResponseHeader) CopyTo(dst *ResponseHeader) {
method All (line 1072) | func (h *ResponseHeader) All() iter.Seq2[[]byte, []byte] {
method VisitAll (line 1117) | func (h *ResponseHeader) VisitAll(f func(key, value []byte)) {
method Cookies (line 1161) | func (h *ResponseHeader) Cookies() iter.Seq2[[]byte, []byte] {
method VisitAllCookie (line 1180) | func (h *ResponseHeader) VisitAllCookie(f func(key, value []byte)) {
method Del (line 1328) | func (h *ResponseHeader) Del(key string) {
method DelBytes (line 1334) | func (h *ResponseHeader) DelBytes(key []byte) {
method del (line 1340) | func (h *ResponseHeader) del(key []byte) {
method setSpecialHeader (line 1396) | func (h *ResponseHeader) setSpecialHeader(key, value []byte) bool {
method Add (line 1524) | func (h *ResponseHeader) Add(key, value string) {
method AddBytesK (line 1539) | func (h *ResponseHeader) AddBytesK(key []byte, value string) {
method AddBytesV (line 1554) | func (h *ResponseHeader) AddBytesV(key string, value []byte) {
method AddBytesKV (line 1569) | func (h *ResponseHeader) AddBytesKV(key, value []byte) {
method Set (line 1587) | func (h *ResponseHeader) Set(key, value string) {
method SetBytesK (line 1601) | func (h *ResponseHeader) SetBytesK(key []byte, value string) {
method SetBytesV (line 1615) | func (h *ResponseHeader) SetBytesV(key string, value []byte) {
method SetBytesKV (line 1629) | func (h *ResponseHeader) SetBytesKV(key, value []byte) {
method SetCanonical (line 1643) | func (h *ResponseHeader) SetCanonical(key, value []byte) {
method SetCookie (line 1653) | func (h *ResponseHeader) SetCookie(cookie *Cookie) {
method DelClientCookie (line 1686) | func (h *ResponseHeader) DelClientCookie(key string) {
method DelClientCookieBytes (line 1709) | func (h *ResponseHeader) DelClientCookieBytes(key []byte) {
method DelCookie (line 1717) | func (h *ResponseHeader) DelCookie(key string) {
method DelCookieBytes (line 1725) | func (h *ResponseHeader) DelCookieBytes(key []byte) {
method DelAllCookies (line 1741) | func (h *ResponseHeader) DelAllCookies() {
method Peek (line 1881) | func (h *ResponseHeader) Peek(key string) []byte {
method PeekBytes (line 1891) | func (h *ResponseHeader) PeekBytes(key []byte) []byte {
method peek (line 1918) | func (h *ResponseHeader) peek(key []byte) []byte {
method PeekAll (line 2023) | func (h *ResponseHeader) PeekAll(key string) [][]byte {
method peekAll (line 2028) | func (h *ResponseHeader) peekAll(key []byte) [][]byte {
method PeekKeys (line 2081) | func (h *ResponseHeader) PeekKeys() [][]byte {
method Cookie (line 2114) | func (h *ResponseHeader) Cookie(cookie *Cookie) bool {
method Read (line 2126) | func (h *ResponseHeader) Read(r *bufio.Reader) error {
method tryRead (line 2141) | func (h *ResponseHeader) tryRead(r *bufio.Reader, n int) error {
method Write (line 2368) | func (h *ResponseHeader) Write(w *bufio.Writer) error {
method WriteTo (line 2376) | func (h *ResponseHeader) WriteTo(w io.Writer) (int64, error) {
method Header (line 2388) | func (h *ResponseHeader) Header() []byte {
method writeTrailer (line 2394) | func (h *ResponseHeader) writeTrailer(w *bufio.Writer) error {
method TrailerHeader (line 2406) | func (h *ResponseHeader) TrailerHeader() []byte {
method String (line 2417) | func (h *ResponseHeader) String() string {
method appendStatusLine (line 2423) | func (h *ResponseHeader) appendStatusLine(dst []byte) []byte {
method AppendBytes (line 2433) | func (h *ResponseHeader) AppendBytes(dst []byte) []byte {
method parse (line 2641) | func (h *ResponseHeader) parse(buf []byte) (int, error) {
method parseFirstLine (line 2775) | func (h *ResponseHeader) parseFirstLine(buf []byte) (int, error) {
method parseHeaders (line 2939) | func (h *ResponseHeader) parseHeaders(buf []byte) (int, error) {
type RequestHeader (line 70) | type RequestHeader struct
method SetByteRange (line 108) | func (h *RequestHeader) SetByteRange(startPos, endPos int) {
method ConnectionUpgrade (line 184) | func (h *RequestHeader) ConnectionUpgrade() bool {
method ContentLength (line 207) | func (h *RequestHeader) ContentLength() int {
method SetContentLength (line 267) | func (h *RequestHeader) SetContentLength(contentLength int) {
method ContentType (line 350) | func (h *RequestHeader) ContentType() []byte {
method ContentEncoding (line 358) | func (h *RequestHeader) ContentEncoding() []byte {
method SetContentEncoding (line 363) | func (h *RequestHeader) SetContentEncoding(contentEncoding string) {
method SetContentEncodingBytes (line 368) | func (h *RequestHeader) SetContentEncodingBytes(contentEncoding []byte) {
method SetMultipartFormBoundary (line 375) | func (h *RequestHeader) SetMultipartFormBoundary(boundary string) {
method SetMultipartFormBoundaryBytes (line 390) | func (h *RequestHeader) SetMultipartFormBoundaryBytes(boundary []byte) {
method MultipartFormBoundary (line 650) | func (h *RequestHeader) MultipartFormBoundary() []byte {
method Host (line 691) | func (h *RequestHeader) Host() []byte {
method SetHost (line 699) | func (h *RequestHeader) SetHost(host string) {
method SetHostBytes (line 704) | func (h *RequestHeader) SetHostBytes(host []byte) {
method UserAgent (line 709) | func (h *RequestHeader) UserAgent() []byte {
method SetUserAgent (line 717) | func (h *RequestHeader) SetUserAgent(userAgent string) {
method SetUserAgentBytes (line 722) | func (h *RequestHeader) SetUserAgentBytes(userAgent []byte) {
method Referer (line 727) | func (h *RequestHeader) Referer() []byte {
method SetReferer (line 732) | func (h *RequestHeader) SetReferer(referer string) {
method SetRefererBytes (line 737) | func (h *RequestHeader) SetRefererBytes(referer []byte) {
method Method (line 742) | func (h *RequestHeader) Method() []byte {
method SetMethod (line 750) | func (h *RequestHeader) SetMethod(method string) {
method SetMethodBytes (line 755) | func (h *RequestHeader) SetMethodBytes(method []byte) {
method SetProtocol (line 768) | func (h *RequestHeader) SetProtocol(protocol string) {
method SetProtocolBytes (line 774) | func (h *RequestHeader) SetProtocolBytes(protocol []byte) {
method RequestURI (line 780) | func (h *RequestHeader) RequestURI() []byte {
method SetRequestURI (line 791) | func (h *RequestHeader) SetRequestURI(requestURI string) {
method SetRequestURIBytes (line 798) | func (h *RequestHeader) SetRequestURIBytes(requestURI []byte) {
method IsGet (line 803) | func (h *RequestHeader) IsGet() bool {
method IsPost (line 808) | func (h *RequestHeader) IsPost() bool {
method IsPut (line 813) | func (h *RequestHeader) IsPut() bool {
method IsHead (line 818) | func (h *RequestHeader) IsHead() bool {
method IsDelete (line 823) | func (h *RequestHeader) IsDelete() bool {
method IsConnect (line 828) | func (h *RequestHeader) IsConnect() bool {
method IsOptions (line 833) | func (h *RequestHeader) IsOptions() bool {
method IsTrace (line 838) | func (h *RequestHeader) IsTrace() bool {
method IsPatch (line 843) | func (h *RequestHeader) IsPatch() bool {
method HasAcceptEncoding (line 854) | func (h *RequestHeader) HasAcceptEncoding(acceptEncoding string) bool {
method HasAcceptEncodingBytes (line 861) | func (h *RequestHeader) HasAcceptEncodingBytes(acceptEncoding []byte) ...
method Len (line 889) | func (h *RequestHeader) Len() int {
method DisableSpecialHeader (line 904) | func (h *RequestHeader) DisableSpecialHeader() bool {
method EnableSpecialHeader (line 914) | func (h *RequestHeader) EnableSpecialHeader() bool {
method Reset (line 992) | func (h *RequestHeader) Reset() {
method resetSkipNormalize (line 999) | func (h *RequestHeader) resetSkipNormalize() {
method CopyTo (line 1051) | func (h *RequestHeader) CopyTo(dst *RequestHeader) {
method Cookies (line 1195) | func (h *RequestHeader) Cookies() iter.Seq2[[]byte, []byte] {
method VisitAllCookie (line 1211) | func (h *RequestHeader) VisitAllCookie(f func(key, value []byte)) {
method All (line 1228) | func (h *RequestHeader) All() iter.Seq2[[]byte, []byte] {
method VisitAll (line 1277) | func (h *RequestHeader) VisitAll(f func(key, value []byte)) {
method AllInOrder (line 1296) | func (h *RequestHeader) AllInOrder() iter.Seq2[[]byte, []byte] {
method VisitAllInOrder (line 1320) | func (h *RequestHeader) VisitAllInOrder(f func(key, value []byte)) {
method Del (line 1362) | func (h *RequestHeader) Del(key string) {
method DelBytes (line 1368) | func (h *RequestHeader) DelBytes(key []byte) {
method del (line 1374) | func (h *RequestHeader) del(key []byte) {
method setSpecialHeader (line 1460) | func (h *RequestHeader) setSpecialHeader(key, value []byte) bool {
method SetCookie (line 1658) | func (h *RequestHeader) SetCookie(key, value string) {
method SetCookieBytesK (line 1664) | func (h *RequestHeader) SetCookieBytesK(key []byte, value string) {
method SetCookieBytesKV (line 1669) | func (h *RequestHeader) SetCookieBytesKV(key, value []byte) {
method DelCookie (line 1730) | func (h *RequestHeader) DelCookie(key string) {
method DelCookieBytes (line 1736) | func (h *RequestHeader) DelCookieBytes(key []byte) {
method DelAllCookies (line 1746) | func (h *RequestHeader) DelAllCookies() {
method Add (line 1758) | func (h *RequestHeader) Add(key, value string) {
method AddBytesK (line 1769) | func (h *RequestHeader) AddBytesK(key []byte, value string) {
method AddBytesV (line 1780) | func (h *RequestHeader) AddBytesV(key string, value []byte) {
method AddBytesKV (line 1795) | func (h *RequestHeader) AddBytesKV(key, value []byte) {
method Set (line 1813) | func (h *RequestHeader) Set(key, value string) {
method SetBytesK (line 1827) | func (h *RequestHeader) SetBytesK(key []byte, value string) {
method SetBytesV (line 1841) | func (h *RequestHeader) SetBytesV(key string, value []byte) {
method SetBytesKV (line 1855) | func (h *RequestHeader) SetBytesKV(key, value []byte) {
method SetCanonical (line 1869) | func (h *RequestHeader) SetCanonical(key, value []byte) {
method Peek (line 1902) | func (h *RequestHeader) Peek(key string) []byte {
method PeekBytes (line 1912) | func (h *RequestHeader) PeekBytes(key []byte) []byte {
method peek (line 1942) | func (h *RequestHeader) peek(key []byte) []byte {
method PeekAll (line 1975) | func (h *RequestHeader) PeekAll(key string) [][]byte {
method peekAll (line 1980) | func (h *RequestHeader) peekAll(key []byte) [][]byte {
method PeekKeys (line 2067) | func (h *RequestHeader) PeekKeys() [][]byte {
method Cookie (line 2100) | func (h *RequestHeader) Cookie(key string) []byte {
method CookieBytes (line 2106) | func (h *RequestHeader) CookieBytes(key []byte) []byte {
method Read (line 2265) | func (h *RequestHeader) Read(r *bufio.Reader) error {
method readLoop (line 2272) | func (h *RequestHeader) readLoop(r *bufio.Reader, waitForMore bool) er...
method tryRead (line 2287) | func (h *RequestHeader) tryRead(r *bufio.Reader, n int) error {
method Write (line 2500) | func (h *RequestHeader) Write(w *bufio.Writer) error {
method WriteTo (line 2508) | func (h *RequestHeader) WriteTo(w io.Writer) (int64, error) {
method Header (line 2520) | func (h *RequestHeader) Header() []byte {
method writeTrailer (line 2526) | func (h *RequestHeader) writeTrailer(w *bufio.Writer) error {
method TrailerHeader (line 2538) | func (h *RequestHeader) TrailerHeader() []byte {
method RawHeaders (line 2558) | func (h *RequestHeader) RawHeaders() []byte {
method String (line 2563) | func (h *RequestHeader) String() string {
method AppendBytes (line 2569) | func (h *RequestHeader) AppendBytes(dst []byte) []byte {
method ignoreBody (line 2653) | func (h *RequestHeader) ignoreBody() bool {
method parse (line 2657) | func (h *RequestHeader) parse(buf []byte) (int, error) {
method parseFirstLine (line 2826) | func (h *RequestHeader) parseFirstLine(buf []byte) (int, error) {
method parseHeaders (line 3064) | func (h *RequestHeader) parseHeaders(buf []byte) (int, error) {
method collectCookies (line 3194) | func (h *RequestHeader) collectCookies() {
function validHeaderFieldByte (line 536) | func validHeaderFieldByte(c byte) bool {
function validHeaderValueByte (line 542) | func validHeaderValueByte(c byte) bool {
function isValidHeaderKey (line 547) | func isValidHeaderKey(a []byte) bool {
function VisitHeaderParams (line 583) | func VisitHeaderParams(b []byte, f func(key, value []byte) bool) {
function headerError (line 2233) | func headerError(typ string, err, errParse error, b []byte, secureErrorL...
function headerErrorMsg (line 2255) | func headerErrorMsg(typ string, err error, b []byte, secureErrorLogMessa...
function bufferSnippet (line 2323) | func bufferSnippet(b []byte) string {
function isOnlyCRLF (line 2338) | func isOnlyCRLF(b []byte) bool {
function updateServerDate (line 2347) | func updateServerDate() {
function refreshServerDate (line 2362) | func refreshServerDate() {
function appendHeaderLine (line 2634) | func appendHeaderLine(dst, key, value []byte) []byte {
function parseTrailer (line 2675) | func parseTrailer(src []byte, dest []argsKV, disableNormalizing bool) ([...
function isBadTrailer (line 2718) | func isBadTrailer(key []byte) bool {
function isValidMethod (line 2817) | func isValidMethod(method []byte) bool {
function readRawHeaders (line 2911) | func readRawHeaders(dst, buf []byte) ([]byte, int, error) {
function parseContentLength (line 3214) | func parseContentLength(b []byte) (int, error) {
type headerValueScanner (line 3225) | type headerValueScanner struct
method next (line 3230) | func (s *headerValueScanner) next() bool {
function stripSpace (line 3246) | func stripSpace(b []byte) []byte {
function hasHeaderValue (line 3256) | func hasHeaderValue(s, value []byte) bool {
function nextLine (line 3267) | func nextLine(b []byte) ([]byte, []byte, error) {
function initHeaderKV (line 3279) | func initHeaderKV(bufK, bufV []byte, key, value string, disableNormalizi...
function getHeaderKeyBytes (line 3287) | func getHeaderKeyBytes(bufK []byte, key string, disableNormalizing bool)...
function normalizeHeaderKey (line 3293) | func normalizeHeaderKey(b []byte, disableNormalizing bool) {
function removeNewLines (line 3323) | func removeNewLines(raw []byte) []byte {
function AppendNormalizedHeaderKey (line 3364) | func AppendNormalizedHeaderKey(dst []byte, key string) []byte {
function AppendNormalizedHeaderKeyBytes (line 3380) | func AppendNormalizedHeaderKeyBytes(dst, key []byte) []byte {
function appendTrailerBytes (line 3384) | func appendTrailerBytes(dst []byte, trailer [][]byte, sep []byte) []byte {
function copyTrailer (line 3394) | func copyTrailer(dst, src [][]byte) [][]byte {
type ErrNothingRead (line 3415) | type ErrNothingRead struct
type ErrSmallBuffer (line 3424) | type ErrSmallBuffer struct
function mustPeekBuffered (line 3428) | func mustPeekBuffered(r *bufio.Reader) []byte {
function mustDiscard (line 3436) | func mustDiscard(r *bufio.Reader, n int) {
FILE: header_regression_test.go
function TestIssue28ResponseWithoutBodyNoContentType (line 11) | func TestIssue28ResponseWithoutBodyNoContentType(t *testing.T) {
function TestIssue6RequestHeaderSetContentType (line 45) | func TestIssue6RequestHeaderSetContentType(t *testing.T) {
function testIssue6RequestHeaderSetContentType (line 54) | func testIssue6RequestHeaderSetContentType(t *testing.T, method string) {
function issue6VerifyRequestHeader (line 77) | func issue6VerifyRequestHeader(t *testing.T, h *RequestHeader, contentTy...
FILE: header_test.go
function TestResponseHeaderAddContentType (line 17) | func TestResponseHeaderAddContentType(t *testing.T) {
function TestResponseHeaderAddContentEncoding (line 39) | func TestResponseHeaderAddContentEncoding(t *testing.T) {
function TestResponseHeaderMultiLineValue (line 61) | func TestResponseHeaderMultiLineValue(t *testing.T) {
function TestIssue1808 (line 116) | func TestIssue1808(t *testing.T) {
function TestResponseHeaderMultiLinePanicked (line 163) | func TestResponseHeaderMultiLinePanicked(t *testing.T) {
function TestRequestHeaderLooseBackslashR (line 174) | func TestRequestHeaderLooseBackslashR(t *testing.T) {
function TestResponseHeaderEmptyValueFromHeader (line 187) | func TestResponseHeaderEmptyValueFromHeader(t *testing.T) {
function TestResponseHeaderEmptyValueFromString (line 214) | func TestResponseHeaderEmptyValueFromString(t *testing.T) {
function TestRequestHeaderEmptyValueFromHeader (line 241) | func TestRequestHeaderEmptyValueFromHeader(t *testing.T) {
function TestRequestHeaderEmptyValueFromString (line 269) | func TestRequestHeaderEmptyValueFromString(t *testing.T) {
function TestRequestRawHeaders (line 295) | func TestRequestRawHeaders(t *testing.T) {
function TestRequestDisableSpecialHeaders (line 395) | func TestRequestDisableSpecialHeaders(t *testing.T) {
function TestRequestDisableSpecialHeadersChunked (line 454) | func TestRequestDisableSpecialHeadersChunked(t *testing.T) {
function TestRequestDisableSpecialHeadersIdentity (line 487) | func TestRequestDisableSpecialHeadersIdentity(t *testing.T) {
function TestRequestHeaderSetCookieWithSpecialChars (line 509) | func TestRequestHeaderSetCookieWithSpecialChars(t *testing.T) {
function TestResponseHeaderDefaultStatusCode (line 536) | func TestResponseHeaderDefaultStatusCode(t *testing.T) {
function TestResponseHeaderDelClientCookie (line 546) | func TestResponseHeaderDelClientCookie(t *testing.T) {
function TestResponseHeaderAdd (line 570) | func TestResponseHeaderAdd(t *testing.T) {
function TestRequestHeaderAdd (line 623) | func TestRequestHeaderAdd(t *testing.T) {
function TestHasHeaderValue (line 680) | func TestHasHeaderValue(t *testing.T) {
function testHasHeaderValue (line 698) | func testHasHeaderValue(t *testing.T, s, value string, has bool) {
function TestRequestHeaderDel (line 705) | func TestRequestHeaderDel(t *testing.T) {
function TestResponseHeaderDel (line 774) | func TestResponseHeaderDel(t *testing.T) {
function TestResponseHeaderSetTrailerGetBytes (line 841) | func TestResponseHeaderSetTrailerGetBytes(t *testing.T) {
function TestRequestHeaderSetTrailerGetBytes (line 864) | func TestRequestHeaderSetTrailerGetBytes(t *testing.T) {
function TestAppendNormalizedHeaderKeyBytes (line 886) | func TestAppendNormalizedHeaderKeyBytes(t *testing.T) {
function testAppendNormalizedHeaderKeyBytes (line 894) | func testAppendNormalizedHeaderKeyBytes(t *testing.T, key, expectedKey s...
function TestRequestHeaderHTTP10ConnectionClose (line 903) | func TestRequestHeaderHTTP10ConnectionClose(t *testing.T) {
function TestRequestHeaderHTTP10ConnectionKeepAlive (line 918) | func TestRequestHeaderHTTP10ConnectionKeepAlive(t *testing.T) {
function TestBufferSnippet (line 933) | func TestBufferSnippet(t *testing.T) {
function testBufferSnippet (line 958) | func testBufferSnippet(t *testing.T, buf, expectedSnippet string) {
function TestResponseHeaderTrailingCRLFSuccess (line 965) | func TestResponseHeaderTrailingCRLFSuccess(t *testing.T) {
function TestResponseHeaderTrailingCRLFError (line 987) | func TestResponseHeaderTrailingCRLFError(t *testing.T) {
function TestRequestHeaderTrailingCRLFSuccess (line 1009) | func TestRequestHeaderTrailingCRLFSuccess(t *testing.T) {
function TestRequestHeaderTrailingCRLFError (line 1031) | func TestRequestHeaderTrailingCRLFError(t *testing.T) {
function TestRequestHeaderReadEOF (line 1053) | func TestRequestHeaderReadEOF(t *testing.T) {
function TestResponseHeaderReadEOF (line 1078) | func TestResponseHeaderReadEOF(t *testing.T) {
function TestResponseHeaderOldVersion (line 1103) | func TestResponseHeaderOldVersion(t *testing.T) {
function TestRequestHeaderSetByteRange (line 1126) | func TestRequestHeaderSetByteRange(t *testing.T) {
function testRequestHeaderSetByteRange (line 1134) | func testRequestHeaderSetByteRange(t *testing.T, startPos, endPos int, e...
function TestResponseHeaderSetContentRange (line 1143) | func TestResponseHeaderSetContentRange(t *testing.T) {
function testResponseHeaderSetContentRange (line 1150) | func testResponseHeaderSetContentRange(t *testing.T, startPos, endPos, c...
function TestRequestHeaderHasAcceptEncoding (line 1160) | func TestRequestHeaderHasAcceptEncoding(t *testing.T) {
function testRequestHeaderHasAcceptEncoding (line 1178) | func testRequestHeaderHasAcceptEncoding(t *testing.T, ae, v string, resu...
function TestVisitHeaderParams (line 1187) | func TestVisitHeaderParams(t *testing.T) {
function testVisitHeaderParams (line 1218) | func testVisitHeaderParams(t *testing.T, header string, expectedParams [...
function TestRequestMultipartFormBoundary (line 1236) | func TestRequestMultipartFormBoundary(t *testing.T) {
function testRequestMultipartFormBoundary (line 1264) | func testRequestMultipartFormBoundary(t *testing.T, s, boundary string) {
function TestResponseHeaderConnectionUpgrade (line 1278) | func TestResponseHeaderConnectionUpgrade(t *testing.T) {
function testResponseHeaderConnectionUpgrade (line 1301) | func testResponseHeaderConnectionUpgrade(t *testing.T, s string, isUpgra...
function TestRequestHeaderConnectionUpgrade (line 1321) | func TestRequestHeaderConnectionUpgrade(t *testing.T) {
function testRequestHeaderConnectionUpgrade (line 1348) | func testRequestHeaderConnectionUpgrade(t *testing.T, s string, isUpgrad...
function TestRequestHeaderProxyWithCookie (line 1368) | func TestRequestHeaderProxyWithCookie(t *testing.T) {
function TestResponseHeaderFirstByteReadEOF (line 1415) | func TestResponseHeaderFirstByteReadEOF(t *testing.T) {
type errorReader (line 1431) | type errorReader struct
method Read (line 1435) | func (r *errorReader) Read(p []byte) (int, error) {
function TestRequestHeaderEmptyMethod (line 1439) | func TestRequestHeaderEmptyMethod(t *testing.T) {
function TestResponseHeaderHTTPVer (line 1449) | func TestResponseHeaderHTTPVer(t *testing.T) {
function TestRequestHeaderHTTPVer (line 1461) | func TestRequestHeaderHTTPVer(t *testing.T) {
function testResponseHeaderHTTPVer (line 1472) | func testResponseHeaderHTTPVer(t *testing.T, s string, connectionClose b...
function testRequestHeaderHTTPVer (line 1485) | func testRequestHeaderHTTPVer(t *testing.T, s string, connectionClose bo...
function TestResponseHeaderCopyTo (line 1500) | func TestResponseHeaderCopyTo(t *testing.T) {
function TestRequestHeaderCopyTo (line 1540) | func TestRequestHeaderCopyTo(t *testing.T) {
function TestResponseContentTypeNoDefaultNotEmpty (line 1585) | func TestResponseContentTypeNoDefaultNotEmpty(t *testing.T) {
function TestRequestContentTypeDefaultNotEmpty (line 1600) | func TestRequestContentTypeDefaultNotEmpty(t *testing.T) {
function TestRequestContentTypeNoDefault (line 1627) | func TestRequestContentTypeNoDefault(t *testing.T) {
function TestResponseDateNoDefaultNotEmpty (line 1654) | func TestResponseDateNoDefaultNotEmpty(t *testing.T) {
function TestRequestHeaderConnectionClose (line 1668) | func TestRequestHeaderConnectionClose(t *testing.T) {
function TestRequestHeaderSetCookie (line 1702) | func TestRequestHeaderSetCookie(t *testing.T) {
function TestResponseHeaderSetCookie (line 1721) | func TestResponseHeaderSetCookie(t *testing.T) {
function TestResponseHeaderVisitAll (line 1753) | func TestResponseHeaderVisitAll(t *testing.T) {
function TestRequestHeaderVisitAll (line 1820) | func TestRequestHeaderVisitAll(t *testing.T) {
function TestRequestHeaderVisitAllInOrder (line 1878) | func TestRequestHeaderVisitAllInOrder(t *testing.T) {
function TestResponseHeaderAddTrailerError (line 1921) | func TestResponseHeaderAddTrailerError(t *testing.T) {
function TestRequestHeaderAddTrailerError (line 1936) | func TestRequestHeaderAddTrailerError(t *testing.T) {
function TestTrailerSecurityVulnerabilityFix (line 1952) | func TestTrailerSecurityVulnerabilityFix(t *testing.T) {
function TestTrailerParsingSecurityFix (line 2040) | func TestTrailerParsingSecurityFix(t *testing.T) {
function TestResponseHeaderCookie (line 2120) | func TestResponseHeaderCookie(t *testing.T) {
function equalCookie (line 2232) | func equalCookie(c1, c2 *Cookie) bool {
function TestRequestHeaderCookie (line 2251) | func TestRequestHeaderCookie(t *testing.T) {
function TestResponseHeaderCookieIssue4 (line 2307) | func TestResponseHeaderCookieIssue4(t *testing.T) {
function TestRequestHeaderCookieIssue313 (line 2353) | func TestRequestHeaderCookieIssue313(t *testing.T) {
function TestRequestHeaderMethod (line 2395) | func TestRequestHeaderMethod(t *testing.T) {
function testRequestHeaderMethod (line 2409) | func testRequestHeaderMethod(t *testing.T, expectedMethod string) {
function TestRequestHeaderSetGet (line 2429) | func TestRequestHeaderSetGet(t *testing.T) {
function TestResponseHeaderSetGet (line 2496) | func TestResponseHeaderSetGet(t *testing.T) {
function expectRequestHeaderGet (line 2556) | func expectRequestHeaderGet(t *testing.T, h *RequestHeader, key, expecte...
function expectResponseHeaderGet (line 2562) | func expectResponseHeaderGet(t *testing.T, h *ResponseHeader, key, expec...
function TestResponseHeaderConnectionClose (line 2568) | func TestResponseHeaderConnectionClose(t *testing.T) {
function testResponseHeaderConnectionClose (line 2575) | func testResponseHeaderConnectionClose(t *testing.T, connectionClose boo...
function TestRequestHeaderTooBig (line 2603) | func TestRequestHeaderTooBig(t *testing.T) {
function TestResponseHeaderTooBig (line 2616) | func TestResponseHeaderTooBig(t *testing.T) {
type bufioPeekReader (line 2629) | type bufioPeekReader struct
method Read (line 2634) | func (r *bufioPeekReader) Read(b []byte) (int, error) {
function TestRequestHeaderBufioPeek (line 2647) | func TestRequestHeaderBufioPeek(t *testing.T) {
function TestResponseHeaderBufioPeek (line 2661) | func TestResponseHeaderBufioPeek(t *testing.T) {
function getHeaders (line 2675) | func getHeaders(n int) string {
function TestResponseHeaderReadSuccess (line 2683) | func TestResponseHeaderReadSuccess(t *testing.T) {
function TestRequestHeaderReadSuccess (line 2833) | func TestRequestHeaderReadSuccess(t *testing.T) {
function TestResponseHeaderReadError (line 2962) | func TestResponseHeaderReadError(t *testing.T) {
function TestResponseHeaderReadErrorSecureLog (line 3004) | func TestResponseHeaderReadErrorSecureLog(t *testing.T) {
function TestRequestHeaderReadError (line 3029) | func TestRequestHeaderReadError(t *testing.T) {
function TestRequestHeaderReadSecuredError (line 3062) | func TestRequestHeaderReadSecuredError(t *testing.T) {
function testResponseHeaderReadError (line 3080) | func testResponseHeaderReadError(t *testing.T, h *ResponseHeader, header...
function testResponseHeaderReadSecuredError (line 3092) | func testResponseHeaderReadSecuredError(t *testing.T, h *ResponseHeader,...
function testRequestHeaderReadError (line 3107) | func testRequestHeaderReadError(t *testing.T, h *RequestHeader, headers ...
function testRequestHeaderReadSecuredError (line 3122) | func testRequestHeaderReadSecuredError(t *testing.T, h *RequestHeader, h...
function testResponseHeaderReadSuccess (line 3137) | func testResponseHeaderReadSuccess(t *testing.T, h *ResponseHeader, head...
function testRequestHeaderReadSuccess (line 3151) | func testRequestHeaderReadSuccess(t *testing.T, h *RequestHeader, header...
function verifyResponseHeader (line 3165) | func verifyResponseHeader(t *testing.T, h *ResponseHeader, expectedStatu...
function verifyResponseHeaderConnection (line 3182) | func verifyResponseHeaderConnection(t *testing.T, h *ResponseHeader, exp...
function verifyRequestHeader (line 3188) | func verifyRequestHeader(t *testing.T, h *RequestHeader, expectedContent...
type peeker (line 3208) | type peeker interface
function verifyTrailer (line 3212) | func verifyTrailer(t *testing.T, h peeker, expectedTrailers map[string]s...
function TestRequestHeader_PeekAll (line 3221) | func TestRequestHeader_PeekAll(t *testing.T) {
function expectRequestHeaderAll (line 3251) | func expectRequestHeaderAll(t *testing.T, h *RequestHeader, key string, ...
function TestResponseHeader_PeekAll (line 3260) | func TestResponseHeader_PeekAll(t *testing.T) {
function expectResponseHeaderAll (line 3287) | func expectResponseHeaderAll(t *testing.T, h *ResponseHeader, key string...
function TestRequestHeader_Keys (line 3296) | func TestRequestHeader_Keys(t *testing.T) {
function TestResponseHeader_Keys (line 3316) | func TestResponseHeader_Keys(t *testing.T) {
function TestAddVaryHeader (line 3336) | func TestAddVaryHeader(t *testing.T) {
function TestAddVaryHeaderExisting (line 3358) | func TestAddVaryHeaderExisting(t *testing.T) {
function TestAddVaryHeaderExistingAcceptEncoding (line 3381) | func TestAddVaryHeaderExistingAcceptEncoding(t *testing.T) {
function TestRequestHeaderExtraWhitespace (line 3404) | func TestRequestHeaderExtraWhitespace(t *testing.T) {
function TestRequestHeaderValidWhitespace (line 3429) | func TestRequestHeaderValidWhitespace(t *testing.T) {
FILE: header_timing_test.go
type benchReadBuf (line 19) | type benchReadBuf struct
method Read (line 24) | func (r *benchReadBuf) Read(p []byte) (int, error) {
function BenchmarkRequestHeaderRead (line 34) | func BenchmarkRequestHeaderRead(b *testing.B) {
function BenchmarkRequestHeaderReadNetHttp (line 65) | func BenchmarkRequestHeaderReadNetHttp(b *testing.B) {
function BenchmarkResponseHeaderRead (line 93) | func BenchmarkResponseHeaderRead(b *testing.B) {
function BenchmarkRequestHeaderWrite (line 121) | func BenchmarkRequestHeaderWrite(b *testing.B) {
function BenchmarkResponseHeaderWrite (line 138) | func BenchmarkResponseHeaderWrite(b *testing.B) {
function BenchmarkRequestHeaderPeekBytesSpecialHeader (line 157) | func BenchmarkRequestHeaderPeekBytesSpecialHeader(b *testing.B) {
function BenchmarkRequestHeaderPeekBytesNonSpecialHeader (line 171) | func BenchmarkRequestHeaderPeekBytesNonSpecialHeader(b *testing.B) {
function BenchmarkResponseHeaderPeekBytesSpecialHeader (line 185) | func BenchmarkResponseHeaderPeekBytesSpecialHeader(b *testing.B) {
function BenchmarkResponseHeaderPeekBytesNonSpecialHeader (line 199) | func BenchmarkResponseHeaderPeekBytesNonSpecialHeader(b *testing.B) {
function BenchmarkNormalizeHeaderKeyCommonCase (line 212) | func BenchmarkNormalizeHeaderKeyCommonCase(b *testing.B) {
function BenchmarkNormalizeHeaderKeyLowercase (line 217) | func BenchmarkNormalizeHeaderKeyLowercase(b *testing.B) {
function BenchmarkNormalizeHeaderKeyUppercase (line 222) | func BenchmarkNormalizeHeaderKeyUppercase(b *testing.B) {
function benchmarkNormalizeHeaderKey (line 227) | func benchmarkNormalizeHeaderKey(b *testing.B, src []byte) {
function BenchmarkVisitHeaderParams (line 237) | func BenchmarkVisitHeaderParams(b *testing.B) {
function BenchmarkRemoveNewLines (line 250) | func BenchmarkRemoveNewLines(b *testing.B) {
function BenchmarkRequestHeaderIsGet (line 281) | func BenchmarkRequestHeaderIsGet(b *testing.B) {
FILE: headers.go
constant HeaderAccept (line 4) | HeaderAccept = "Accept"
constant HeaderAcceptCH (line 5) | HeaderAcceptCH = "Accept-CH"
constant HeaderAcceptCharset (line 6) | HeaderAcceptCharset = "Accept-Charset"
constant HeaderAcceptCHLifetime (line 7) | HeaderAcceptCHLifetime = "Accept-CH-Lifetime"
constant HeaderAcceptEncoding (line 8) | HeaderAcceptEncoding = "Accept-Encoding"
constant HeaderAcceptLanguage (line 9) | HeaderAcceptLanguage = "Accept-Language"
constant HeaderAcceptPatch (line 10) | HeaderAcceptPatch = "Accept-Patch"
constant HeaderAcceptPushPolicy (line 11) | HeaderAcceptPushPolicy = "Accept-Push-Policy"
constant HeaderAcceptRanges (line 12) | HeaderAcceptRanges = "Accept-Ranges"
constant HeaderAcceptSignature (line 13) | HeaderAcceptSignature = "Accept-Signature"
constant HeaderAccessControlAllowCredentials (line 14) | HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
constant HeaderAccessControlAllowHeaders (line 15) | HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
constant HeaderAccessControlAllowMethods (line 16) | HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
constant HeaderAccessControlAllowOrigin (line 17) | HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
constant HeaderAccessControlExposeHeaders (line 18) | HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
constant HeaderAccessControlMaxAge (line 19) | HeaderAccessControlMaxAge = "Access-Control-Max-Age"
constant HeaderAccessControlRequestHeaders (line 20) | HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
constant HeaderAccessControlRequestMethod (line 21) | HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
constant HeaderAge (line 22) | HeaderAge = "Age"
constant HeaderAllow (line 23) | HeaderAllow = "Allow"
constant HeaderAltSvc (line 24) | HeaderAltSvc = "Alt-Svc"
constant HeaderAuthorization (line 25) | HeaderAuthorization = "Authorization"
constant HeaderCacheControl (line 26) | HeaderCacheControl = "Cache-Control"
constant HeaderClearSiteData (line 27) | HeaderClearSiteData = "Clear-Site-Data"
constant HeaderConnection (line 28) | HeaderConnection = "Connection"
constant HeaderContentDisposition (line 29) | HeaderContentDisposition = "Content-Disposition"
constant HeaderContentDPR (line 30) | HeaderContentDPR = "Content-DPR"
constant HeaderContentEncoding (line 31) | HeaderContentEncoding = "Content-Encoding"
constant HeaderContentLanguage (line 32) | HeaderContentLanguage = "Content-Language"
constant HeaderContentLength (line 33) | HeaderContentLength = "Content-Length"
constant HeaderContentLocation (line 34) | HeaderContentLocation = "Content-Location"
constant HeaderContentRange (line 35) | HeaderContentRange = "Content-Range"
constant HeaderContentSecurityPolicy (line 36) | HeaderContentSecurityPolicy = "Content-Security-Policy"
constant HeaderContentSecurityPolicyReportOnly (line 37) | HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-...
constant HeaderContentType (line 38) | HeaderContentType = "Content-Type"
constant HeaderCookie (line 39) | HeaderCookie = "Cookie"
constant HeaderCrossOriginResourcePolicy (line 40) | HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy"
constant HeaderDate (line 41) | HeaderDate = "Date"
constant HeaderDNT (line 42) | HeaderDNT = "DNT"
constant HeaderDPR (line 43) | HeaderDPR = "DPR"
constant HeaderEarlyData (line 44) | HeaderEarlyData = "Early-Data"
constant HeaderETag (line 45) | HeaderETag = "ETag"
constant HeaderExpect (line 46) | HeaderExpect = "Expect"
constant HeaderExpectCT (line 47) | HeaderExpectCT = "Expect-CT"
constant HeaderExpires (line 48) | HeaderExpires = "Expires"
constant HeaderFeaturePolicy (line 49) | HeaderFeaturePolicy = "Feature-Policy"
constant HeaderForwarded (line 50) | HeaderForwarded = "Forwarded"
constant HeaderFrom (line 51) | HeaderFrom = "From"
constant HeaderHost (line 52) | HeaderHost = "Host"
constant HeaderIfMatch (line 53) | HeaderIfMatch = "If-Match"
constant HeaderIfModifiedSince (line 54) | HeaderIfModifiedSince = "If-Modified-Since"
constant HeaderIfNoneMatch (line 55) | HeaderIfNoneMatch = "If-None-Match"
constant HeaderIfRange (line 56) | HeaderIfRange = "If-Range"
constant HeaderIfUnmodifiedSince (line 57) | HeaderIfUnmodifiedSince = "If-Unmodified-Since"
constant HeaderIndex (line 58) | HeaderIndex = "Index"
constant HeaderKeepAlive (line 59) | HeaderKeepAlive = "Keep-Alive"
constant HeaderLargeAllocation (line 60) | HeaderLargeAllocation = "Large-Allocation"
constant HeaderLastEventID (line 61) | HeaderLastEventID = "Last-Event-ID"
constant HeaderLastModified (line 62) | HeaderLastModified = "Last-Modified"
constant HeaderLink (line 63) | HeaderLink = "Link"
constant HeaderLocation (line 64) | HeaderLocation = "Location"
constant HeaderMaxForwards (line 65) | HeaderMaxForwards = "Max-Forwards"
constant HeaderNEL (line 66) | HeaderNEL = "NEL"
constant HeaderOrigin (line 67) | HeaderOrigin = "Origin"
constant HeaderPingFrom (line 68) | HeaderPingFrom = "Ping-From"
constant HeaderPingTo (line 69) | HeaderPingTo = "Ping-To"
constant HeaderPragma (line 70) | HeaderPragma = "Pragma"
constant HeaderProxyAuthenticate (line 71) | HeaderProxyAuthenticate = "Proxy-Authenticate"
constant HeaderProxyAuthorization (line 72) | HeaderProxyAuthorization = "Proxy-Authorization"
constant HeaderProxyConnection (line 73) | HeaderProxyConnection = "Proxy-Connection"
constant HeaderPublicKeyPins (line 74) | HeaderPublicKeyPins = "Public-Key-Pins"
constant HeaderPublicKeyPinsReportOnly (line 75) | HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only"
constant HeaderPushPolicy (line 76) | HeaderPushPolicy = "Push-Policy"
constant HeaderRange (line 77) | HeaderRange = "Range"
constant HeaderReferer (line 78) | HeaderReferer = "Referer"
constant HeaderReferrerPolicy (line 79) | HeaderReferrerPolicy = "Referrer-Policy"
constant HeaderReportTo (line 80) | HeaderReportTo = "Report-To"
constant HeaderRetryAfter (line 81) | HeaderRetryAfter = "Retry-After"
constant HeaderSaveData (line 82) | HeaderSaveData = "Save-Data"
constant HeaderSecWebSocketAccept (line 83) | HeaderSecWebSocketAccept = "Sec-WebSocket-Accept"
constant HeaderSecWebSocketExtensions (line 84) | HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions"
constant HeaderSecWebSocketKey (line 85) | HeaderSecWebSocketKey = "Sec-WebSocket-Key"
constant HeaderSecWebSocketProtocol (line 86) | HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol"
constant HeaderSecWebSocketVersion (line 87) | HeaderSecWebSocketVersion = "Sec-WebSocket-Version"
constant HeaderServer (line 88) | HeaderServer = "Server"
constant HeaderServerTiming (line 89) | HeaderServerTiming = "Server-Timing"
constant HeaderSetCookie (line 90) | HeaderSetCookie = "Set-Cookie"
constant HeaderSignature (line 91) | HeaderSignature = "Signature"
constant HeaderSignedHeaders (line 92) | HeaderSignedHeaders = "Signed-Headers"
constant HeaderSourceMap (line 93) | HeaderSourceMap = "SourceMap"
constant HeaderStrictTransportSecurity (line 94) | HeaderStrictTransportSecurity = "Strict-Transport-Security"
constant HeaderTE (line 95) | HeaderTE = "TE"
constant HeaderTimingAllowOrigin (line 96) | HeaderTimingAllowOrigin = "Timing-Allow-Origin"
constant HeaderTk (line 97) | HeaderTk = "Tk"
constant HeaderTrailer (line 98) | HeaderTrailer = "Trailer"
constant HeaderTransferEncoding (line 99) | HeaderTransferEncoding = "Transfer-Encoding"
constant HeaderUpgrade (line 100) | HeaderUpgrade = "Upgrade"
constant HeaderUpgradeInsecureRequests (line 101) | HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests"
constant HeaderUserAgent (line 102) | HeaderUserAgent = "User-Agent"
constant HeaderVary (line 103) | HeaderVary = "Vary"
constant HeaderVia (line 104) | HeaderVia = "Via"
constant HeaderViewportWidth (line 105) | HeaderViewportWidth = "Viewport-Width"
constant HeaderWarning (line 106) | HeaderWarning = "Warning"
constant HeaderWidth (line 107) | HeaderWidth = "Width"
constant HeaderWWWAuthenticate (line 108) | HeaderWWWAuthenticate = "WWW-Authenticate"
constant HeaderXContentTypeOptions (line 109) | HeaderXContentTypeOptions = "X-Content-Type-Options"
constant HeaderXDNSPrefetchControl (line 110) | HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control"
constant HeaderXDownloadOptions (line 111) | HeaderXDownloadOptions = "X-Download-Options"
constant HeaderXForwardedFor (line 112) | HeaderXForwardedFor = "X-Forwarded-For"
constant HeaderXForwardedHost (line 113) | HeaderXForwardedHost = "X-Forwarded-Host"
constant HeaderXForwardedProto (line 114) | HeaderXForwardedProto = "X-Forwarded-Proto"
constant HeaderXFrameOptions (line 115) | HeaderXFrameOptions = "X-Frame-Options"
constant HeaderXPermittedCrossDomainPolicies (line 116) | HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
constant HeaderXPingback (line 117) | HeaderXPingback = "X-Pingback"
constant HeaderXPoweredBy (line 118) | HeaderXPoweredBy = "X-Powered-By"
constant HeaderXRequestedWith (line 119) | HeaderXRequestedWith = "X-Requested-With"
constant HeaderXRobotsTag (line 120) | HeaderXRobotsTag = "X-Robots-Tag"
constant HeaderXUACompatible (line 121) | HeaderXUACompatible = "X-UA-Compatible"
constant HeaderXXSSProtection (line 122) | HeaderXXSSProtection = "X-XSS-Protection"
FILE: headerscanner.go
type headerScanner (line 9) | type headerScanner struct
method next (line 21) | func (s *headerScanner) next() bool {
method readLine (line 76) | func (s *headerScanner) readLine() (line []byte) {
method readContinuedLineSlice (line 107) | func (s *headerScanner) readContinuedLineSlice() ([]byte, error) {
method skipSpace (line 138) | func (s *headerScanner) skipSpace() bool {
function isASCIILetter (line 151) | func isASCIILetter(b byte) bool {
function trim (line 158) | func trim(s []byte) []byte {
FILE: http.go
function SetBodySizePoolLimit (line 27) | func SetBodySizePoolLimit(reqBodyLimit, respBodyLimit int) {
type Request (line 38) | type Request struct
method SetHost (line 132) | func (req *Request) SetHost(host string) {
method SetHostBytes (line 137) | func (req *Request) SetHostBytes(host []byte) {
method Host (line 142) | func (req *Request) Host() []byte {
method SetRequestURI (line 147) | func (req *Request) SetRequestURI(requestURI string) {
method SetRequestURIBytes (line 154) | func (req *Request) SetRequestURIBytes(requestURI []byte) {
method RequestURI (line 161) | func (req *Request) RequestURI() []byte {
method ConnectionClose (line 190) | func (req *Request) ConnectionClose() bool {
method SetConnectionClose (line 195) | func (req *Request) SetConnectionClose() {
method GetTimeOut (line 205) | func (req *Request) GetTimeOut() time.Duration {
method SetBodyStream (line 248) | func (req *Request) SetBodyStream(bodyStream io.Reader, bodySize int) {
method IsBodyStream (line 272) | func (req *Request) IsBodyStream() bool {
method SetBodyStreamWriter (line 293) | func (req *Request) SetBodyStreamWriter(sw StreamWriter) {
method BodyStream (line 326) | func (req *Request) BodyStream() io.Reader {
method CloseBodyStream (line 330) | func (req *Request) CloseBodyStream() error {
method BodyWriter (line 371) | func (req *Request) BodyWriter() io.Writer {
method bodyBytes (line 449) | func (req *Request) bodyBytes() []byte {
method bodyBuffer (line 476) | func (req *Request) bodyBuffer() *bytebufferpool.ByteBuffer {
method BodyGunzip (line 494) | func (req *Request) BodyGunzip() ([]byte, error) {
method BodyGunzipWithLimit (line 502) | func (req *Request) BodyGunzipWithLimit(maxBodySize int) ([]byte, erro...
method BodyUnbrotli (line 537) | func (req *Request) BodyUnbrotli() ([]byte, error) {
method BodyUnbrotliWithLimit (line 545) | func (req *Request) BodyUnbrotliWithLimit(maxBodySize int) ([]byte, er...
method BodyInflate (line 580) | func (req *Request) BodyInflate() ([]byte, error) {
method BodyInflateWithLimit (line 588) | func (req *Request) BodyInflateWithLimit(maxBodySize int) ([]byte, err...
method BodyUnzstd (line 613) | func (req *Request) BodyUnzstd() ([]byte, error) {
method BodyUnzstdWithLimit (line 621) | func (req *Request) BodyUnzstdWithLimit(maxBodySize int) ([]byte, erro...
method BodyUncompressed (line 663) | func (req *Request) BodyUncompressed() ([]byte, error) {
method BodyUncompressedWithLimit (line 671) | func (req *Request) BodyUncompressedWithLimit(maxBodySize int) ([]byte...
method BodyWriteTo (line 720) | func (req *Request) BodyWriteTo(w io.Writer) error {
method SetBodyRaw (line 801) | func (req *Request) SetBodyRaw(body []byte) {
method ReleaseBody (line 831) | func (req *Request) ReleaseBody(size int) {
method SwapBody (line 872) | func (req *Request) SwapBody(body []byte) []byte {
method Body (line 897) | func (req *Request) Body() []byte {
method AppendBody (line 913) | func (req *Request) AppendBody(p []byte) {
method AppendBodyString (line 920) | func (req *Request) AppendBodyString(s string) {
method SetBody (line 929) | func (req *Request) SetBody(body []byte) {
method SetBodyString (line 936) | func (req *Request) SetBodyString(body string) {
method ResetBody (line 943) | func (req *Request) ResetBody() {
method CopyTo (line 958) | func (req *Request) CopyTo(dst *Request) {
method copyToSkipBody (line 973) | func (req *Request) copyToSkipBody(dst *Request) {
method URI (line 1036) | func (req *Request) URI() *URI {
method SetURI (line 1045) | func (req *Request) SetURI(newURI *URI) {
method parseURI (line 1057) | func (req *Request) parseURI() error {
method PostArgs (line 1068) | func (req *Request) PostArgs() *Args {
method parsePostArgs (line 1073) | func (req *Request) parsePostArgs() {
method MultipartForm (line 1099) | func (req *Request) MultipartForm() (*multipart.Form, error) {
method MultipartFormWithLimit (line 1113) | func (req *Request) MultipartFormWithLimit(maxBodySize int) (*multipar...
method Reset (line 1255) | func (req *Request) Reset() {
method resetSkipHeader (line 1267) | func (req *Request) resetSkipHeader() {
method RemoveMultipartFormFiles (line 1279) | func (req *Request) RemoveMultipartFormFiles() {
method Read (line 1322) | func (req *Request) Read(r *bufio.Reader) error {
method ReadLimitBody (line 1350) | func (req *Request) ReadLimitBody(r *bufio.Reader, maxBodySize int) er...
method readLimitBody (line 1359) | func (req *Request) readLimitBody(r *bufio.Reader, maxBodySize int, ge...
method readBodyStream (line 1377) | func (req *Request) readBodyStream(r *bufio.Reader, maxBodySize int, g...
method MayContinue (line 1405) | func (req *Request) MayContinue() bool {
method ContinueReadBody (line 1416) | func (req *Request) ContinueReadBody(r *bufio.Reader, maxBodySize int,...
method ReadBody (line 1468) | func (req *Request) ReadBody(r *bufio.Reader, contentLength, maxBodySi...
method ContinueReadBodyStream (line 1499) | func (req *Request) ContinueReadBodyStream(r *bufio.Reader, maxBodySiz...
method WriteTo (line 1645) | func (req *Request) WriteTo(w io.Writer) (int64, error) {
method onlyMultipartForm (line 1723) | func (req *Request) onlyMultipartForm() bool {
method Write (line 1732) | func (req *Request) Write(w *bufio.Writer) error {
method writeBodyStream (line 2144) | func (req *Request) writeBodyStream(w *bufio.Writer) error {
method closeBodyStream (line 2238) | func (req *Request) closeBodyStream() error {
method String (line 2276) | func (req *Request) String() string {
method SetUserValue (line 2300) | func (req *Request) SetUserValue(key, value any) {
method SetUserValueBytes (line 2313) | func (req *Request) SetUserValueBytes(key []byte, value any) {
method UserValue (line 2318) | func (req *Request) UserValue(key any) any {
method UserValueBytes (line 2324) | func (req *Request) UserValueBytes(key []byte) any {
method VisitUserValues (line 2332) | func (req *Request) VisitUserValues(visitor func([]byte, any)) {
method VisitUserValuesAll (line 2345) | func (req *Request) VisitUserValuesAll(visitor func(any, any)) {
method ResetUserValues (line 2353) | func (req *Request) ResetUserValues() {
method RemoveUserValue (line 2358) | func (req *Request) RemoveUserValue(key any) {
method RemoveUserValueBytes (line 2363) | func (req *Request) RemoveUserValueBytes(key []byte) {
method SetTimeout (line 2806) | func (req *Request) SetTimeout(t time.Duration) {
type Response (line 93) | type Response struct
method StatusCode (line 170) | func (resp *Response) StatusCode() int {
method SetStatusCode (line 175) | func (resp *Response) SetStatusCode(statusCode int) {
method ConnectionClose (line 180) | func (resp *Response) ConnectionClose() bool {
method SetConnectionClose (line 185) | func (resp *Response) SetConnectionClose() {
method SendFile (line 214) | func (resp *Response) SendFile(path string) error {
method SetBodyStream (line 265) | func (resp *Response) SetBodyStream(bodyStream io.Reader, bodySize int) {
method IsBodyStream (line 277) | func (resp *Response) IsBodyStream() bool {
method SetBodyStreamWriter (line 308) | func (resp *Response) SetBodyStreamWriter(sw StreamWriter) {
method BodyWriter (line 318) | func (resp *Response) BodyWriter() io.Writer {
method BodyStream (line 337) | func (resp *Response) BodyStream() io.Reader {
method CloseBodyStream (line 341) | func (resp *Response) CloseBodyStream() error {
method ParseNetConn (line 404) | func (resp *Response) ParseNetConn(conn net.Conn) {
method RemoteAddr (line 411) | func (resp *Response) RemoteAddr() net.Addr {
method LocalAddr (line 417) | func (resp *Response) LocalAddr() net.Addr {
method Body (line 426) | func (resp *Response) Body() []byte {
method bodyBytes (line 439) | func (resp *Response) bodyBytes() []byte {
method bodyBuffer (line 468) | func (resp *Response) bodyBuffer() *bytebufferpool.ByteBuffer {
method BodyGunzip (line 511) | func (resp *Response) BodyGunzip() ([]byte, error) {
method BodyGunzipWithLimit (line 519) | func (resp *Response) BodyGunzipWithLimit(maxBodySize int) ([]byte, er...
method BodyUnbrotli (line 554) | func (resp *Response) BodyUnbrotli() ([]byte, error) {
method BodyUnbrotliWithLimit (line 562) | func (resp *Response) BodyUnbrotliWithLimit(maxBodySize int) ([]byte, ...
method BodyInflate (line 597) | func (resp *Response) BodyInflate() ([]byte, error) {
method BodyInflateWithLimit (line 605) | func (resp *Response) BodyInflateWithLimit(maxBodySize int) ([]byte, e...
method BodyUnzstd (line 625) | func (resp *Response) BodyUnzstd() ([]byte, error) {
method BodyUnzstdWithLimit (line 633) | func (resp *Response) BodyUnzstdWithLimit(maxBodySize int) ([]byte, er...
method BodyUncompressed (line 694) | func (resp *Response) BodyUncompressed() ([]byte, error) {
method BodyUncompressedWithLimit (line 702) | func (resp *Response) BodyUncompressedWithLimit(maxBodySize int) ([]by...
method BodyWriteTo (line 734) | func (resp *Response) BodyWriteTo(w io.Writer) error {
method AppendBody (line 747) | func (resp *Response) AppendBody(p []byte) {
method AppendBodyString (line 753) | func (resp *Response) AppendBodyString(s string) {
method SetBody (line 761) | func (resp *Response) SetBody(body []byte) {
method SetBodyString (line 769) | func (resp *Response) SetBodyString(body string) {
method ResetBody (line 777) | func (resp *Response) ResetBody() {
method SetBodyRaw (line 793) | func (resp *Response) SetBodyRaw(body []byte) {
method ReleaseBody (line 813) | func (resp *Response) ReleaseBody(size int) {
method SwapBody (line 847) | func (resp *Response) SwapBody(body []byte) []byte {
method CopyTo (line 992) | func (resp *Response) CopyTo(dst *Response) {
method copyToSkipBody (line 1007) | func (resp *Response) copyToSkipBody(dst *Response) {
method Reset (line 1290) | func (resp *Response) Reset() {
method resetSkipHeader (line 1303) | func (resp *Response) resetSkipHeader() {
method Read (line 1559) | func (resp *Response) Read(r *bufio.Reader) error {
method ReadLimitBody (line 1572) | func (resp *Response) ReadLimitBody(r *bufio.Reader, maxBodySize int) ...
method ReadBody (line 1606) | func (resp *Response) ReadBody(r *bufio.Reader, maxBodySize int) (err ...
method mustSkipBody (line 1638) | func (resp *Response) mustSkipBody() bool {
method WriteTo (line 1650) | func (resp *Response) WriteTo(w io.Writer) (int64, error) {
method WriteGzip (line 1808) | func (resp *Response) WriteGzip(w *bufio.Writer) error {
method WriteGzipLevel (line 1826) | func (resp *Response) WriteGzipLevel(w *bufio.Writer, level int) error {
method WriteDeflate (line 1837) | func (resp *Response) WriteDeflate(w *bufio.Writer) error {
method WriteDeflateLevel (line 1855) | func (resp *Response) WriteDeflateLevel(w *bufio.Writer, level int) er...
method brotliBody (line 1860) | func (resp *Response) brotliBody(level int) {
method gzipBody (line 1918) | func (resp *Response) gzipBody(level int) {
method deflateBody (line 1976) | func (resp *Response) deflateBody(level int) {
method zstdBody (line 2034) | func (resp *Response) zstdBody(level int) {
method Write (line 2121) | func (resp *Response) Write(w *bufio.Writer) error {
method writeBodyStream (line 2186) | func (resp *Response) writeBodyStream(w *bufio.Writer, sendBody bool) ...
method closeBodyStream (line 2253) | func (resp *Response) closeBodyStream(wErr error) error {
method String (line 2285) | func (resp *Response) String() string {
type ReadCloserWithError (line 345) | type ReadCloserWithError interface
type closeReader (line 350) | type closeReader struct
method CloseWithError (line 363) | func (c *closeReader) CloseWithError(err error) error {
function newCloseReaderWithError (line 356) | func newCloseReaderWithError(r io.Reader, closeFunc func(err error) erro...
type responseBodyWriter (line 376) | type responseBodyWriter struct
method Write (line 380) | func (w *responseBodyWriter) Write(p []byte) (int, error) {
method WriteString (line 385) | func (w *responseBodyWriter) WriteString(s string) (int, error) {
type requestBodyWriter (line 390) | type requestBodyWriter struct
method Write (line 394) | func (w *requestBodyWriter) Write(p []byte) (int, error) {
method WriteString (line 399) | func (w *requestBodyWriter) WriteString(s string) (int, error) {
function gunzipData (line 523) | func gunzipData(p []byte, maxBodySize int) ([]byte, error) {
function unBrotliData (line 566) | func unBrotliData(p []byte, maxBodySize int) ([]byte, error) {
method RequestBodyStream (line 609) | func (ctx *RequestCtx) RequestBodyStream() io.Reader {
function unzstdData (line 637) | func unzstdData(p []byte, maxBodySize int) ([]byte, error) {
function inflateData (line 646) | func inflateData(p []byte, maxBodySize int) ([]byte, error) {
function swapRequestBody (line 1015) | func swapRequestBody(a, b *Request) {
function swapResponseBody (line 1029) | func swapResponseBody(a, b *Response) {
function marshalMultipartForm (line 1178) | func marshalMultipartForm(f *multipart.Form, boundary string) ([]byte, e...
function WriteMultipartForm (line 1188) | func WriteMultipartForm(w io.Writer, f *multipart.Form, boundary string)...
function readMultipartForm (line 1237) | func readMultipartForm(r io.Reader, boundary string, size, maxInMemoryFi...
constant defaultMaxInMemoryFileSize (line 1326) | defaultMaxInMemoryFileSize = 16 * 1024 * 1024
function writeBufio (line 1654) | func writeBufio(hw httpWriter, w io.Writer) (int64, error) {
type statsWriter (line 1670) | type statsWriter struct
method Write (line 1675) | func (w *statsWriter) Write(p []byte) (int, error) {
method WriteString (line 1681) | func (w *statsWriter) WriteString(s string) (int, error) {
function acquireStatsWriter (line 1687) | func acquireStatsWriter(w io.Writer) *statsWriter {
function releaseStatsWriter (line 1699) | func releaseStatsWriter(sw *statsWriter) {
function acquireBufioWriter (line 1707) | func acquireBufioWriter(w io.Writer) *bufio.Writer {
function releaseBufioWriter (line 1717) | func releaseBufioWriter(bw *bufio.Writer) {
constant minCompressLen (line 2086) | minCompressLen = 200
type writeFlusher (line 2088) | type writeFlusher interface
type flushWriter (line 2093) | type flushWriter struct
method Write (line 2098) | func (w *flushWriter) Write(p []byte) (int, error) {
method WriteString (line 2112) | func (w *flushWriter) WriteString(s string) (int, error) {
type ErrBodyStreamWritePanic (line 2182) | type ErrBodyStreamWritePanic struct
function getHTTPString (line 2367) | func getHTTPString(hw httpWriter) string {
type httpWriter (line 2382) | type httpWriter interface
function writeBodyChunked (line 2386) | func writeBodyChunked(w *bufio.Writer, r io.Reader) error {
function limitedReaderSize (line 2415) | func limitedReaderSize(r io.Reader) int64 {
function writeBodyFixedSize (line 2423) | func writeBodyFixedSize(w *bufio.Writer, r io.Reader, size int64) error {
function copyZeroAlloc (line 2477) | func copyZeroAlloc(w io.Writer, r io.Reader) (int64, error) {
function copyBuffer (line 2521) | func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64...
function writeChunk (line 2558) | func writeChunk(w *bufio.Writer, b []byte) error {
function copyZeroAllocWithLimit (line 2582) | func copyZeroAllocWithLimit(w io.Writer, r io.Reader, maxBodySize int) (...
function readBody (line 2601) | func readBody(r *bufio.Reader, contentLength, maxBodySize int, dst []byt...
function readBodyWithStreaming (line 2610) | func readBodyWithStreaming(r *bufio.Reader, contentLength, maxBodySize i...
function readBodyIdentity (line 2637) | func readBodyIdentity(r *bufio.Reader, maxBodySize int, dst []byte) ([]b...
function appendBodyFixedSize (line 2671) | func appendBodyFixedSize(r *bufio.Reader, dst []byte, n int) ([]byte, er...
type ErrBrokenChunk (line 2705) | type ErrBrokenChunk struct
function readBodyChunked (line 2709) | func readBodyChunked(r *bufio.Reader, maxBodySize int, dst []byte) ([]by...
function parseChunkSize (line 2741) | func parseChunkSize(r *bufio.Reader) (int, error) {
function readCrLf (line 2779) | func readCrLf(r *bufio.Reader) error {
FILE: http_test.go
function TestInvalidTrailers (line 21) | func TestInvalidTrailers(t *testing.T) {
function TestResponseEmptyTransferEncoding (line 35) | func TestResponseEmptyTransferEncoding(t *testing.T) {
function TestFragmentInURIRequest (line 52) | func TestFragmentInURIRequest(t *testing.T) {
function TestIssue875 (line 68) | func TestIssue875(t *testing.T) {
function TestRequestCopyTo (line 117) | func TestRequestCopyTo(t *testing.T) {
function TestResponseCopyTo (line 138) | func TestResponseCopyTo(t *testing.T) {
function testRequestCopyTo (line 154) | func testRequestCopyTo(t *testing.T, src *Request) {
function testResponseCopyTo (line 164) | func testResponseCopyTo(t *testing.T, src *Response) {
function TestRequestBodyStreamWithTrailer (line 173) | func TestRequestBodyStreamWithTrailer(t *testing.T) {
function testRequestBodyStreamWithTrailer (line 183) | func testRequestBodyStreamWithTrailer(t *testing.T, body []byte, disable...
function TestResponseBodyStreamWithTrailer (line 232) | func TestResponseBodyStreamWithTrailer(t *testing.T) {
function testResponseBodyStreamWithTrailer (line 242) | func testResponseBodyStreamWithTrailer(t *testing.T, body []byte, disabl...
function TestResponseBodyStreamDeflate (line 289) | func TestResponseBodyStreamDeflate(t *testing.T) {
function TestResponseBodyStreamGzip (line 302) | func TestResponseBodyStreamGzip(t *testing.T) {
function testResponseBodyStreamDeflate (line 315) | func testResponseBodyStreamDeflate(t *testing.T, body []byte, bodySize i...
function testResponseBodyStreamGzip (line 349) | func testResponseBodyStreamGzip(t *testing.T, body []byte, bodySize int) {
function TestResponseWriteGzipNilBody (line 383) | func TestResponseWriteGzipNilBody(t *testing.T) {
function TestResponseWriteDeflateNilBody (line 397) | func TestResponseWriteDeflateNilBody(t *testing.T) {
function TestResponseBodyUncompressed (line 411) | func TestResponseBodyUncompressed(t *testing.T) {
function TestBodyDecodeWithLimitTooLarge (line 451) | func TestBodyDecodeWithLimitTooLarge(t *testing.T) {
function TestRequestMultipartFormWithLimitGzip (line 515) | func TestRequestMultipartFormWithLimitGzip(t *testing.T) {
function TestResponseSwapBodySerial (line 576) | func TestResponseSwapBodySerial(t *testing.T) {
function TestResponseSwapBodyConcurrent (line 582) | func TestResponseSwapBodyConcurrent(t *testing.T) {
function testResponseSwapBody (line 602) | func testResponseSwapBody(t *testing.T) {
function TestRequestSwapBodySerial (line 630) | func TestRequestSwapBodySerial(t *testing.T) {
function TestRequestSwapBodyConcurrent (line 636) | func TestRequestSwapBodyConcurrent(t *testing.T) {
function testRequestSwapBody (line 656) | func testRequestSwapBody(t *testing.T) {
function TestRequestHostFromRequestURI (line 684) | func TestRequestHostFromRequestURI(t *testing.T) {
function TestRequestHostFromHeader (line 697) | func TestRequestHostFromHeader(t *testing.T) {
function TestRequestContentTypeWithCharsetIssue100 (line 709) | func TestRequestContentTypeWithCharsetIssue100(t *testing.T) {
function TestRequestReadMultipartFormWithFile (line 741) | func TestRequestReadMultipartFormWithFile(t *testing.T) {
function TestRequestSetURI (line 828) | func TestRequestSetURI(t *testing.T) {
function TestRequestRequestURI (line 853) | func TestRequestRequestURI(t *testing.T) {
function TestRequestUpdateURI (line 883) | func TestRequestUpdateURI(t *testing.T) {
function TestUseHostHeader (line 907) | func TestUseHostHeader(t *testing.T) {
function TestUseHostHeader2 (line 932) | func TestUseHostHeader2(t *testing.T) {
function TestUseHostHeaderAfterRelease (line 966) | func TestUseHostHeaderAfterRelease(t *testing.T) {
function TestRequestBodyStreamMultipleBodyCalls (line 979) | func TestRequestBodyStreamMultipleBodyCalls(t *testing.T) {
function TestResponseBodyStreamMultipleBodyCalls (line 1000) | func TestResponseBodyStreamMultipleBodyCalls(t *testing.T) {
function TestRequestBodyWriteToPlain (line 1021) | func TestRequestBodyWriteToPlain(t *testing.T) {
function TestResponseBodyWriteToPlain (line 1032) | func TestResponseBodyWriteToPlain(t *testing.T) {
function TestResponseBodyWriteToStream (line 1043) | func TestResponseBodyWriteToStream(t *testing.T) {
function TestRequestBodyWriteToMultipart (line 1061) | func TestRequestBodyWriteToMultipart(t *testing.T) {
type bodyWriterTo (line 1077) | type bodyWriterTo interface
function testBodyWriteTo (line 1082) | func testBodyWriteTo(t *testing.T, bw bodyWriterTo, expectedS string, is...
function TestRequestReadEOF (line 1105) | func TestRequestReadEOF(t *testing.T) {
function TestResponseReadEOF (line 1130) | func TestResponseReadEOF(t *testing.T) {
function TestRequestReadNoBody (line 1155) | func TestRequestReadNoBody(t *testing.T) {
function TestRequestReadNoBodyStreaming (line 1172) | func TestRequestReadNoBodyStreaming(t *testing.T) {
function TestResponseWriteTo (line 1191) | func TestResponseWriteTo(t *testing.T) {
function TestRequestWriteTo (line 1212) | func TestRequestWriteTo(t *testing.T) {
function TestResponseSkipBody (line 1233) | func TestResponseSkipBody(t *testing.T) {
function TestRequestNoContentLength (line 1300) | func TestRequestNoContentLength(t *testing.T) {
function TestRequestReadGzippedBody (line 1321) | func TestRequestReadGzippedBody(t *testing.T) {
function TestRequestReadPostNoBody (line 1354) | func TestRequestReadPostNoBody(t *testing.T) {
function TestRequestContinueReadBody (line 1387) | func TestRequestContinueReadBody(t *testing.T) {
function TestRequestContinueReadBodyDisablePrereadMultipartForm (line 1418) | func TestRequestContinueReadBodyDisablePrereadMultipartForm(t *testing.T) {
function TestRequestMayContinue (line 1459) | func TestRequestMayContinue(t *testing.T) {
function TestResponseGzipStream (line 1478) | func TestResponseGzipStream(t *testing.T) {
function TestResponseDeflateStream (line 1503) | func TestResponseDeflateStream(t *testing.T) {
function TestResponseDeflate (line 1526) | func TestResponseDeflate(t *testing.T) {
function TestResponseGzip (line 1534) | func TestResponseGzip(t *testing.T) {
function testResponseDeflate (line 1542) | func testResponseDeflate(t *testing.T, s string) {
function testResponseDeflateExt (line 1554) | func testResponseDeflateExt(t *testing.T, r *Response, s string) {
function testResponseGzip (line 1595) | func testResponseGzip(t *testing.T, s string) {
function testResponseGzipExt (line 1607) | func testResponseGzipExt(t *testing.T, r *Response, s string) {
function isCompressibleResponse (line 1648) | func isCompressibleResponse(r *Response, s string) bool {
function TestRequestMultipartForm (line 1656) | func TestRequestMultipartForm(t *testing.T) {
function testRequestMultipartForm (line 1696) | func testRequestMultipartForm(t *testing.T, boundary string, formData []...
function TestResponseReadLimitBody (line 1741) | func TestResponseReadLimitBody(t *testing.T) {
function TestRequestReadLimitBody (line 1761) | func TestRequestReadLimitBody(t *testing.T) {
function testResponseReadLimitBodyError (line 1776) | func testResponseReadLimitBodyError(t *testing.T, s string, maxBodySize ...
function testResponseReadLimitBodySuccess (line 1789) | func testResponseReadLimitBodySuccess(t *testing.T, s string, maxBodySiz...
function testRequestReadLimitBodyError (line 1800) | func testRequestReadLimitBodyError(t *testing.T, s string, maxBodySize i...
function testRequestReadLimitBodySuccess (line 1813) | func testRequestReadLimitBodySuccess(t *testing.T, s string, maxBodySize...
function TestRequestString (line 1824) | func TestRequestString(t *testing.T) {
function TestRequestBodyWriter (line 1836) | func TestRequestBodyWriter(t *testing.T) {
function TestResponseBodyWriter (line 1847) | func TestResponseBodyWriter(t *testing.T) {
function TestRequestWriteRequestURINoHost (line 1860) | func TestRequestWriteRequestURINoHost(t *testing.T) {
function TestSetRequestBodyStreamFixedSize (line 1896) | func TestSetRequestBodyStreamFixedSize(t *testing.T) {
function TestSetResponseBodyStreamFixedSize (line 1904) | func TestSetResponseBodyStreamFixedSize(t *testing.T) {
function TestSetRequestBodyStreamChunked (line 1912) | func TestSetRequestBodyStreamChunked(t *testing.T) {
function TestSetResponseBodyStreamChunked (line 1924) | func TestSetResponseBodyStreamChunked(t *testing.T) {
function testSetRequestBodyStream (line 1936) | func testSetRequestBodyStream(t *testing.T, body string) {
function testSetRequestBodyStreamChunked (line 1969) | func testSetRequestBodyStreamChunked(t *testing.T, body string, trailer ...
function testSetResponseBodyStream (line 2016) | func testSetResponseBodyStream(t *testing.T, body string) {
function testSetResponseBodyStreamChunked (line 2046) | func testSetResponseBodyStreamChunked(t *testing.T, body string, trailer...
function TestRequestReadChunked (line 2090) | func TestRequestReadChunked(t *testing.T) {
function TestRequestChunkedEmpty (line 2110) | func TestRequestChunkedEmpty(t *testing.T) {
function TestRequestChunkedWhitespace (line 2130) | func TestRequestChunkedWhitespace(t *testing.T) {
function TestResponseReadWithoutBody (line 2148) | func TestResponseReadWithoutBody(t *testing.T) {
function testResponseReadWithoutBody (line 2170) | func testResponseReadWithoutBody(t *testing.T, resp *Response, s string,...
function TestRequestSuccess (line 2193) | func TestRequestSuccess(t *testing.T) {
function TestResponseSuccess (line 2218) | func TestResponseSuccess(t *testing.T) {
function testResponseSuccess (line 2242) | func testResponseSuccess(t *testing.T, statusCode int, contentType, serv...
function TestRequestWriteError (line 2283) | func TestRequestWriteError(t *testing.T) {
function testRequestWriteError (line 2290) | func testRequestWriteError(t *testing.T, method, requestURI, host, userA...
function testRequestSuccess (line 2307) | func testRequestSuccess(t *testing.T, method, requestURI, host, userAgen...
function TestResponseReadSuccess (line 2360) | func TestResponseReadSuccess(t *testing.T) {
function TestResponseReadError (line 2416) | func TestResponseReadError(t *testing.T) {
function testResponseReadError (line 2439) | func testResponseReadError(t *testing.T, resp *Response, response string) {
function testResponseReadSuccess (line 2451) | func testResponseReadSuccess(t *testing.T, resp *Response, response stri...
function TestReadBodyFixedSize (line 2468) | func TestReadBodyFixedSize(t *testing.T) {
function TestReadBodyChunked (line 2487) | func TestReadBodyChunked(t *testing.T) {
function TestRequestURITLS (line 2506) | func TestRequestURITLS(t *testing.T) {
function TestRequestURI (line 2530) | func TestRequestURI(t *testing.T) {
function TestRequestPostArgsSuccess (line 2562) | func TestRequestPostArgsSuccess(t *testing.T) {
function TestRequestPostArgsError (line 2572) | func TestRequestPostArgsError(t *testing.T) {
function testRequestPostArgsError (line 2584) | func testRequestPostArgsError(t *testing.T, req *Request, s string) {
function testRequestPostArgsSuccess (line 2597) | func testRequestPostArgsSuccess(t *testing.T, req *Request, s string, ex...
function testReadBodyChunked (line 2620) | func testReadBodyChunked(t *testing.T, bodySize int) {
function testReadBodyFixedSize (line 2636) | func testReadBodyFixedSize(t *testing.T, bodySize int) {
function createFixedBody (line 2649) | func createFixedBody(bodySize int) []byte {
function createChunkedBody (line 2657) | func createChunkedBody(body []byte, trailer map[string]string, withEnd b...
function TestWriteMultipartForm (line 2683) | func TestWriteMultipartForm(t *testing.T) {
function TestResponseRawBodySet (line 2713) | func TestResponseRawBodySet(t *testing.T) {
function TestRequestRawBodySet (line 2725) | func TestRequestRawBodySet(t *testing.T) {
function TestResponseRawBodyReset (line 2737) | func TestResponseRawBodyReset(t *testing.T) {
function TestRequestRawBodyReset (line 2749) | func TestRequestRawBodyReset(t *testing.T) {
function TestResponseRawBodyCopyTo (line 2761) | func TestResponseRawBodyCopyTo(t *testing.T) {
function TestRequestRawBodyCopyTo (line 2773) | func TestRequestRawBodyCopyTo(t *testing.T) {
type testReader (line 2789) | type testReader struct
method Read (line 2795) | func (r *testReader) Read(b []byte) (int, error) {
method Close (line 2811) | func (r *testReader) Close() error {
function TestResponseImmediateHeaderFlushRegressionFixedLength (line 2818) | func TestResponseImmediateHeaderFlushRegressionFixedLength(t *testing.T) {
function TestResponseImmediateHeaderFlushRegressionChunked (line 2831) | func TestResponseImmediateHeaderFlushRegressionChunked(t *testing.T) {
function TestResponseImmediateHeaderFlushFixedLength (line 2844) | func TestResponseImmediateHeaderFlushFixedLength(t *testing.T) {
function TestResponseImmediateHeaderFlushFixedLengthSkipBody (line 2888) | func TestResponseImmediateHeaderFlushFixedLengthSkipBody(t *testing.T) {
function TestResponseImmediateHeaderFlushChunked (line 2923) | func TestResponseImmediateHeaderFlushChunked(t *testing.T) {
function TestResponseImmediateHeaderFlushChunkedNoBody (line 2968) | func TestResponseImmediateHeaderFlushChunkedNoBody(t *testing.T) {
type ErroneousBodyStream (line 3003) | type ErroneousBodyStream struct
method Read (line 3008) | func (ebs *ErroneousBodyStream) Read(p []byte) (n int, err error) {
method Close (line 3015) | func (ebs *ErroneousBodyStream) Close() error {
function TestResponseBodyStreamErrorOnPanicDuringRead (line 3022) | func TestResponseBodyStreamErrorOnPanicDuringRead(t *testing.T) {
function TestResponseBodyStreamErrorOnPanicDuringClose (line 3043) | func TestResponseBodyStreamErrorOnPanicDuringClose(t *testing.T) {
function TestResponseBodyStream (line 3064) | func TestResponseBodyStream(t *testing.T) {
function TestRequestMultipartFormPipeEmptyFormField (line 3216) | func TestRequestMultipartFormPipeEmptyFormField(t *testing.T) {
function testRequestMultipartFormPipeEmptyFormField (line 3256) | func testRequestMultipartFormPipeEmptyFormField(t *testing.T, boundary s...
function TestReqCopeToRace (line 3299) | func TestReqCopeToRace(t *testing.T) {
function TestRespCopeToRace (line 3315) | func TestRespCopeToRace(t *testing.T) {
function TestRequestGetTimeOut (line 3331) | func TestRequestGetTimeOut(t *testing.T) {
FILE: http_timing_test.go
function BenchmarkCopyZeroAllocOSFileToBytesBuffer (line 12) | func BenchmarkCopyZeroAllocOSFileToBytesBuffer(b *testing.B) {
function BenchmarkCopyZeroAllocBytesBufferToOSFile (line 31) | func BenchmarkCopyZeroAllocBytesBufferToOSFile(b *testing.B) {
function BenchmarkCopyZeroAllocOSFileToStringsBuilder (line 69) | func BenchmarkCopyZeroAllocOSFileToStringsBuilder(b *testing.B) {
function BenchmarkCopyZeroAllocIOLimitedReaderToOSFile (line 88) | func BenchmarkCopyZeroAllocIOLimitedReaderToOSFile(b *testing.B) {
function BenchmarkCopyZeroAllocOSFileToOSFile (line 122) | func BenchmarkCopyZeroAllocOSFileToOSFile(b *testing.B) {
function BenchmarkCopyZeroAllocOSFileToNetConn (line 154) | func BenchmarkCopyZeroAllocOSFileToNetConn(b *testing.B) {
function BenchmarkCopyZeroAllocNetConnToOSFile (line 207) | func BenchmarkCopyZeroAllocNetConnToOSFile(b *testing.B) {
FILE: ipv6.go
function validateIPv6Literal (line 14) | func validateIPv6Literal(host []byte) error {
function parseIPv6Hextets (line 85) | func parseIPv6Hextets(s []byte, allowTrailingColon bool) (groups int, se...
function validIPv4 (line 146) | func validIPv4(s []byte) bool {
FILE: ipv6_test.go
function oracleValid (line 15) | func oracleValid(host []byte) bool {
function FuzzValidateIPv6Literal (line 51) | func FuzzValidateIPv6Literal(f *testing.F) {
FILE: lbclient.go
type BalancingClient (line 11) | type BalancingClient interface
type LBClient (line 27) | type LBClient struct
method DoDeadline (line 64) | func (cc *LBClient) DoDeadline(req *Request, resp *Response, deadline ...
method DoTimeout (line 69) | func (cc *LBClient) DoTimeout(req *Request, resp *Response, timeout ti...
method Do (line 76) | func (cc *LBClient) Do(req *Request, resp *Response) error {
method init (line 84) | func (cc *LBClient) init() {
method AddClient (line 101) | func (cc *LBClient) AddClient(c BalancingClient) int {
method RemoveClients (line 114) | func (cc *LBClient) RemoveClients(rc func(BalancingClient) bool) int {
method get (line 131) | func (cc *LBClient) get() *lbClient {
constant DefaultLBClientTimeout (line 61) | DefaultLBClientTimeout = time.Second
type lbClient (line 153) | type lbClient struct
method DoDeadline (line 162) | func (c *lbClient) DoDeadline(req *Request, resp *Response, deadline t...
method PendingRequests (line 174) | func (c *lbClient) PendingRequests() int {
method isHealthy (line 180) | func (c *lbClient) isHealthy(req *Request, resp *Response, err error) ...
method incPenalty (line 187) | func (c *lbClient) incPenalty() bool {
method decPenalty (line 196) | func (c *lbClient) decPenalty() {
constant maxPenalty (line 201) | maxPenalty = 300
constant penaltyDuration (line 203) | penaltyDuration = 3 * time.Second
FILE: lbclient_example_test.go
function ExampleLBClient (line 10) | func ExampleLBClient() {
FILE: methods.go
constant MethodGet (line 5) | MethodGet = "GET"
constant MethodHead (line 6) | MethodHead = "HEAD"
constant MethodPost (line 7) | MethodPost = "POST"
constant MethodPut (line 8) | MethodPut = "PUT"
constant MethodPatch (line 9) | MethodPatch = "PATCH"
constant MethodDelete (line 10) | MethodDelete = "DELETE"
constant MethodConnect (line 11) | MethodConnect = "CONNECT"
constant MethodOptions (line 12) | MethodOptions = "OPTIONS"
constant MethodTrace (line 13) | MethodTrace = "TRACE"
FILE: nocopy.go
type noCopy (line 8) | type noCopy struct
method Lock (line 10) | func (*noCopy) Lock() {}
method Unlock (line 11) | func (*noCopy) Unlock() {}
FILE: peripconn.go
type perIPConnCounter (line 10) | type perIPConnCounter struct
method Register (line 17) | func (cc *perIPConnCounter) Register(ip uint32) int {
method Unregister (line 28) | func (cc *perIPConnCounter) Unregister(ip uint32) {
type perIPConn (line 39) | type perIPConn struct
method Close (line 87) | func (c *perIPConn) Close() error {
type perIPTLSConn (line 48) | type perIPTLSConn struct
method Close (line 103) | func (c *perIPTLSConn) Close() error {
function acquirePerIPConn (line 57) | func acquirePerIPConn(conn net.Conn, ip uint32, counter *perIPConnCounte...
function getUint32IP (line 119) | func getUint32IP(c net.Conn) uint32 {
function getConnIP4 (line 123) | func getConnIP4(c net.Conn) net.IP {
function ip2uint32 (line 132) | func ip2uint32(ip net.IP) uint32 {
function uint322ip (line 139) | func uint322ip(ip uint32) net.IP {
FILE: peripconn_test.go
function TestIPxUint32 (line 9) | func TestIPxUint32(t *testing.T) {
function testIPxUint32 (line 17) | func testIPxUint32(t *testing.T, n uint32) {
function TestPerIPConnCounter (line 25) | func TestPerIPConnCounter(t *testing.T) {
FILE: pprofhandler/pprof.go
function PprofHandler (line 24) | func PprofHandler(ctx *fasthttp.RequestCtx) {
FILE: prefork/prefork.go
constant preforkChildEnvVariable (line 17) | preforkChildEnvVariable = "FASTHTTP_PREFORK_CHILD"
constant defaultNetwork (line 18) | defaultNetwork = "tcp4"
type Logger (line 32) | type Logger interface
type Prefork (line 45) | type Prefork struct
method logger (line 90) | func (p *Prefork) logger() Logger {
method listen (line 97) | func (p *Prefork) listen(addr string) (net.Listener, error) {
method setTCPListenerFiles (line 111) | func (p *Prefork) setTCPListenerFiles(addr string) error {
method doCommand (line 138) | func (p *Prefork) doCommand() (*exec.Cmd, error) {
method prefork (line 160) | func (p *Prefork) prefork(addr string) (err error) {
method ListenAndServe (line 237) | func (p *Prefork) ListenAndServe(addr string) error {
method ListenAndServeTLS (line 255) | func (p *Prefork) ListenAndServeTLS(addr, certKey, certFile string) er...
method ListenAndServeTLSEmbed (line 273) | func (p *Prefork) ListenAndServeTLSEmbed(addr string, certData, keyDat...
function IsChild (line 74) | func IsChild() bool {
function New (line 79) | func New(s *fasthttp.Server) *Prefork {
FILE: prefork/prefork_test.go
function setUp (line 15) | func setUp() {
function tearDown (line 19) | func tearDown() {
function getAddr (line 23) | func getAddr() string {
function Test_IsChild (line 27) | func Test_IsChild(t *testing.T) {
function Test_New (line 44) | func Test_New(t *testing.T) {
function Test_listen (line 67) | func Test_listen(t *testing.T) {
function Test_setTCPListenerFiles (line 97) | func Test_setTCPListenerFiles(t *testing.T) {
function Test_ListenAndServe (line 132) | func Test_ListenAndServe(t *testing.T) {
function Test_ListenAndServeTLS (line 164) | func Test_ListenAndServeTLS(t *testing.T) {
function Test_ListenAndServeTLSEmbed (line 196) | func Test_ListenAndServeTLSEmbed(t *testing.T) {
FILE: requestctx_setbodystreamwriter_example_test.go
function ExampleRequestCtx_SetBodyStreamWriter (line 12) | func ExampleRequestCtx_SetBodyStreamWriter() {
function responseStreamHandler (line 19) | func responseStreamHandler(ctx *fasthttp.RequestCtx) {
FILE: reuseport/reuseport.go
function Listen (line 31) | func Listen(network, addr string) (net.Listener, error) {
FILE: reuseport/reuseport_aix.go
function Listen (line 23) | func Listen(network, addr string) (net.Listener, error) {
FILE: reuseport/reuseport_error.go
type ErrNoReusePort (line 8) | type ErrNoReusePort struct
method Error (line 13) | func (e *ErrNoReusePort) Error() string {
FILE: reuseport/reuseport_example_test.go
function ExampleListen (line 11) | func ExampleListen() {
function requestHandler (line 22) | func requestHandler(ctx *fasthttp.RequestCtx) {
FILE: reuseport/reuseport_solaris.go
constant _SO_REUSEPORT (line 14) | _SO_REUSEPORT = 0x100e
function Listen (line 29) | func Listen(network, addr string) (net.Listener, error) {
FILE: reuseport/reuseport_test.go
function TestTCP4 (line 8) | func TestTCP4(t *testing.T) {
function TestTCP6 (line 14) | func TestTCP6(t *testing.T) {
function hasLocalIPv6 (line 23) | func hasLocalIPv6(t *testing.T) bool {
function testNewListener (line 36) | func testNewListener(t *testing.T, network, addr string) {
FILE: reuseport/reuseport_windows.go
function Listen (line 21) | func Listen(network, addr string) (net.Listener, error) {
FILE: round2_32.go
function roundUpForSliceCap (line 7) | func roundUpForSliceCap(n int) int {
FILE: round2_32_test.go
function TestRound2ForSliceCap (line 10) | func TestRound2ForSliceCap(t *testing.T) {
function testRound2ForSliceCap (line 27) | func testRound2ForSliceCap(t *testing.T, n, expectedRound2 int) {
FILE: round2_64.go
function roundUpForSliceCap (line 5) | func roundUpForSliceCap(n int) int {
FILE: round2_64_test.go
function TestRound2ForSliceCap (line 10) | func TestRound2ForSliceCap(t *testing.T) {
function testRound2ForSliceCap (line 28) | func testRound2ForSliceCap(t *testing.T, n, expectedRound2 int) {
FILE: s2b.go
function s2b (line 6) | func s2b(s string) []byte {
FILE: server.go
function ServeConn (line 37) | func ServeConn(c net.Conn, handler RequestHandler) error {
function Serve (line 56) | func Serve(ln net.Listener, handler RequestHandler) error {
function ServeTLS (line 67) | func ServeTLS(ln net.Listener, certFile, keyFile string, handler Request...
function ServeTLSEmbed (line 78) | func ServeTLSEmbed(ln net.Listener, certData, keyData []byte, handler Re...
function ListenAndServe (line 87) | func ListenAndServe(addr string, handler RequestHandler) error {
function ListenAndServeUNIX (line 100) | func ListenAndServeUNIX(addr string, mode os.FileMode, handler RequestHa...
function ListenAndServeTLS (line 111) | func ListenAndServeTLS(addr, certFile, keyFile string, handler RequestHa...
function ListenAndServeTLSEmbed (line 122) | func ListenAndServeTLSEmbed(addr string, certData, keyData []byte, handl...
type RequestHandler (line 135) | type RequestHandler
type ServeHandler (line 138) | type ServeHandler
type Server (line 149) | type Server struct
method NextProto (line 1670) | func (s *Server) NextProto(key string, nph ServeHandler) {
method getNextProto (line 1680) | func (s *Server) getNextProto(c net.Conn) (string, error) {
method ListenAndServe (line 1708) | func (s *Server) ListenAndServe(addr string) error {
method ListenAndServeUNIX (line 1721) | func (s *Server) ListenAndServeUNIX(addr string, mode os.FileMode) err...
method ListenAndServeTLS (line 1746) | func (s *Server) ListenAndServeTLS(addr, certFile, keyFile string) err...
method ListenAndServeTLSEmbed (line 1765) | func (s *Server) ListenAndServeTLSEmbed(addr string, certData, keyData...
method ServeTLS (line 1779) | func (s *Server) ServeTLS(ln net.Listener, certFile, keyFile string) e...
method ServeTLSEmbed (line 1803) | func (s *Server) ServeTLSEmbed(ln net.Listener, certData, keyData []by...
method AppendCert (line 1825) | func (s *Server) AppendCert(certFile, keyFile string) error {
method AppendCertEmbed (line 1842) | func (s *Server) AppendCertEmbed(certData, keyData []byte) error {
method configTLS (line 1859) | func (s *Server) configTLS() {
method Serve (line 1872) | func (s *Server) Serve(ln net.Listener) error {
method Shutdown (line 1952) | func (s *Server) Shutdown() error {
method ShutdownWithContext (line 1967) | func (s *Server) ShutdownWithContext(ctx context.Context) (err error) {
method logger (line 2078) | func (s *Server) logger() Logger {
method ServeConn (line 2104) | func (s *Server) ServeConn(c net.Conn) error {
method GetCurrentConcurrency (line 2146) | func (s *Server) GetCurrentConcurrency() uint32 {
method GetOpenConnectionsCount (line 2153) | func (s *Server) GetOpenConnectionsCount() int32 {
method GetRejectedConnectionsCount (line 2168) | func (s *Server) GetRejectedConnectionsCount() uint32 {
method getConcurrency (line 2172) | func (s *Server) getConcurrency() int {
method idleTimeout (line 2192) | func (s *Server) idleTimeout() time.Duration {
method serveConnCleanup (line 2199) | func (s *Server) serveConnCleanup() {
method serveConn (line 2204) | func (s *Server) serveConn(c net.Conn) error {
method setState (line 2633) | func (s *Server) setState(nc net.Conn, state ConnState) {
method acquireHijackConn (line 2653) | func (s *Server) acquireHijackConn(r io.Reader, c net.Conn) *hijackConn {
method releaseHijackConn (line 2669) | func (s *Server) releaseHijackConn(hjc *hijackConn) {
method acquireCtx (line 2792) | func (s *Server) acquireCtx(c net.Conn) (ctx *RequestCtx) {
method releaseCtx (line 2936) | func (s *Server) releaseCtx(ctx *RequestCtx) {
method getServerName (line 2946) | func (s *Server) getServerName() string {
method writeFastError (line 2956) | func (s *Server) writeFastError(w io.Writer, statusCode int, msg strin...
method writeErrorResponse (line 2989) | func (s *Server) writeErrorResponse(bw *bufio.Writer, ctx *RequestCtx,...
method closeIdleConns (line 3014) | func (s *Server) closeIdleConns() {
method closeListenersLocked (line 3028) | func (s *Server) closeListenersLocked() error {
function TimeoutHandler (line 454) | func TimeoutHandler(h RequestHandler, timeout time.Duration, msg string)...
function TimeoutWithCodeHandler (line 465) | func TimeoutWithCodeHandler(h RequestHandler, timeout time.Duration, msg...
type RequestConfig (line 500) | type RequestConfig struct
function CompressHandler (line 517) | func CompressHandler(h RequestHandler) RequestHandler {
function CompressHandlerLevel (line 532) | func CompressHandlerLevel(h RequestHandler, level int) RequestHandler {
function CompressHandlerBrotliLevel (line 564) | func CompressHandlerBrotliLevel(h RequestHandler, brotliLevel, otherLeve...
type RequestCtx (line 594) | type RequestCtx struct
method EarlyHints (line 650) | func (ctx *RequestCtx) EarlyHints() error {
method Hijack (line 731) | func (ctx *RequestCtx) Hijack(handler HijackHandler) {
method HijackSetNoResponse (line 740) | func (ctx *RequestCtx) HijackSetNoResponse(noResponse bool) {
method Hijacked (line 745) | func (ctx *RequestCtx) Hijacked() bool {
method SetUserValue (line 760) | func (ctx *RequestCtx) SetUserValue(key, value any) {
method SetUserValueBytes (line 773) | func (ctx *RequestCtx) SetUserValueBytes(key []byte, value any) {
method UserValue (line 778) | func (ctx *RequestCtx) UserValue(key any) any {
method UserValueBytes (line 784) | func (ctx *RequestCtx) UserValueBytes(key []byte) any {
method VisitUserValues (line 792) | func (ctx *RequestCtx) VisitUserValues(visitor func([]byte, any)) {
method VisitUserValuesAll (line 800) | func (ctx *RequestCtx) VisitUserValuesAll(visitor func(any, any)) {
method ResetUserValues (line 805) | func (ctx *RequestCtx) ResetUserValues() {
method RemoveUserValue (line 810) | func (ctx *RequestCtx) RemoveUserValue(key any) {
method RemoveUserValueBytes (line 815) | func (ctx *RequestCtx) RemoveUserValueBytes(key []byte) {
method IsTLS (line 827) | func (ctx *RequestCtx) IsTLS() bool {
method TLSConnectionState (line 853) | func (ctx *RequestCtx) TLSConnectionState() *tls.ConnectionState {
method Conn (line 867) | func (ctx *RequestCtx) Conn() net.Conn {
method reset (line 871) | func (ctx *RequestCtx) reset() {
method String (line 955) | func (ctx *RequestCtx) String() string {
method ID (line 961) | func (ctx *RequestCtx) ID() uint64 {
method ConnID (line 969) | func (ctx *RequestCtx) ConnID() uint64 {
method Time (line 974) | func (ctx *RequestCtx) Time() time.Time {
method ConnTime (line 980) | func (ctx *RequestCtx) ConnTime() time.Time {
method ConnRequestNum (line 988) | func (ctx *RequestCtx) ConnRequestNum() uint64 {
method SetConnectionClose (line 994) | func (ctx *RequestCtx) SetConnectionClose() {
method SetStatusCode (line 999) | func (ctx *RequestCtx) SetStatusCode(statusCode int) {
method SetContentType (line 1004) | func (ctx *RequestCtx) SetContentType(contentType string) {
method SetContentTypeBytes (line 1011) | func (ctx *RequestCtx) SetContentTypeBytes(contentType []byte) {
method RequestURI (line 1018) | func (ctx *RequestCtx) RequestURI() []byte {
method URI (line 1025) | func (ctx *RequestCtx) URI() *URI {
method Referer (line 1032) | func (ctx *RequestCtx) Referer() []byte {
method UserAgent (line 1039) | func (ctx *RequestCtx) UserAgent() []byte {
method Path (line 1046) | func (ctx *RequestCtx) Path() []byte {
method Host (line 1053) | func (ctx *RequestCtx) Host() []byte {
method QueryArgs (line 1064) | func (ctx *RequestCtx) QueryArgs() *Args {
method PostArgs (line 1075) | func (ctx *RequestCtx) PostArgs() *Args {
method MultipartForm (line 1096) | func (ctx *RequestCtx) MultipartForm() (*multipart.Form, error) {
method MultipartFormWithLimit (line 1107) | func (ctx *RequestCtx) MultipartFormWithLimit(maxBodySize int) (*multi...
method FormFile (line 1122) | func (ctx *RequestCtx) FormFile(key string) (*multipart.FileHeader, er...
method FormValue (line 1210) | func (ctx *RequestCtx) FormValue(key string) []byte {
method IsGet (line 1265) | func (ctx *RequestCtx) IsGet() bool {
method IsPost (line 1270) | func (ctx *RequestCtx) IsPost() bool {
method IsPut (line 1275) | func (ctx *RequestCtx) IsPut() bool {
method IsDelete (line 1280) | func (ctx *RequestCtx) IsDelete() bool {
method IsConnect (line 1285) | func (ctx *RequestCtx) IsConnect() bool {
method IsOptions (line 1290) | func (ctx *RequestCtx) IsOptions() bool {
method IsTrace (line 1295) | func (ctx *RequestCtx) IsTrace() bool {
method IsPatch (line 1300) | func (ctx *RequestCtx) IsPatch() bool {
method Method (line 1307) | func (ctx *RequestCtx) Method() []byte {
method IsHead (line 1312) | func (ctx *RequestCtx) IsHead() bool {
method RemoteAddr (line 1319) | func (ctx *RequestCtx) RemoteAddr() net.Addr {
method SetRemoteAddr (line 1337) | func (ctx *RequestCtx) SetRemoteAddr(remoteAddr net.Addr) {
method LocalAddr (line 1344) | func (ctx *RequestCtx) LocalAddr() net.Addr {
method RemoteIP (line 1358) | func (ctx *RequestCtx) RemoteIP() net.IP {
method LocalIP (line 1365) | func (ctx *RequestCtx) LocalIP() net.IP {
method Error (line 1381) | func (ctx *RequestCtx) Error(msg string, statusCode int) {
method Success (line 1389) | func (ctx *RequestCtx) Success(contentType string, body []byte) {
method SuccessString (line 1395) | func (ctx *RequestCtx) SuccessString(contentType, body string) {
method Redirect (line 1419) | func (ctx *RequestCtx) Redirect(uri string, statusCode int) {
method RedirectBytes (line 1447) | func (ctx *RequestCtx) RedirectBytes(uri []byte, statusCode int) {
method redirect (line 1452) | func (ctx *RequestCtx) redirect(uri []byte, statusCode int) {
method SetBody (line 1470) | func (ctx *RequestCtx) SetBody(body []byte) {
method SetBodyString (line 1475) | func (ctx *RequestCtx) SetBodyString(body string) {
method ResetBody (line 1480) | func (ctx *RequestCtx) ResetBody() {
method SendFile (line 1495) | func (ctx *RequestCtx) SendFile(path string) {
method SendFileBytes (line 1510) | func (ctx *RequestCtx) SendFileBytes(path []byte) {
method IfModifiedSince (line 1518) | func (ctx *RequestCtx) IfModifiedSince(lastModified time.Time) bool {
method NotModified (line 1532) | func (ctx *RequestCtx) NotModified() {
method NotFound (line 1538) | func (ctx *RequestCtx) NotFound() {
method Write (line 1545) | func (ctx *RequestCtx) Write(p []byte) (int, error) {
method WriteString (line 1551) | func (ctx *RequestCtx) WriteString(s string) (int, error) {
method PostBody (line 1559) | func (ctx *RequestCtx) PostBody() []byte {
method SetBodyStream (line 1574) | func (ctx *RequestCtx) SetBodyStream(bodyStream io.Reader, bodySize in...
method SetBodyStreamWriter (line 1589) | func (ctx *RequestCtx) SetBodyStreamWriter(sw StreamWriter) {
method IsBodyStream (line 1594) | func (ctx *RequestCtx) IsBodyStream() bool {
method Logger (line 1609) | func (ctx *RequestCtx) Logger() Logger {
method TimeoutError (line 1629) | func (ctx *RequestCtx) TimeoutError(msg string) {
method TimeoutErrorWithCode (line 1643) | func (ctx *RequestCtx) TimeoutErrorWithCode(msg string, statusCode int) {
method TimeoutErrorWithResponse (line 1660) | func (ctx *RequestCtx) TimeoutErrorWithResponse(resp *Response) {
method LastTimeoutErrorResponse (line 2704) | func (ctx *RequestCtx) LastTimeoutErrorResponse() *Response {
method Init2 (line 2818) | func (ctx *RequestCtx) Init2(conn net.Conn, logger Logger, reduceMemor...
method Init (line 2837) | func (ctx *RequestCtx) Init(req *Request, remoteAddr net.Addr, logger ...
method Deadline (line 2858) | func (ctx *RequestCtx) Deadline() (deadline time.Time, ok bool) {
method Done (line 2868) | func (ctx *RequestCtx) Done() <-chan struct{} {
method Err (line 2881) | func (ctx *RequestCtx) Err() error {
method Value (line 2896) | func (ctx *RequestCtx) Value(key any) any {
type HijackHandler (line 705) | type HijackHandler
type connTLSer (line 819) | type connTLSer interface
type firstByteReader (line 901) | type firstByteReader struct
method reset (line 907) | func (r *firstByteReader) reset() {
method Read (line 913) | func (r *firstByteReader) Read(b []byte) (int, error) {
type Logger (line 929) | type Logger interface
type ctxLogger (line 936) | type ctxLogger struct
method Printf (line 941) | func (cl *ctxLogger) Printf(format string, args ...any) {
function SaveMultipartFile (line 1142) | func SaveMultipartFile(fh *multipart.FileHeader, path string) (err error) {
type FormValueFunc (line 1218) | type FormValueFunc
function addrToIP (line 1369) | func addrToIP(addr net.Addr) net.IP {
function getRedirectStatusCode (line 1458) | func getRedirectStatusCode(statusCode int) int {
constant DefaultConcurrency (line 1867) | DefaultConcurrency = 256 * 1024
type connKeepAliveer (line 2010) | type connKeepAliveer interface
function acceptConn (line 2016) | func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Tim...
function wrapPerIPConn (line 2061) | func wrapPerIPConn(s *Server, c net.Conn) net.Conn {
function nextConnID (line 2182) | func nextConnID() uint64 {
constant DefaultMaxRequestBodySize (line 2190) | DefaultMaxRequestBodySize = 4 * 1024 * 1024
function hijackConnHandler (line 2639) | func hijackConnHandler(ctx *RequestCtx, r io.Reader, c net.Conn, s *Serv...
type hijackConn (line 2675) | type hijackConn struct
method UnsafeConn (line 2682) | func (c *hijackConn) UnsafeConn() net.Conn {
method Read (line 2686) | func (c *hijackConn) Read(p []byte) (int, error) {
method Close (line 2690) | func (c *hijackConn) Close() error {
function writeResponse (line 2708) | func writeResponse(ctx *RequestCtx, w *bufio.Writer) error {
constant defaultReadBufferSize (line 2718) | defaultReadBufferSize = 4096
constant defaultWriteBufferSize (line 2719) | defaultWriteBufferSize = 4096
function acquireByteReader (line 2722) | func acquireByteReader(ctxP **RequestCtx) (*bufio.Reader, error) {
function acquireReader (line 2756) | func acquireReader(ctx *RequestCtx) *bufio.Reader {
function releaseReader (line 2770) | func releaseReader(s *Server, r *bufio.Reader) {
function acquireWriter (line 2774) | func acquireWriter(ctx *RequestCtx) *bufio.Writer {
function releaseWriter (line 2788) | func releaseWriter(s *Server, w *bufio.Writer) {
type fakeAddrer (line 2906) | type fakeAddrer struct
method RemoteAddr (line 2913) | func (fa *fakeAddrer) RemoteAddr() net.Addr {
method LocalAddr (line 2917) | func (fa *fakeAddrer) LocalAddr() net.Addr {
method Read (line 2921) | func (fa *fakeAddrer) Read(p []byte) (int, error) {
method Write (line 2926) | func (fa *fakeAddrer) Write(p []byte) (int, error) {
method Close (line 2931) | func (fa *fakeAddrer) Close() error {
function defaultErrorHandler (line 2979) | func defaultErrorHandler(ctx *RequestCtx, err error) {
type ConnState (line 3041) | type ConnState
method String (line 3087) | func (c ConnState) String() string {
constant StateNew (line 3048) | StateNew ConnState = iota
constant StateActive (line 3061) | StateActive
constant StateIdle (line 3067) | StateIdle
constant StateHijacked (line 3071) | StateHijacked
constant StateClosed (line 3076) | StateClosed
FILE: server_example_test.go
function ExampleListenAndServe (line 13) | func ExampleListenAndServe() {
function ExampleServe (line 34) | func ExampleServe() {
function ExampleServer (line 62) | func ExampleServer() {
function ExampleRequestCtx_Hijack (line 89) | func ExampleRequestCtx_Hijack() {
function ExampleRequestCtx_TimeoutError (line 127) | func ExampleRequestCtx_TimeoutError() {
function ExampleRequestCtx_Logger (line 158) | func ExampleRequestCtx_Logger() {
FILE: server_race_test.go
function TestServerDoneRace (line 13) | func TestServerDoneRace(t *testing.T) {
FILE: server_test.go
type closerWithRequestCtx (line 29) | type closerWithRequestCtx struct
method Close (line 34) | func (c *closerWithRequestCtx) Close() error {
function TestServerCRNLAfterPost_Pipeline (line 38) | func TestServerCRNLAfterPost_Pipeline(t *testing.T) {
function TestServerCRNLAfterPost (line 83) | func TestServerCRNLAfterPost(t *testing.T) {
function TestServerPipelineFlush (line 126) | func TestServerPipelineFlush(t *testing.T) {
function TestServerInvalidHeader (line 187) | func TestServerInvalidHeader(t *testing.T) {
function TestServerConnState (line 249) | func TestServerConnState(t *testing.T) {
function TestSaveMultipartFile (line 322) | func TestSaveMultipartFile(t *testing.T) {
function TestServerName (line 379) | func TestServerName(t *testing.T) {
function TestRequestCtxString (line 442) | func TestRequestCtxString(t *testing.T) {
function TestServerErrSmallBuffer (line 461) | func TestServerErrSmallBuffer(t *testing.T) {
function TestRequestCtxIsTLS (line 509) | func TestRequestCtxIsTLS(t *testing.T) {
function TestRequestCtxRedirectHTTPSSchemeless (line 542) | func TestRequestCtxRedirectHTTPSSchemeless(t *testing.T) {
function TestRequestCtxRedirect (line 562) | func TestRequestCtxRedirect(t *testing.T) {
function testRequestCtxRedirect (line 587) | func testRequestCtxRedirect(t *testing.T, origURL, redirectURL, expected...
function TestServerResponseServerHeader (line 600) | func TestServerResponseServerHeader(t *testing.T) {
function TestServerResponseBodyStream (line 677) | func TestServerResponseBodyStream(t *testing.T) {
function TestServerDisableKeepalive (line 768) | func TestServerDisableKeepalive(t *testing.T) {
function TestServerMaxConnsPerIPLimit (line 841) | func TestServerMaxConnsPerIPLimit(t *testing.T) {
type fakeIPListener (line 919) | type fakeIPListener struct
method Accept (line 923) | func (ln *fakeIPListener) Accept() (net.Conn, error) {
type fakeIPConn (line 933) | type fakeIPConn struct
method RemoteAddr (line 937) | func (conn *fakeIPConn) RemoteAddr() net.Addr {
function TestServerConcurrencyLimit (line 945) | func TestServerConcurrencyLimit(t *testing.T) {
function TestRejectedRequestsCount (line 1020) | func TestRejectedRequestsCount(t *testing.T) {
function TestServerWriteFastError (line 1081) | func TestServerWriteFastError(t *testing.T) {
function TestServerTLS (line 1116) | func TestServerTLS(t *testing.T) {
function TestServerTLSReadTimeout (line 1166) | func TestServerTLSReadTimeout(t *testing.T) {
function TestServerServeTLSEmbed (line 1218) | func TestServerServeTLSEmbed(t *testing.T) {
function TestServerMultipartFormDataRequest (line 1293) | func TestServerMultipartFormDataRequest(t *testing.T) {
function TestServerGetWithContent (line 1426) | func TestServerGetWithContent(t *testing.T) {
function TestServerDisableHeaderNamesNormalizing (line 1449) | func TestServerDisableHeaderNamesNormalizing(t *testing.T) {
function TestServerReduceMemoryUsageSerial (line 1496) | func TestServerReduceMemoryUsageSerial(t *testing.T) {
function TestServerReduceMemoryUsageConcurrent (line 1527) | func TestServerReduceMemoryUsageConcurrent(t *testing.T) {
function testServerRequests (line 1571) | func testServerRequests(t *testing.T, ln *fasthttputil.InmemoryListener) {
function TestServerHTTP10ConnectionKeepAlive (line 1603) | func TestServerHTTP10ConnectionKeepAlive(t *testing.T) {
function TestServerHTTP10ConnectionClose (line 1682) | func TestServerHTTP10ConnectionClose(t *testing.T) {
function TestRequestCtxFormValue (line 1757) | func TestRequestCtxFormValue(t *testing.T) {
function TestSetStandardFormValueFunc (line 1782) | func TestSetStandardFormValueFunc(t *testing.T) {
function TestRequestCtxUserValue (line 1797) | func TestRequestCtxUserValue(t *testing.T) {
function TestServerHeadRequest (line 1841) | func TestServerHeadRequest(t *testing.T) {
function TestServerRejectsBackslashInAbsoluteURI (line 1886) | func TestServerRejectsBackslashInAbsoluteURI(t *testing.T) {
function TestServerExpect100Continue (line 1918) | func TestServerExpect100Continue(t *testing.T) {
function TestServerExpect103EarlyHints (line 1959) | func TestServerExpect103EarlyHints(t *testing.T) {
function TestServerContinueHandler (line 2002) | func TestServerContinueHandler(t *testing.T) {
function TestCompressHandler (line 2081) | func TestCompressHandler(t *testing.T) {
function TestCompressHandlerVary (line 2178) | func TestCompressHandlerVary(t *testing.T) {
function TestRequestCtxWriteString (line 2319) | func TestRequestCtxWriteString(t *testing.T) {
function TestServeConnKeepRequestAndResponseUntilResetUserValues (line 2344) | func TestServeConnKeepRequestAndResponseUntilResetUserValues(t *testing....
function TestServerErrorHandler (line 2394) | func TestServerErr
Condensed preview — 157 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,481K chars).
[
{
"path": ".github/dependabot.yml",
"chars": 213,
"preview": "version: 2\r\nupdates:\r\n - package-ecosystem: \"github-actions\"\r\n directory: \"/\"\r\n schedule:\r\n interval: \"daily"
},
{
"path": ".github/workflows/cifuzz.yml",
"chars": 699,
"preview": "name: CIFuzz\non: [pull_request]\njobs:\n Fuzzing:\n runs-on: ubuntu-latest\n steps:\n - name: Build Fuzzers\n i"
},
{
"path": ".github/workflows/lint.yml",
"chars": 691,
"preview": "name: Lint\non:\n push:\n branches:\n - master\n pull_request:\n\npermissions:\n # Required: allow read access to the"
},
{
"path": ".github/workflows/security.yml",
"chars": 434,
"preview": "name: Security\non:\n push:\n branches:\n - master\n pull_request:\njobs:\n test:\n strategy:\n matrix:\n "
},
{
"path": ".github/workflows/test.yml",
"chars": 517,
"preview": "name: Test\non:\n push:\n branches:\n - master\n pull_request:\njobs:\n test:\n strategy:\n fail-fast: false\n "
},
{
"path": ".gitignore",
"chars": 102,
"preview": "tags\n*.pprof\n*.fasthttp.br\n*.fasthttp.zst\n*.fasthttp.gz\n.idea\n.vscode\n.DS_Store\nvendor/\ntestdata/fuzz\n"
},
{
"path": ".golangci.yml",
"chars": 1745,
"preview": "version: \"2\"\nlinters:\n default: all\n disable:\n - copyloopvar\n - cyclop\n - depguard\n - dupl\n - err113\n "
},
{
"path": "LICENSE",
"chars": 1158,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, Fas"
},
{
"path": "README.md",
"chars": 36531,
"preview": "# fasthttp\n\n[](https://pkg.go.dev/github.com/valyal"
},
{
"path": "SECURITY.md",
"chars": 2330,
"preview": "### TL;DR\n\nWe use a simplified version of [Golang Security Policy](https://go.dev/security).\nFor example, for now we ski"
},
{
"path": "TODO",
"chars": 197,
"preview": "- SessionClient with referer and cookies support.\n- ProxyHandler similar to FSHandler.\n- WebSockets. See https://tools.i"
},
{
"path": "allocation_test.go",
"chars": 2980,
"preview": "//go:build !race\n\npackage fasthttp\n\nimport (\n\t\"net\"\n\t\"testing\"\n)\n\nfunc TestAllocationServeConn(t *testing.T) {\n\ts := &Se"
},
{
"path": "args.go",
"chars": 15144,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"iter\"\n\t\"sort\"\n\t\"sync\"\n)\n\nconst (\n\targsNoValue = true\n\targsHasValu"
},
{
"path": "args_test.go",
"chars": 14761,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/valyala/byt"
},
{
"path": "args_timing_test.go",
"chars": 550,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc BenchmarkArgsParse(b *testing.B) {\n\ts := []byte(\"foo=bar&baz=qqq&"
},
{
"path": "b2s.go",
"chars": 266,
"preview": "package fasthttp\n\nimport \"unsafe\"\n\n// b2s converts byte slice to a string without memory allocation.\n// See https://grou"
},
{
"path": "brotli.go",
"chars": 5493,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/andybalholm/brotli\"\n\t\"github.com/valyala/bytebuff"
},
{
"path": "brotli_test.go",
"chars": 4542,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n)\n\nfunc TestBrotliBytesSerial(t *testing.T) {\n\tt.Pa"
},
{
"path": "bytesconv.go",
"chars": 7238,
"preview": "//go:generate go run bytesconv_table_gen.go\n\npackage fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n"
},
{
"path": "bytesconv_32.go",
"chars": 121,
"preview": "//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x\n\npackage fasthttp\n\nconst (\n\tmaxHexIntChars = 7\n)"
},
{
"path": "bytesconv_32_test.go",
"chars": 1289,
"preview": "//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x\n\npackage fasthttp\n\nimport (\n\t\"testing\"\n)\n\nfunc T"
},
{
"path": "bytesconv_64.go",
"chars": 116,
"preview": "//go:build amd64 || arm64 || ppc64 || ppc64le || riscv64 || s390x\n\npackage fasthttp\n\nconst (\n\tmaxHexIntChars = 15\n)\n"
},
{
"path": "bytesconv_64_test.go",
"chars": 1481,
"preview": "//go:build amd64 || arm64 || ppc64 || ppc64le || riscv64 || s390x\n\npackage fasthttp\n\nimport (\n\t\"testing\"\n)\n\nfunc TestWri"
},
{
"path": "bytesconv_table.go",
"chars": 7479,
"preview": "package fasthttp\n\n// Code generated by go run bytesconv_table_gen.go; DO NOT EDIT.\n// See bytesconv_table_gen.go for mor"
},
{
"path": "bytesconv_table_gen.go",
"chars": 5583,
"preview": "//go:build ignore\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n)\n\nconst (\n\ttoLower = 'a' - 'A'\n)\n\nfunc main() {\n"
},
{
"path": "bytesconv_test.go",
"chars": 9682,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"html\"\n\t\"net\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/valya"
},
{
"path": "bytesconv_timing_test.go",
"chars": 3939,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"html\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/valyala/bytebufferpool\"\n)\n\nfunc BenchmarkApp"
},
{
"path": "client.go",
"chars": 85350,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomi"
},
{
"path": "client_example_test.go",
"chars": 1056,
"preview": "package fasthttp_test\n\nimport (\n\t\"log\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc ExampleHostClient() {\n\t// Prepare a clien"
},
{
"path": "client_test.go",
"chars": 81067,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/ur"
},
{
"path": "client_timing_test.go",
"chars": 14248,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testi"
},
{
"path": "coarsetime.go",
"chars": 314,
"preview": "package fasthttp\n\nimport (\n\t\"time\"\n)\n\n// CoarseTimeNow returns the current time truncated to the nearest second.\n//\n// D"
},
{
"path": "compress.go",
"chars": 12388,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"sync\"\n\n\t\"github.com/klauspost/compress/flate\"\n\t\"github.com/k"
},
{
"path": "compress_test.go",
"chars": 5453,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar compressTestcases = func() []string"
},
{
"path": "cookie.go",
"chars": 15108,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar zeroTime time.Time\n\nvar (\n\t// CookieExpireDel"
},
{
"path": "cookie_test.go",
"chars": 11660,
"preview": "package fasthttp\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestCookiePanic(t *testing.T) {\n\tt.Parallel()\n\n\tvar c C"
},
{
"path": "cookie_timing_test.go",
"chars": 821,
"preview": "package fasthttp\n\nimport (\n\t\"testing\"\n)\n\nfunc BenchmarkCookieParseMin(b *testing.B) {\n\tvar c Cookie\n\ts := []byte(\"xxx=yy"
},
{
"path": "doc.go",
"chars": 1339,
"preview": "/*\nPackage fasthttp provides fast HTTP server and client API.\n\nFasthttp provides the following features:\n\n 1. Optimized "
},
{
"path": "examples/README.md",
"chars": 92,
"preview": "# Code examples\n\n* [HelloWorld server](helloworldserver)\n* [Static file server](fileserver)\n"
},
{
"path": "examples/host_client/.gitignore",
"chars": 11,
"preview": "hostclient\n"
},
{
"path": "examples/host_client/Makefile",
"chars": 95,
"preview": "host_client: clean\n\tgo get -u github.com/valyala/fasthttp\n\tgo build\n\nclean:\n\trm -f host_client\n"
},
{
"path": "examples/host_client/README.md",
"chars": 419,
"preview": "# Host Client Example\n\nThe HostClient is useful when calling an API from a single host.\nThe example also shows how to us"
},
{
"path": "examples/host_client/hostclient.go",
"chars": 819,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc main() {\n\t// Get URI from a pool\n\turl := fas"
},
{
"path": "examples/letsencrypt/letsencryptserver.go",
"chars": 825,
"preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"net\"\n\n\t\"github.com/valyala/fasthttp\"\n\t\"golang.org/x/crypto/acme\"\n\t\"golang.org/x/c"
},
{
"path": "examples/multidomain/Makefile",
"chars": 90,
"preview": "writer: clean\n\tgo get -u github.com/valyala/fasthttp\n\tgo build\n\nclean:\n\trm -f multidomain\n"
},
{
"path": "examples/multidomain/README.md",
"chars": 155,
"preview": "# Multidomain using SSL certs example\n\n* Prints two messages depending on visited host.\n\n# How to build\n\n```\nmake\n```\n\n#"
},
{
"path": "examples/multidomain/multidomain.go",
"chars": 1335,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nvar domains = make(map[string]fasthttp.RequestHandler)\n"
},
{
"path": "expvarhandler/expvar.go",
"chars": 1438,
"preview": "// Package expvarhandler provides fasthttp-compatible request handler\n// serving expvars.\npackage expvarhandler\n\nimport "
},
{
"path": "expvarhandler/expvar_test.go",
"chars": 1616,
"preview": "package expvarhandler\n\nimport (\n\t\"encoding/json\"\n\t\"expvar\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/valyala/fasthttp\""
},
{
"path": "fasthttpadaptor/adaptor.go",
"chars": 8514,
"preview": "// Package fasthttpadaptor provides helper functions for converting net/http\n// request handlers to fasthttp request han"
},
{
"path": "fasthttpadaptor/adaptor_test.go",
"chars": 18098,
"preview": "package fasthttpadaptor\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"re"
},
{
"path": "fasthttpadaptor/b2s.go",
"chars": 273,
"preview": "package fasthttpadaptor\n\nimport \"unsafe\"\n\n// b2s converts byte slice to a string without memory allocation.\n// See https"
},
{
"path": "fasthttpadaptor/request.go",
"chars": 1546,
"preview": "package fasthttpadaptor\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\n//"
},
{
"path": "fasthttpadaptor/request_test.go",
"chars": 568,
"preview": "package fasthttpadaptor\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc BenchmarkConvertRequest"
},
{
"path": "fasthttpproxy/dialer.go",
"chars": 7844,
"preview": "package fasthttpproxy\n\nimport (\n\t\"bufio\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time"
},
{
"path": "fasthttpproxy/dialer_test.go",
"chars": 8005,
"preview": "package fasthttpproxy\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/valyala/fasthtt"
},
{
"path": "fasthttpproxy/doc.go",
"chars": 100,
"preview": "// Package fasthttpproxy provides SOCKS5 and HTTP proxy support for fasthttp.\npackage fasthttpproxy\n"
},
{
"path": "fasthttpproxy/http.go",
"chars": 2224,
"preview": "package fasthttpproxy\n\nimport (\n\t\"time\"\n\n\t\"github.com/valyala/fasthttp\"\n\t\"golang.org/x/net/http/httpproxy\"\n)\n\n// Fasthtt"
},
{
"path": "fasthttpproxy/proxy_env.go",
"chars": 1061,
"preview": "package fasthttpproxy\n\nimport (\n\t\"time\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nconst (\n\thttpsScheme = \"https\"\n\thttpScheme ="
},
{
"path": "fasthttpproxy/socks5.go",
"chars": 1042,
"preview": "package fasthttpproxy\n\nimport (\n\t\"github.com/valyala/fasthttp\"\n\t\"golang.org/x/net/http/httpproxy\"\n)\n\n// FasthttpSocksDia"
},
{
"path": "fasthttputil/doc.go",
"chars": 86,
"preview": "// Package fasthttputil provides utility functions for fasthttp.\npackage fasthttputil\n"
},
{
"path": "fasthttputil/inmemory_listener.go",
"chars": 3217,
"preview": "package fasthttputil\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n)\n\n// ErrInmemoryListenerClosed indicates that the InmemoryListe"
},
{
"path": "fasthttputil/inmemory_listener_test.go",
"chars": 5907,
"preview": "package fasthttputil\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc Te"
},
{
"path": "fasthttputil/inmemory_listener_timing_test.go",
"chars": 5594,
"preview": "package fasthttputil_test\n\nimport (\n\t\"crypto/tls\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/valyala/fasthttp\"\n\t\"github.com/valyala"
},
{
"path": "fasthttputil/pipeconns.go",
"chars": 6993,
"preview": "package fasthttputil\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n)\n\n// NewPipeConns returns new bi-directional conn"
},
{
"path": "fasthttputil/pipeconns_test.go",
"chars": 8502,
"preview": "package fasthttputil\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestPipeConnsWriteTimeout(t *test"
},
{
"path": "fasthttputil/s2b.go",
"chars": 186,
"preview": "package fasthttputil\n\nimport \"unsafe\"\n\n// s2b converts string to a byte slice without memory allocation.\nfunc s2b(s stri"
},
{
"path": "fs.go",
"chars": 50299,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"html\"\n\t\"io\"\n\t\"io/fs\"\n\t\"maps\"\n\t\"mime\"\n\t\"net/http\"\n\t\"os\"\n\t\"path\"\n\t\""
},
{
"path": "fs_example_test.go",
"chars": 577,
"preview": "package fasthttp_test\n\nimport (\n\t\"log\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc ExampleFS() {\n\tfs := &fasthttp.FS{\n\t\t// P"
},
{
"path": "fs_fs_test.go",
"chars": 26881,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"embed\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t"
},
{
"path": "fs_handler_example_test.go",
"chars": 1171,
"preview": "package fasthttp_test\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\n// Setup file handlers (aka 'file ser"
},
{
"path": "fs_test.go",
"chars": 29870,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strin"
},
{
"path": "fuzz_test.go",
"chars": 6961,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net/textproto\"\n\t\"net/url\"\n\t\""
},
{
"path": "go.mod",
"chars": 326,
"preview": "module github.com/valyala/fasthttp\n\ngo 1.24.0\n\ntoolchain go1.24.1\n\nrequire (\n\tgithub.com/andybalholm/brotli v1.2.0\n\tgith"
},
{
"path": "go.sum",
"chars": 1342,
"preview": "github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=\ngithub.com/andybalholm/brotli v1.2."
},
{
"path": "header.go",
"chars": 98557,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"iter\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nconst (\n\tr"
},
{
"path": "header_regression_test.go",
"chars": 2461,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestIssue28ResponseWithoutBodyNoConten"
},
{
"path": "header_test.go",
"chars": 105206,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"reflect\"\n\t\"strconv\""
},
{
"path": "header_timing_test.go",
"chars": 6893,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/valyala/bytebufferpoo"
},
{
"path": "headers.go",
"chars": 6898,
"preview": "package fasthttp\n\nconst (\n\tHeaderAccept = \"Accept\"\n\tHeaderAcceptCH = \"Ac"
},
{
"path": "headerscanner.go",
"chars": 3175,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n)\n\ntype headerScanner struct {\n\tinitialized bool\n\n\tb []byte\n\tr int\n"
},
{
"path": "http.go",
"chars": 76181,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart"
},
{
"path": "http_test.go",
"chars": 89795,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t"
},
{
"path": "http_timing_test.go",
"chars": 4627,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc BenchmarkCopyZeroAllocOSFileToBytes"
},
{
"path": "ipv6.go",
"chars": 3623,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n)\n\nvar (\n\terrInvalidIPv6Host = errors.New(\"invalid IPv6 host\")\n\terrInva"
},
{
"path": "ipv6_test.go",
"chars": 2255,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"net\"\n\t\"testing\"\n)\n\n// oracleValid replicates the original function's semantics usi"
},
{
"path": "lbclient.go",
"chars": 5024,
"preview": "package fasthttp\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// BalancingClient is the interface for clients, which may "
},
{
"path": "lbclient_example_test.go",
"chars": 908,
"preview": "package fasthttp_test\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc ExampleLBClient() {\n\t// Requests w"
},
{
"path": "methods.go",
"chars": 478,
"preview": "package fasthttp\n\n// HTTP methods were copied from net/http.\nconst (\n\tMethodGet = \"GET\" // RFC 7231, 4.3.1\n\tMeth"
},
{
"path": "nocopy.go",
"chars": 378,
"preview": "package fasthttp\n\n// Embed this type into a struct, which mustn't be copied,\n// so `go vet` gives a warning if this stru"
},
{
"path": "peripconn.go",
"chars": 2449,
"preview": "package fasthttp\n\nimport (\n\t\"crypto/tls\"\n\t\"encoding/binary\"\n\t\"net\"\n\t\"sync\"\n)\n\ntype perIPConnCounter struct {\n\tperIPConnP"
},
{
"path": "peripconn_test.go",
"chars": 881,
"preview": "package fasthttp\n\nimport (\n\t\"testing\"\n)\n\nvar _ connTLSer = &perIPTLSConn{}\n\nfunc TestIPxUint32(t *testing.T) {\n\tt.Parall"
},
{
"path": "pprofhandler/pprof.go",
"chars": 1456,
"preview": "// Package pprofhandler provides a fasthttp handler similar to net/http/pprof.\npackage pprofhandler\n\nimport (\n\t\"bytes\"\n\t"
},
{
"path": "prefork/README.md",
"chars": 2146,
"preview": "# Prefork\n\nServer prefork implementation.\n\nPreforks master process between several child processes increases performance"
},
{
"path": "prefork/prefork.go",
"chars": 6446,
"preview": "// Package prefork provides a way to prefork a fasthttp server.\npackage prefork\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n"
},
{
"path": "prefork/prefork_test.go",
"chars": 4243,
"preview": "package prefork\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/valyala/fastht"
},
{
"path": "requestctx_setbodystreamwriter_example_test.go",
"chars": 736,
"preview": "package fasthttp_test\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc ExampleRequestCtx"
},
{
"path": "reuseport/LICENSE",
"chars": 1077,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Max Riveiro\n\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "reuseport/reuseport.go",
"chars": 1286,
"preview": "//go:build !windows && !aix && !solaris\n\n// Package reuseport provides TCP net.Listener with SO_REUSEPORT support.\n//\n//"
},
{
"path": "reuseport/reuseport_aix.go",
"chars": 633,
"preview": "package reuseport\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"syscall\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nvar listenConfig = net.ListenConfi"
},
{
"path": "reuseport/reuseport_error.go",
"chars": 302,
"preview": "package reuseport\n\nimport (\n\t\"fmt\"\n)\n\n// ErrNoReusePort is returned if the OS doesn't support SO_REUSEPORT.\ntype ErrNoRe"
},
{
"path": "reuseport/reuseport_example_test.go",
"chars": 476,
"preview": "package reuseport_test\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/valyala/fasthttp\"\n\t\"github.com/valyala/fasthttp/reuseport\"\n"
},
{
"path": "reuseport/reuseport_solaris.go",
"chars": 684,
"preview": "//go:build solaris\n\npackage reuseport\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"syscall\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nconst (\n\t_SO_R"
},
{
"path": "reuseport/reuseport_test.go",
"chars": 853,
"preview": "package reuseport\n\nimport (\n\t\"net\"\n\t\"testing\"\n)\n\nfunc TestTCP4(t *testing.T) {\n\tt.Parallel()\n\n\ttestNewListener(t, \"tcp4\""
},
{
"path": "reuseport/reuseport_windows.go",
"chars": 646,
"preview": "package reuseport\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"syscall\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\nvar listenConfig = net.ListenCo"
},
{
"path": "round2_32.go",
"chars": 515,
"preview": "//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x\n\npackage fasthttp\n\nimport \"math\"\n\nfunc roundUpFo"
},
{
"path": "round2_32_test.go",
"chars": 788,
"preview": "//go:build !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x\n\npackage fasthttp\n\nimport (\n\t\"math\"\n\t\"testing\"\n)"
},
{
"path": "round2_64.go",
"chars": 392,
"preview": "//go:build amd64 || arm64 || ppc64 || ppc64le || riscv64 || s390x\n\npackage fasthttp\n\nfunc roundUpForSliceCap(n int) int "
},
{
"path": "round2_64_test.go",
"chars": 838,
"preview": "//go:build amd64 || arm64 || ppc64 || ppc64le || riscv64 || s390x\n\npackage fasthttp\n\nimport (\n\t\"math\"\n\t\"testing\"\n)\n\nfunc"
},
{
"path": "s2b.go",
"chars": 182,
"preview": "package fasthttp\n\nimport \"unsafe\"\n\n// s2b converts string to a byte slice without memory allocation.\nfunc s2b(s string) "
},
{
"path": "server.go",
"chars": 89418,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"mime/multipart\"\n\t\"net\"\n\t\"os"
},
{
"path": "server_example_test.go",
"chars": 5540,
"preview": "package fasthttp_test\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/valyala/fasthttp\"\n)\n\nfunc Exampl"
},
{
"path": "server_race_test.go",
"chars": 888,
"preview": "//go:build race\n\npackage fasthttp\n\nimport (\n\t\"context\"\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/valyala/fasthttp/fasthttputil\"\n)"
},
{
"path": "server_test.go",
"chars": 112073,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net\"\n\t\""
},
{
"path": "server_timing_test.go",
"chars": 11453,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\""
},
{
"path": "stackless/doc.go",
"chars": 143,
"preview": "// Package stackless provides functionality that may save stack space\n// for high number of concurrently running gorouti"
},
{
"path": "stackless/func.go",
"chars": 1577,
"preview": "package stackless\n\nimport (\n\t\"runtime\"\n\t\"sync\"\n)\n\n// NewFunc returns stackless wrapper for the function f.\n//\n// Unlike "
},
{
"path": "stackless/func_test.go",
"chars": 1606,
"preview": "package stackless\n\nimport (\n\t\"errors\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestNewFuncSimple(t *testing.T) {\n\tt.Par"
},
{
"path": "stackless/func_timing_test.go",
"chars": 715,
"preview": "package stackless\n\nimport (\n\t\"sync/atomic\"\n\t\"testing\"\n)\n\nfunc BenchmarkFuncOverhead(b *testing.B) {\n\tvar n atomic.Uint64"
},
{
"path": "stackless/s2b.go",
"chars": 183,
"preview": "package stackless\n\nimport \"unsafe\"\n\n// s2b converts string to a byte slice without memory allocation.\nfunc s2b(s string)"
},
{
"path": "stackless/writer.go",
"chars": 2723,
"preview": "package stackless\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/valyala/bytebufferpool\"\n)\n\n// Writer is an inte"
},
{
"path": "stackless/writer_test.go",
"chars": 2757,
"preview": "package stackless\n\nimport (\n\t\"bytes\"\n\t\"compress/flate\"\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestComp"
},
{
"path": "status.go",
"chars": 7797,
"preview": "package fasthttp\n\nimport (\n\t\"strconv\"\n)\n\nconst (\n\tstatusMessageMin = 100\n\tstatusMessageMax = 511\n)\n\n// HTTP status codes"
},
{
"path": "status_test.go",
"chars": 796,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestStatusLine(t *testing.T) {\n\tt.Parallel()\n\n\ttestStatusLine(t, "
},
{
"path": "status_timing_test.go",
"chars": 760,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc BenchmarkStatusLine99(b *testing.B) {\n\tbenchmarkStatusLine(b, 99,"
},
{
"path": "stream.go",
"chars": 1171,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/valyala/fasthttp/fasthttputil\"\n)\n\n// StreamWriter must w"
},
{
"path": "stream_test.go",
"chars": 2197,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestNewStreamReader(t *testing.T) "
},
{
"path": "stream_timing_test.go",
"chars": 1367,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc BenchmarkStreamReader1(b *testing.B) {\n\tbenchmarkSt"
},
{
"path": "streaming.go",
"chars": 2250,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/valyala/bytebufferpool\"\n)\n\ntype headerInterface"
},
{
"path": "streaming_test.go",
"chars": 5857,
"preview": "package fasthttp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/valyala/fa"
},
{
"path": "strings.go",
"chars": 4192,
"preview": "package fasthttp\n\nvar (\n\tdefaultServerName = \"fasthttp\"\n\tdefaultUserAgent = \"fasthttp\"\n\tdefaultContentType = []byte(\""
},
{
"path": "tcpdialer.go",
"chars": 15719,
"preview": "package fasthttp\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// Dial dials"
},
{
"path": "tcplisten/README.md",
"chars": 558,
"preview": "# TCPListen\n\nPackage tcplisten provides customizable TCP net.Listener with various\nperformance-related options:\n\n * SO_R"
},
{
"path": "tcplisten/socket.go",
"chars": 653,
"preview": "//go:build !js && !wasm && (linux || darwin || dragonfly || freebsd || netbsd || openbsd || rumprun || (zos && s390x))\n\n"
},
{
"path": "tcplisten/socket_darwin.go",
"chars": 81,
"preview": "//go:build darwin\n\npackage tcplisten\n\nvar newSocketCloexec = newSocketCloexecOld\n"
},
{
"path": "tcplisten/socket_other.go",
"chars": 523,
"preview": "//go:build !js && !wasm && (linux || dragonfly || freebsd || netbsd || openbsd || rumprun)\n\npackage tcplisten\n\nimport (\n"
},
{
"path": "tcplisten/socket_zos_s390x.go",
"chars": 445,
"preview": "//go:build zos && s390x\n\npackage tcplisten\n\nimport (\n\t\"fmt\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc newSocketCloexec(domain, t"
},
{
"path": "tcplisten/tcplisten.go",
"chars": 5340,
"preview": "//go:build linux || darwin || dragonfly || freebsd || netbsd || openbsd || rumprun || (zos && s390x)\n\n// Package tcplist"
},
{
"path": "tcplisten/tcplisten_js_wasm.go",
"chars": 284,
"preview": "package tcplisten\n\nimport (\n\t\"net\"\n)\n\n// A dummy implementation for js,wasm\ntype Config struct {\n\tReusePort bool\n\tDefe"
},
{
"path": "tcplisten/tcplisten_linux.go",
"chars": 2390,
"preview": "//go:build linux\n\npackage tcplisten\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nconst (\n\ts"
},
{
"path": "tcplisten/tcplisten_other.go",
"chars": 488,
"preview": "//go:build darwin || dragonfly || freebsd || netbsd || openbsd || rumprun || (zos && s390x)\n\npackage tcplisten\n\nimport \""
},
{
"path": "tcplisten/tcplisten_test.go",
"chars": 3299,
"preview": "//go:build linux || darwin || dragonfly || freebsd || netbsd || openbsd || rumprun\n\npackage tcplisten\n\nimport (\n\t\"fmt\"\n\t"
},
{
"path": "timer.go",
"chars": 1250,
"preview": "package fasthttp\n\nimport (\n\t\"sync\"\n\t\"time\"\n)\n\nfunc initTimer(t *time.Timer, timeout time.Duration) *time.Timer {\n\tif t ="
},
{
"path": "tls.go",
"chars": 1447,
"preview": "package fasthttp\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"math/big\"\n\t"
},
{
"path": "uri.go",
"chars": 24288,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"sync\"\n)\n\n// AcquireURI returns "
},
{
"path": "uri_test.go",
"chars": 18910,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestURICopyToQueryArgs(t *te"
},
{
"path": "uri_timing_test.go",
"chars": 1206,
"preview": "package fasthttp\n\nimport (\n\t\"testing\"\n)\n\nfunc BenchmarkURIParsePath(b *testing.B) {\n\tbenchmarkURIParse(b, \"google.com\", "
},
{
"path": "uri_unix.go",
"chars": 203,
"preview": "//go:build !windows\n\npackage fasthttp\n\nfunc addLeadingSlash(dst, src []byte) []byte {\n\t// add leading slash for unix pat"
},
{
"path": "uri_windows.go",
"chars": 235,
"preview": "package fasthttp\n\nfunc addLeadingSlash(dst, src []byte) []byte {\n\t// zero length 、\"C:/\" and \"a\" case\n\tisDisk := len(src)"
},
{
"path": "uri_windows_test.go",
"chars": 451,
"preview": "package fasthttp\n\nimport \"testing\"\n\nfunc TestURIPathNormalizeIssue86(t *testing.T) {\n\tt.Parallel()\n\n\t// see https://gith"
},
{
"path": "userdata.go",
"chars": 1534,
"preview": "package fasthttp\n\nimport (\n\t\"io\"\n)\n\ntype userDataKV struct {\n\tkey any\n\tvalue any\n}\n\ntype userData []userDataKV\n\nfunc ("
},
{
"path": "userdata_test.go",
"chars": 2771,
"preview": "package fasthttp\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestUserData(t *testing.T) {\n\tt.Paral"
},
{
"path": "userdata_timing_test.go",
"chars": 918,
"preview": "package fasthttp\n\nimport (\n\t\"testing\"\n)\n\nfunc BenchmarkUserDataCustom(b *testing.B) {\n\tkeys := []string{\"foobar\", \"baz\","
},
{
"path": "workerpool.go",
"chars": 5102,
"preview": "package fasthttp\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n// workerPool serves incoming conne"
},
{
"path": "workerpool_test.go",
"chars": 3507,
"preview": "package fasthttp\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/valyala/fasthttp/fasthttputil\"\n)\n\nfunc TestWork"
},
{
"path": "zstd.go",
"chars": 4158,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/valyala/byt"
},
{
"path": "zstd_test.go",
"chars": 2376,
"preview": "package fasthttp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n)\n\nfunc TestZstdBytesSerial(t *testing.T) {\n\tt.Parallel()\n\n\t"
}
]
About this extraction
This page contains the full source code of the valyala/fasthttp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 157 files (1.3 MB), approximately 390.4k tokens, and a symbol index with 2602 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.