Browse Source

SVI Поднятие версии go до 1.24.2; 100.0%

SVI 1 năm trước cách đây
mục cha
commit
cb700c8ed8

+ 12 - 3
Makefile

@@ -6,7 +6,7 @@ demo:
 mod:
 	clear
 	go get -u ./...
-	go mod tidy -compat=1.22.0
+	go mod tidy -compat=1.24.2
 	go mod vendor
 	go fmt ./...
 
@@ -17,9 +17,18 @@ test:
 	go test -race -shuffle=on -timeout=30s -coverprofile=./cover.out ./...
 	go tool cover -func=./cover.out
 
+.PHONY: lint
 lint:
 	clear
-	go fmt ./...
-	golangci-lint run ./...
+	go fmt  ./...
+	go vet  ./...
+	# go install honnef.co/go/tools/cmd/staticcheck@latest
+	# staticcheck ./...
+	# go install github.com/MakeNowJust/enumcase/cmd/enumcase@latest
+	# enumcase ./...
+	# go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+	# golangci-lint run ./...
+	go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
 	gocyclo -over 11 .
+	go install github.com/securego/gosec/cmd/gosec@latest
 	gosec ./...

+ 1 - 41
README.md

@@ -30,47 +30,7 @@ tree -I vendor -I bin_dev -d
 ```
 
 ```bash
-.
-├── kc                # Вспомогательные компоненты
-│   ├── helpers       # Жёсткий и мягкий assert
-│   ├── local_ctx     # Локальный контекст
-│   │   └── ctx_value # Переменная контекста с метаинформацией
-│   ├── log_buf       # Буферизованный лог
-│   │   └── log_msg   # Сообщение буферизованного лога
-│   └── safe_bool     # Потокобезопасная булева переменная
-├── krn                          # Компоненты ядра
-│   ├── kalias                   # Алиасы типов ядра
-│   ├── kbus                     # Шина данных ядра
-│   │   ├── dict_sub_hook        # Словарь обработчиков подписок
-│   │   ├── dict_topic_serve     # Список топиков для обработчиков входящих запросов
-│   │   ├── dict_topic_sub       # Список топиков подписки
-│   │   ├── kbus_base            # БазоваЯ шина данных
-│   │   ├── kbus_http            # Шина данных поверх HTTP
-│   │   │   └── client_bus_http  # Клиент для шины данных поверх HTTP
-│   │   ├── kbus_local           # Локальная шина данных
-│   │   │   └── client_bus_local # Клиент для локальной шины данных
-│   │   └── kbus_msg          # Сообщения для всех сетевых шин
-│   │       ├── msg_pub       # Сообщения для публикации
-│   │       ├── msg_serve     # Сообщения для запросов
-│   │       ├── msg_sub       # Сообщения для подписки
-│   │       └── msg_unsub     # Сообщения для отписки
-│   ├── kctx              # Контекст ядра
-│   │   ├── kernel_keeper # Сторож сигналов ОС
-│   │   └── kwg           # Именованный ожидатель групп
-│   ├── kmodule   # Компонент модуль ядра
-│   ├── kmonolit  # Компонент модульного монолита ядра
-│   ├── kserv_http      # Компонент встроенного быстрого HTTP-сервера (fiber)
-│   │   └── static      # Встраиваемые статические файлы
-│   │       ├── css     # Встраиваемые стили (bootstrap)
-│   │       └── js      # Встраиваемые скрипты (htmx, hyperscript, bootstrap)
-│   ├── kstore_kv   # Встраиваемое быстрое key:value хранилище (Badger)
-│   └── ktypes  # Интерфейсы ядра
-├── mds   # Типовые модули ядра
-└── mock        # Мок-объекты для тестирования и экспериментов
-    ├── mock_env            # Мок-окружение для запуска компонентов ядра
-    ├── mock_hand_serve     # Мок-обработчик входящих запросов
-    ├── mock_hand_sub_http  # Мок-обработчик подписки через HTTP-шину
-    └── mock_hand_sub_local # Мок-обработчик подписки через локальную шину
+TODO: update
 ```
 
 ## Версия компилятора

+ 2 - 4
go.mod

@@ -1,8 +1,6 @@
 module gitp78su.ipnodns.ru/svi/kern
 
-go 1.23.0
-
-toolchain go1.24.1
+go 1.24.2
 
 require (
 	github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b
@@ -26,7 +24,7 @@ require (
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/rivo/uniseg v0.4.7 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
-	github.com/valyala/fasthttp v1.59.0 // indirect
+	github.com/valyala/fasthttp v1.60.0 // indirect
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/otel v1.35.0 // indirect
 	go.opentelemetry.io/otel/metric v1.35.0 // indirect

+ 2 - 2
go.sum

@@ -50,8 +50,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.59.0 h1:Qu0qYHfXvPk1mSLNqcFtEk6DpxgA26hy6bmydotDpRI=
-github.com/valyala/fasthttp v1.59.0/go.mod h1:GTxNb9Bc6r2a9D0TWNSPwDz78UxnTGBViY3xZNEqyYU=
+github.com/valyala/fasthttp v1.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw=
+github.com/valyala/fasthttp v1.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuHgTO4FXCvc=
 github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
 github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

+ 60 - 69
vendor/github.com/valyala/fasthttp/.golangci.yml

@@ -1,15 +1,9 @@
-# This file contains configuration options for golangci-lint.
-# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
-
-run:
-  # Timeout for analysis.
-  timeout: 5m
-
+version: "2"
 linters:
-  enable-all: true
+  default: all
   disable:
-    - cyclop
     - copyloopvar
+    - cyclop
     - depguard
     - dupl
     - err113
@@ -17,15 +11,16 @@ linters:
     - errorlint
     - exhaustive
     - exhaustruct
+    - forbidigo
     - forcetypeassert
     - funlen
     - gochecknoglobals
     - gocognit
     - goconst
     - gocyclo
-    - goerr113
-    - gomnd
+    - godox
     - gosec
+    - gosmopolitan
     - inamedparam
     - intrange
     - ireturn
@@ -46,65 +41,61 @@ linters:
     - varnamelen
     - wrapcheck
     - wsl
-
-    # Deprecated linters
-    - deadcode
-    - exhaustivestruct
-    - exportloopref
-    - execinquery
-    - golint
-    - ifshort
-    - interfacer
-    - maligned
-    - nosnakecase
-    - scopelint
-    - structcheck
-    - varcheck
-
-linters-settings:
-  revive:
-    # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
+  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:
-      - name: indent-error-flow
-      - name: use-any
-  lll:
-    line-length: 130
-  stylecheck:
-    checks: [
-      "all",
-      "-ST1000", # at least one file in a package should have a package comment
-    ]
-  gocritic:
-    enabled-tags:
-      - diagnostic
-      - experimental
-      - opinionated
-      - performance
-      - style
-    disabled-checks:
-      - deferInLoop
-      - importShadow
-      - sloppyReassign
-      - unnamedResult
-      - whyNoLint
-  govet:
-    enable-all: true
-    disable:
-      - fieldalignment
-      - shadow
-
+      - linters:
+          - lll
+        path: _test\.go
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
 issues:
-  # Show all issues from a linter.
   max-issues-per-linter: 0
-
-  # Show all issues with the same text.
   max-same-issues: 0
-
-  include:
-    - EXC0011 # include issues about comments from `stylecheck`
-
-  exclude-rules:
-    # Exclude some linters from running on tests files.
-    - path: _test\.go
-      linters:
-        - lll
+formatters:
+  enable:
+    - gci
+    - gofmt
+    - gofumpt
+    - goimports
+  exclusions:
+    generated: lax
+    paths:
+      - third_party$
+      - builtin$
+      - examples$

+ 8 - 5
vendor/github.com/valyala/fasthttp/README.md

@@ -536,7 +536,7 @@ This is an **unsafe** way, the result string and `[]byte` buffer share the same
     performance fasthttp request router that scales well.
   * [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
+  * [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
@@ -547,9 +547,10 @@ This is an **unsafe** way, the result string and `[]byte` buffer share the same
   * [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
+  * [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
 
@@ -602,7 +603,9 @@ This is an **unsafe** way, the result string and `[]byte` buffer share the same
 
 * *Which GO versions are supported by fasthttp?*
 
-  Go 1.21.x and newer. Older versions might work, but won't officially be supported.
+  We support the same versions the Go team supports.
+  Currently that is Go 1.23.x and newer.
+  Older versions might work, but won't officially be supported.
 
 * *Please provide real benchmark data and server information*
 

+ 15 - 7
vendor/github.com/valyala/fasthttp/args.go

@@ -155,12 +155,12 @@ func (a *Args) WriteTo(w io.Writer) (int64, error) {
 
 // Del deletes argument with the given key from query args.
 func (a *Args) Del(key string) {
-	a.args = delAllArgs(a.args, key)
+	a.args = delAllArgsStable(a.args, key)
 }
 
 // DelBytes deletes argument with the given key from query args.
 func (a *Args) DelBytes(key []byte) {
-	a.args = delAllArgs(a.args, b2s(key))
+	a.args = delAllArgsStable(a.args, b2s(key))
 }
 
 // Add adds 'key=value' argument.
@@ -385,11 +385,7 @@ func copyArgs(dst, src []argsKV) []argsKV {
 	return dst
 }
 
-func delAllArgsBytes(args []argsKV, key []byte) []argsKV {
-	return delAllArgs(args, b2s(key))
-}
-
-func delAllArgs(args []argsKV, key string) []argsKV {
+func delAllArgsStable(args []argsKV, key string) []argsKV {
 	for i, n := 0, len(args); i < n; i++ {
 		kv := &args[i]
 		if key == string(kv.key) {
@@ -404,6 +400,18 @@ func delAllArgs(args []argsKV, key string) []argsKV {
 	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)
 }

+ 109 - 171
vendor/github.com/valyala/fasthttp/header.go

@@ -193,7 +193,7 @@ func (h *ResponseHeader) SetConnectionClose() {
 func (h *ResponseHeader) ResetConnectionClose() {
 	if h.connectionClose {
 		h.connectionClose = false
-		h.h = delAllArgsBytes(h.h, strConnection)
+		h.h = delAllArgs(h.h, HeaderConnection)
 	}
 }
 
@@ -211,7 +211,7 @@ func (h *RequestHeader) SetConnectionClose() {
 func (h *RequestHeader) ResetConnectionClose() {
 	if h.connectionClose {
 		h.connectionClose = false
-		h.h = delAllArgsBytes(h.h, strConnection)
+		h.h = delAllArgs(h.h, HeaderConnection)
 	}
 }
 
@@ -251,7 +251,7 @@ func (h *ResponseHeader) SetContentLength(contentLength int) {
 	h.contentLength = contentLength
 	if contentLength >= 0 {
 		h.contentLengthBytes = AppendUint(h.contentLengthBytes[:0], contentLength)
-		h.h = delAllArgsBytes(h.h, strTransferEncoding)
+		h.h = delAllArgs(h.h, HeaderTransferEncoding)
 		return
 	} else if contentLength == -1 {
 		h.contentLengthBytes = h.contentLengthBytes[:0]
@@ -296,7 +296,7 @@ func (h *RequestHeader) SetContentLength(contentLength int) {
 	h.contentLength = contentLength
 	if contentLength >= 0 {
 		h.contentLengthBytes = AppendUint(h.contentLengthBytes[:0], contentLength)
-		h.h = delAllArgsBytes(h.h, strTransferEncoding)
+		h.h = delAllArgs(h.h, HeaderTransferEncoding)
 	} else {
 		h.contentLengthBytes = h.contentLengthBytes[:0]
 		h.h = setArgBytes(h.h, strTransferEncoding, strChunked, argsHasValue)
@@ -520,38 +520,8 @@ var ErrBadTrailer = errors.New("contain forbidden trailer")
 // 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
 //
 // Return ErrBadTrailer if contain any forbidden trailers.
-func (h *ResponseHeader) AddTrailerBytes(trailer []byte) error {
-	var err error
-	for i := -1; i+1 < len(trailer); {
-		trailer = trailer[i+1:]
-		i = bytes.IndexByte(trailer, ',')
-		if i < 0 {
-			i = len(trailer)
-		}
-		key := trailer[:i]
-		for len(key) > 0 && key[0] == ' ' {
-			key = key[1:]
-		}
-		for len(key) > 0 && key[len(key)-1] == ' ' {
-			key = key[:len(key)-1]
-		}
-		// Forbidden by RFC 7230, section 4.1.2
-		if isBadTrailer(key) {
-			err = ErrBadTrailer
-			continue
-		}
-		h.bufK = append(h.bufK[:0], key...)
-		normalizeHeaderKey(h.bufK, h.disableNormalizing)
-		if cap(h.trailer) > len(h.trailer) {
-			h.trailer = h.trailer[:len(h.trailer)+1]
-			h.trailer[len(h.trailer)-1] = append(h.trailer[len(h.trailer)-1][:0], h.bufK...)
-		} else {
-			key = make([]byte, len(h.bufK))
-			copy(key, h.bufK)
-			h.trailer = append(h.trailer, key)
-		}
-	}
-
+func (h *ResponseHeader) AddTrailerBytes(trailer []byte) (err error) {
+	h.bufK, h.trailer, err = addTrailerBytes(trailer, h.bufK, h.trailer, h.disableNormalizing)
 	return err
 }
 
@@ -875,38 +845,8 @@ func (h *RequestHeader) AddTrailer(trailer string) error {
 // 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
 //
 // Return ErrBadTrailer if contain any forbidden trailers.
-func (h *RequestHeader) AddTrailerBytes(trailer []byte) error {
-	var err error
-	for i := -1; i+1 < len(trailer); {
-		trailer = trailer[i+1:]
-		i = bytes.IndexByte(trailer, ',')
-		if i < 0 {
-			i = len(trailer)
-		}
-		key := trailer[:i]
-		for len(key) > 0 && key[0] == ' ' {
-			key = key[1:]
-		}
-		for len(key) > 0 && key[len(key)-1] == ' ' {
-			key = key[:len(key)-1]
-		}
-		// Forbidden by RFC 7230, section 4.1.2
-		if isBadTrailer(key) {
-			err = ErrBadTrailer
-			continue
-		}
-		h.bufK = append(h.bufK[:0], key...)
-		normalizeHeaderKey(h.bufK, h.disableNormalizing)
-		if cap(h.trailer) > len(h.trailer) {
-			h.trailer = h.trailer[:len(h.trailer)+1]
-			h.trailer[len(h.trailer)-1] = append(h.trailer[len(h.trailer)-1][:0], h.bufK...)
-		} else {
-			key = make([]byte, len(h.bufK))
-			copy(key, h.bufK)
-			h.trailer = append(h.trailer, key)
-		}
-	}
-
+func (h *RequestHeader) AddTrailerBytes(trailer []byte) (err error) {
+	h.bufK, h.trailer, err = addTrailerBytes(trailer, h.bufK, h.trailer, h.disableNormalizing)
 	return err
 }
 
@@ -1321,8 +1261,8 @@ func (h *RequestHeader) VisitAll(f func(key, value []byte)) {
 func (h *RequestHeader) VisitAllInOrder(f func(key, value []byte)) {
 	var s headerScanner
 	s.b = h.rawHeaders
-	s.disableNormalizing = h.disableNormalizing
 	for s.next() {
+		normalizeHeaderKey(s.key, h.disableNormalizing || bytes.IndexByte(s.key, ' ') != -1)
 		if len(s.key) > 0 {
 			f(s.key, s.value)
 		}
@@ -1338,7 +1278,7 @@ func (h *ResponseHeader) Del(key string) {
 // DelBytes deletes header with the given key.
 func (h *ResponseHeader) DelBytes(key []byte) {
 	h.bufK = append(h.bufK[:0], key...)
-	normalizeHeaderKey(h.bufK, h.disableNormalizing)
+	normalizeHeaderKey(h.bufK, h.disableNormalizing || bytes.IndexByte(key, ' ') != -1)
 	h.del(h.bufK)
 }
 
@@ -1360,7 +1300,7 @@ func (h *ResponseHeader) del(key []byte) {
 	case HeaderTrailer:
 		h.trailer = h.trailer[:0]
 	}
-	h.h = delAllArgsBytes(h.h, key)
+	h.h = delAllArgs(h.h, b2s(key))
 }
 
 // Del deletes header with the given key.
@@ -1372,7 +1312,7 @@ func (h *RequestHeader) Del(key string) {
 // DelBytes deletes header with the given key.
 func (h *RequestHeader) DelBytes(key []byte) {
 	h.bufK = append(h.bufK[:0], key...)
-	normalizeHeaderKey(h.bufK, h.disableNormalizing)
+	normalizeHeaderKey(h.bufK, h.disableNormalizing || bytes.IndexByte(key, ' ') != -1)
 	h.del(h.bufK)
 }
 
@@ -1394,7 +1334,7 @@ func (h *RequestHeader) del(key []byte) {
 	case HeaderTrailer:
 		h.trailer = h.trailer[:0]
 	}
-	h.h = delAllArgsBytes(h.h, key)
+	h.h = delAllArgs(h.h, b2s(key))
 }
 
 // setSpecialHeader handles special headers and return true when a header is processed.
@@ -1638,7 +1578,7 @@ func (h *ResponseHeader) SetBytesV(key string, value []byte) {
 // Use AddBytesKV for setting multiple header values under the same key.
 func (h *ResponseHeader) SetBytesKV(key, value []byte) {
 	h.bufK = append(h.bufK[:0], key...)
-	normalizeHeaderKey(h.bufK, h.disableNormalizing)
+	normalizeHeaderKey(h.bufK, h.disableNormalizing || bytes.IndexByte(key, ' ') != -1)
 	h.SetCanonical(h.bufK, value)
 }
 
@@ -1864,7 +1804,7 @@ func (h *RequestHeader) SetBytesV(key string, value []byte) {
 // Use AddBytesKV for setting multiple header values under the same key.
 func (h *RequestHeader) SetBytesKV(key, value []byte) {
 	h.bufK = append(h.bufK[:0], key...)
-	normalizeHeaderKey(h.bufK, h.disableNormalizing)
+	normalizeHeaderKey(h.bufK, h.disableNormalizing || bytes.IndexByte(key, ' ') != -1)
 	h.SetCanonical(h.bufK, value)
 }
 
@@ -1900,7 +1840,7 @@ func (h *ResponseHeader) Peek(key string) []byte {
 // Do not store references to returned value. Make copies instead.
 func (h *ResponseHeader) PeekBytes(key []byte) []byte {
 	h.bufK = append(h.bufK[:0], key...)
-	normalizeHeaderKey(h.bufK, h.disableNormalizing)
+	normalizeHeaderKey(h.bufK, h.disableNormalizing || bytes.IndexByte(key, ' ') != -1)
 	return h.peek(h.bufK)
 }
 
@@ -1921,7 +1861,7 @@ func (h *RequestHeader) Peek(key string) []byte {
 // Do not store references to returned value. Make copies instead.
 func (h *RequestHeader) PeekBytes(key []byte) []byte {
 	h.bufK = append(h.bufK[:0], key...)
-	normalizeHeaderKey(h.bufK, h.disableNormalizing)
+	normalizeHeaderKey(h.bufK, h.disableNormalizing || bytes.IndexByte(key, ' ') != -1)
 	return h.peek(h.bufK)
 }
 
@@ -2239,7 +2179,8 @@ func (h *ResponseHeader) tryReadTrailer(r *bufio.Reader, n int) error {
 		return fmt.Errorf("error when reading response trailer: %w", err)
 	}
 	b = mustPeekBuffered(r)
-	headersLen, errParse := h.parseTrailer(b)
+	trailers, headersLen, errParse := parseTrailer(b, h.h, h.disableNormalizing)
+	h.h = trailers
 	if errParse != nil {
 		if err == io.EOF {
 			return err
@@ -2348,7 +2289,8 @@ func (h *RequestHeader) tryReadTrailer(r *bufio.Reader, n int) error {
 		return fmt.Errorf("error when reading request trailer: %w", err)
 	}
 	b = mustPeekBuffered(r)
-	headersLen, errParse := h.parseTrailer(b)
+	trailers, headersLen, errParse := parseTrailer(b, h.h, h.disableNormalizing)
+	h.h = trailers
 	if errParse != nil {
 		if err == io.EOF {
 			return err
@@ -2725,43 +2667,6 @@ func (h *ResponseHeader) parse(buf []byte) (int, error) {
 	return m + n, nil
 }
 
-func (h *ResponseHeader) parseTrailer(buf []byte) (int, error) {
-	// Skip any 0 length chunk.
-	if buf[0] == '0' {
-		skip := len(strCRLF) + 1
-		if len(buf) < skip {
-			return 0, io.EOF
-		}
-		buf = buf[skip:]
-	}
-
-	var s headerScanner
-	s.b = buf
-	s.disableNormalizing = h.disableNormalizing
-	var err error
-	for s.next() {
-		if len(s.key) > 0 {
-			if bytes.IndexByte(s.key, ' ') != -1 || bytes.IndexByte(s.key, '\t') != -1 {
-				err = fmt.Errorf("invalid trailer key %q", s.key)
-				continue
-			}
-			// Forbidden by RFC 7230, section 4.1.2
-			if isBadTrailer(s.key) {
-				err = fmt.Errorf("forbidden trailer key %q", s.key)
-				continue
-			}
-			h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
-		}
-	}
-	if s.err != nil {
-		return 0, s.err
-	}
-	if err != nil {
-		return 0, err
-	}
-	return s.hLen, nil
-}
-
 func (h *RequestHeader) ignoreBody() bool {
 	return h.IsGet() || h.IsHead()
 }
@@ -2784,41 +2689,82 @@ func (h *RequestHeader) parse(buf []byte) (int, error) {
 	return m + n, nil
 }
 
-func (h *RequestHeader) parseTrailer(buf []byte) (int, error) {
+func addTrailerBytes(src, buf []byte, trailers [][]byte, disableNormalizing bool) ([]byte, [][]byte, error) {
+	var err error
+	for i := -1; i+1 < len(src); {
+		src = src[i+1:]
+		i = bytes.IndexByte(src, ',')
+		if i < 0 {
+			i = len(src)
+		}
+		key := src[:i]
+		for len(key) > 0 && key[0] == ' ' {
+			key = key[1:]
+		}
+		for len(key) > 0 && key[len(key)-1] == ' ' {
+			key = key[:len(key)-1]
+		}
+		// Forbidden by RFC 7230, section 4.1.2
+		if isBadTrailer(key) {
+			err = ErrBadTrailer
+			continue
+		}
+		buf = append(buf[:0], key...)
+		normalizeHeaderKey(buf, disableNormalizing || bytes.IndexByte(buf, ' ') != -1)
+		if cap(trailers) > len(trailers) {
+			trailers = trailers[:len(trailers)+1]
+			trailers[len(trailers)-1] = append(trailers[len(trailers)-1][:0], buf...)
+		} else {
+			key = make([]byte, len(buf))
+			copy(key, buf)
+			trailers = append(trailers, key)
+		}
+	}
+
+	return buf, trailers, err
+}
+
+func parseTrailer(src []byte, dest []argsKV, disableNormalizing bool) ([]argsKV, int, error) {
 	// Skip any 0 length chunk.
-	if buf[0] == '0' {
+	if src[0] == '0' {
 		skip := len(strCRLF) + 1
-		if len(buf) < skip {
-			return 0, io.EOF
+		if len(src) < skip {
+			return dest, 0, io.EOF
 		}
-		buf = buf[skip:]
+		src = src[skip:]
 	}
 
 	var s headerScanner
-	s.b = buf
-	s.disableNormalizing = h.disableNormalizing
-	var err error
+	s.b = src
+
 	for s.next() {
-		if len(s.key) > 0 {
-			if bytes.IndexByte(s.key, ' ') != -1 || bytes.IndexByte(s.key, '\t') != -1 {
-				err = fmt.Errorf("invalid trailer key %q", s.key)
-				continue
-			}
-			// Forbidden by RFC 7230, section 4.1.2
-			if isBadTrailer(s.key) {
-				err = fmt.Errorf("forbidden trailer key %q", s.key)
-				continue
+		if len(s.key) == 0 {
+			continue
+		}
+		disable := disableNormalizing
+		for _, ch := range s.key {
+			if !validHeaderFieldByte(ch) {
+				// We accept invalid headers with a space before the
+				// colon, but must not canonicalize them.
+				// See: https://github.com/valyala/fasthttp/issues/1917
+				if ch == ' ' {
+					disable = true
+					continue
+				}
+				return dest, 0, fmt.Errorf("invalid trailer key %q", s.key)
 			}
-			h.h = appendArgBytes(h.h, s.key, s.value, argsHasValue)
 		}
+		// Forbidden by RFC 7230, section 4.1.2
+		if isBadTrailer(s.key) {
+			return dest, 0, fmt.Errorf("forbidden trailer key %q", s.key)
+		}
+		normalizeHeaderKey(s.key, disable)
+		dest = appendArgBytes(dest, s.key, s.value, argsHasValue)
 	}
 	if s.err != nil {
-		return 0, s.err
-	}
-	if err != nil {
-		return 0, err
+		return dest, 0, s.err
 	}
-	return s.hLen, nil
+	return dest, s.hLen, nil
 }
 
 func isBadTrailer(key []byte) bool {
@@ -3019,7 +2965,6 @@ func (h *ResponseHeader) parseHeaders(buf []byte) (int, error) {
 
 	var s headerScanner
 	s.b = buf
-	s.disableNormalizing = h.disableNormalizing
 	var kv *argsKV
 
 	for s.next() {
@@ -3028,12 +2973,22 @@ func (h *ResponseHeader) parseHeaders(buf []byte) (int, error) {
 			return 0, fmt.Errorf("invalid header key %q", s.key)
 		}
 
+		disableNormalizing := h.disableNormalizing
 		for _, ch := range s.key {
 			if !validHeaderFieldByte(ch) {
 				h.connectionClose = true
+				// We accept invalid headers with a space before the
+				// colon, but must not canonicalize them.
+				// See: https://github.com/valyala/fasthttp/issues/1917
+				if ch == ' ' {
+					disableNormalizing = true
+					continue
+				}
 				return 0, fmt.Errorf("invalid header key %q", s.key)
 			}
 		}
+		normalizeHeaderKey(s.key, disableNormalizing)
+
 		for _, ch := range s.value {
 			if !validHeaderValueByte(ch) {
 				h.connectionClose = true
@@ -3136,7 +3091,6 @@ func (h *RequestHeader) parseHeaders(buf []byte) (int, error) {
 
 	var s headerScanner
 	s.b = buf
-	s.disableNormalizing = h.disableNormalizing
 
 	for s.next() {
 		if len(s.key) == 0 {
@@ -3144,12 +3098,19 @@ func (h *RequestHeader) parseHeaders(buf []byte) (int, error) {
 			return 0, fmt.Errorf("invalid header key %q", s.key)
 		}
 
+		disableNormalizing := h.disableNormalizing
 		for _, ch := range s.key {
 			if !validHeaderFieldByte(ch) {
+				if ch == ' ' {
+					disableNormalizing = true
+					continue
+				}
 				h.connectionClose = true
 				return 0, fmt.Errorf("invalid header key %q", s.key)
 			}
 		}
+		normalizeHeaderKey(s.key, disableNormalizing)
+
 		for _, ch := range s.value {
 			if !validHeaderValueByte(ch) {
 				h.connectionClose = true
@@ -3304,8 +3265,7 @@ type headerScanner struct {
 	nextColon   int
 	nextNewLine int
 
-	disableNormalizing bool
-	initialized        bool
+	initialized bool
 }
 
 func (s *headerScanner) next() bool {
@@ -3351,7 +3311,6 @@ func (s *headerScanner) next() bool {
 		return false
 	}
 	s.key = s.b[:n]
-	normalizeHeaderKey(s.key, s.disableNormalizing)
 	n++
 	for len(s.b) > n && (s.b[n] == ' ' || s.b[n] == '\t') {
 		n++
@@ -3372,11 +3331,7 @@ func (s *headerScanner) next() bool {
 		s.err = errNeedMore
 		return false
 	}
-	isMultiLineValue := false
-	for {
-		if n+1 >= len(s.b) {
-			break
-		}
+	for n+1 < len(s.b) {
 		if s.b[n+1] != ' ' && s.b[n+1] != '\t' {
 			break
 		}
@@ -3392,14 +3347,12 @@ func (s *headerScanner) next() bool {
 			s.nextNewLine = d - c - 1
 			break
 		}
-		isMultiLineValue = true
 		n = e
 	}
 	if n >= len(s.b) {
 		s.err = errNeedMore
 		return false
 	}
-	oldB := s.b
 	s.value = s.b[:n]
 	s.hLen += n + 1
 	s.b = s.b[n+1:]
@@ -3411,8 +3364,8 @@ func (s *headerScanner) next() bool {
 		n--
 	}
 	s.value = s.value[:n]
-	if isMultiLineValue {
-		s.value, s.b, s.hLen = normalizeHeaderValue(s.value, oldB, s.hLen)
+	if bytes.Contains(s.b, strCRLF) {
+		s.value = normalizeHeaderValue(s.value)
 	}
 
 	return true
@@ -3482,11 +3435,11 @@ func initHeaderKV(bufK, bufV []byte, key, value string, disableNormalizing bool)
 
 func getHeaderKeyBytes(bufK []byte, key string, disableNormalizing bool) []byte {
 	bufK = append(bufK[:0], key...)
-	normalizeHeaderKey(bufK, disableNormalizing)
+	normalizeHeaderKey(bufK, disableNormalizing || bytes.IndexByte(bufK, ' ') != -1)
 	return bufK
 }
 
-func normalizeHeaderValue(ov, ob []byte, headerLength int) (nv, nb []byte, nhl int) {
+func normalizeHeaderValue(ov []byte) (nv []byte) {
 	nv = ov
 	length := len(ov)
 	if length <= 0 {
@@ -3521,23 +3474,8 @@ func normalizeHeaderValue(ov, ob []byte, headerLength int) (nv, nb []byte, nhl i
 		write++
 	}
 
-	nv = nv[:write]
-	copy(ob[write:], ob[write+shrunk:])
-
-	// Check if we need to skip \r\n or just \n
-	skip := 0
-	if ob[write] == rChar {
-		if ob[write+1] == nChar {
-			skip += 2
-		} else {
-			skip++
-		}
-	} else if ob[write] == nChar {
-		skip++
-	}
+	nv = nv[:length-shrunk]
 
-	nb = ob[write+skip : len(ob)-shrunk]
-	nhl = headerLength - shrunk
 	return
 }
 

+ 40 - 36
vendor/github.com/valyala/fasthttp/server.go

@@ -219,7 +219,7 @@ type Server struct {
 
 	concurrencyCh chan struct{}
 
-	idleConns map[net.Conn]time.Time
+	idleConns map[net.Conn]*atomic.Int64
 	done      chan struct{}
 
 	// Server name for sending in response headers.
@@ -1157,7 +1157,7 @@ var (
 	// NetHttpFormValueFunc gives consistent behavior with net/http.
 	// POST and PUT body parameters take precedence over URL query string values.
 	//
-	//nolint:stylecheck // backwards compatibility
+	//nolint:staticcheck // backwards compatibility
 	NetHttpFormValueFunc = func(ctx *RequestCtx, key string) []byte {
 		v := ctx.PostArgs().Peek(key)
 		if len(v) > 0 {
@@ -1704,10 +1704,6 @@ func (s *Server) ServeTLS(ln net.Listener, certFile, keyFile string) error {
 		}
 	}
 
-	// BuildNameToCertificate has been deprecated since 1.14.
-	// But since we also support older versions we'll keep this here.
-	s.TLSConfig.BuildNameToCertificate() //nolint:staticcheck
-
 	s.mu.Unlock()
 
 	return s.Serve(
@@ -1732,10 +1728,6 @@ func (s *Server) ServeTLSEmbed(ln net.Listener, certData, keyData []byte) error
 		}
 	}
 
-	// BuildNameToCertificate has been deprecated since 1.14.
-	// But since we also support older versions we'll keep this here.
-	s.TLSConfig.BuildNameToCertificate() //nolint:staticcheck
-
 	s.mu.Unlock()
 
 	return s.Serve(
@@ -2140,6 +2132,26 @@ func (s *Server) serveConn(c net.Conn) (err error) {
 		return handler(c)
 	}
 
+	s.idleConnsMu.Lock()
+	if s.idleConns == nil {
+		s.idleConns = make(map[net.Conn]*atomic.Int64)
+	}
+	idleConnTime, ok := s.idleConns[c]
+	if !ok {
+		v := idleConnTimePool.Get()
+		if v == nil {
+			v = &atomic.Int64{}
+		}
+		idleConnTime = v.(*atomic.Int64)
+		s.idleConns[c] = idleConnTime
+	}
+
+	// Count the connection as Idle after 5 seconds.
+	// Same as net/http.Server:
+	// https://github.com/golang/go/blob/85d7bab91d9a3ed1f76842e4328973ea75efef54/src/net/http/server.go#L2834-L2836
+	idleConnTime.Store(time.Now().Add(time.Second * 5).Unix())
+	s.idleConnsMu.Unlock()
+
 	serverName := s.getServerName()
 	connRequestNum := uint64(0)
 	connID := nextConnID()
@@ -2215,6 +2227,8 @@ func (s *Server) serveConn(c net.Conn) (err error) {
 		if err == nil {
 			s.setState(c, StateActive)
 
+			idleConnTime.Store(0)
+
 			if s.ReadTimeout > 0 {
 				if err = c.SetReadDeadline(time.Now().Add(s.ReadTimeout)); err != nil {
 					break
@@ -2493,6 +2507,8 @@ func (s *Server) serveConn(c net.Conn) (err error) {
 			err = nil
 			break
 		}
+
+		idleConnTime.Store(time.Now().Unix())
 	}
 
 	if br != nil {
@@ -2505,11 +2521,18 @@ func (s *Server) serveConn(c net.Conn) (err error) {
 		s.releaseCtx(ctx)
 	}
 
+	s.idleConnsMu.Lock()
+	ic, ok := s.idleConns[c]
+	if ok {
+		idleConnTimePool.Put(ic)
+		delete(s.idleConns, c)
+	}
+	s.idleConnsMu.Unlock()
+
 	return
 }
 
 func (s *Server) setState(nc net.Conn, state ConnState) {
-	s.trackConn(nc, state)
 	if hook := s.ConnState; hook != nil {
 		hook(nc, state)
 	}
@@ -2886,36 +2909,17 @@ func (s *Server) writeErrorResponse(bw *bufio.Writer, ctx *RequestCtx, serverNam
 	return bw
 }
 
-func (s *Server) trackConn(c net.Conn, state ConnState) {
-	s.idleConnsMu.Lock()
-	switch state {
-	case StateIdle:
-		if s.idleConns == nil {
-			s.idleConns = make(map[net.Conn]time.Time)
-		}
-		s.idleConns[c] = time.Now()
-	case StateNew:
-		if s.idleConns == nil {
-			s.idleConns = make(map[net.Conn]time.Time)
-		}
-		// Count the connection as Idle after 5 seconds.
-		// Same as net/http.Server:
-		// https://github.com/golang/go/blob/85d7bab91d9a3ed1f76842e4328973ea75efef54/src/net/http/server.go#L2834-L2836
-		s.idleConns[c] = time.Now().Add(time.Second * 5)
-
-	default:
-		delete(s.idleConns, c)
-	}
-	s.idleConnsMu.Unlock()
-}
+var idleConnTimePool sync.Pool
 
 func (s *Server) closeIdleConns() {
 	s.idleConnsMu.Lock()
-	now := time.Now()
-	for c, t := range s.idleConns {
-		if now.Sub(t) >= 0 {
+	now := time.Now().Unix()
+	for c, ict := range s.idleConns {
+		t := ict.Load()
+		if t != 0 && now-t >= 0 {
 			_ = c.Close()
 			delete(s.idleConns, c)
+			idleConnTimePool.Put(ict)
 		}
 	}
 	s.idleConnsMu.Unlock()

+ 3 - 2
vendor/github.com/valyala/fasthttp/tcplisten/tcplisten.go

@@ -184,8 +184,9 @@ func safeIntToUint32(i int) (uint32, error) {
 	if i < 0 {
 		return 0, errors.New("value is negative, cannot convert to uint32")
 	}
-	if i > math.MaxUint32 {
+	ui := uint64(i)
+	if ui > math.MaxUint32 {
 		return 0, errors.New("value exceeds uint32 max value")
 	}
-	return uint32(i), nil
+	return uint32(ui), nil
 }

+ 3 - 2
vendor/github.com/valyala/fasthttp/workerpool.go

@@ -224,12 +224,13 @@ func (wp *workerPool) workerFunc(ch *workerChan) {
 
 		if err = wp.WorkerFunc(c); err != nil && err != errHijacked {
 			errStr := err.Error()
-			if wp.LogAllErrors || !(strings.Contains(errStr, "broken pipe") ||
+			shouldIgnore := strings.Contains(errStr, "broken pipe") ||
 				strings.Contains(errStr, "reset by peer") ||
 				strings.Contains(errStr, "request headers: small read buffer") ||
 				strings.Contains(errStr, "unexpected EOF") ||
 				strings.Contains(errStr, "i/o timeout") ||
-				errors.Is(err, ErrBadTrailer)) {
+				errors.Is(err, ErrBadTrailer)
+			if wp.LogAllErrors || !shouldIgnore {
 				wp.Logger.Printf("error when serving connection %q<->%q: %v", c.LocalAddr(), c.RemoteAddr(), err)
 			}
 		}

+ 2 - 2
vendor/modules.txt

@@ -92,8 +92,8 @@ github.com/rivo/uniseg
 # github.com/valyala/bytebufferpool v1.0.0
 ## explicit
 github.com/valyala/bytebufferpool
-# github.com/valyala/fasthttp v1.59.0
-## explicit; go 1.21
+# github.com/valyala/fasthttp v1.60.0
+## explicit; go 1.23.0
 github.com/valyala/fasthttp
 github.com/valyala/fasthttp/fasthttpadaptor
 github.com/valyala/fasthttp/fasthttputil