diff --git a/arp/stringers.go b/arp/stringers.go index cd8d0c7..376de7a 100644 --- a/arp/stringers.go +++ b/arp/stringers.go @@ -17,9 +17,9 @@ const _Operation_name = "requestreply" var _Operation_index = [...]uint8{0, 7, 12} func (i Operation) String() string { - i -= 1 - if i >= Operation(len(_Operation_index)-1) { - return "Operation(" + strconv.FormatInt(int64(i+1), 10) + ")" + idx := int(i) - 1 + if i < 1 || idx >= len(_Operation_index)-1 { + return "Operation(" + strconv.FormatInt(int64(i), 10) + ")" } - return _Operation_name[_Operation_index[i]:_Operation_index[i+1]] + return _Operation_name[_Operation_index[idx]:_Operation_index[idx+1]] } diff --git a/dhcp/dhcpv4/stringers.go b/dhcp/dhcpv4/stringers.go index 2141e9e..8dcce7b 100644 --- a/dhcp/dhcpv4/stringers.go +++ b/dhcp/dhcpv4/stringers.go @@ -106,10 +106,11 @@ const _Op_name = "undefinedrequestreply" var _Op_index = [...]uint8{0, 9, 16, 21} func (i Op) String() string { - if i >= Op(len(_Op_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_Op_index)-1 { return "Op(" + strconv.FormatInt(int64(i), 10) + ")" } - return _Op_name[_Op_index[i]:_Op_index[i+1]] + return _Op_name[_Op_index[idx]:_Op_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -131,10 +132,11 @@ const _MessageType_name = "undefineddiscoverofferrequestdeclineacknakreleaseinfo var _MessageType_index = [...]uint8{0, 9, 17, 22, 29, 36, 39, 42, 49, 55} func (i MessageType) String() string { - if i >= MessageType(len(_MessageType_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_MessageType_index)-1 { return "MessageType(" + strconv.FormatInt(int64(i), 10) + ")" } - return _MessageType_name[_MessageType_index[i]:_MessageType_index[i+1]] + return _MessageType_name[_MessageType_index[idx]:_MessageType_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -155,9 +157,9 @@ const _ClientState_name = "initselectingrequestingboundrenewingrebindinginit-reb var _ClientState_index = [...]uint8{0, 4, 13, 23, 28, 36, 45, 56, 65} func (i ClientState) String() string { - i -= 1 - if i >= ClientState(len(_ClientState_index)-1) { - return "ClientState(" + strconv.FormatInt(int64(i+1), 10) + ")" + idx := int(i) - 1 + if i < 1 || idx >= len(_ClientState_index)-1 { + return "ClientState(" + strconv.FormatInt(int64(i), 10) + ")" } - return _ClientState_name[_ClientState_index[i]:_ClientState_index[i+1]] + return _ClientState_name[_ClientState_index[idx]:_ClientState_index[idx+1]] } diff --git a/dhcp/dhcpv6/stringers.go b/dhcp/dhcpv6/stringers.go index c7c29bc..0145ead 100644 --- a/dhcp/dhcpv6/stringers.go +++ b/dhcp/dhcpv6/stringers.go @@ -28,11 +28,11 @@ const _MsgType_name = "solicitadvertiserequestconfirmrenewrebindreplyreleasedecl var _MsgType_index = [...]uint8{0, 7, 16, 23, 30, 35, 41, 46, 53, 60, 71, 85, 95, 105} func (i MsgType) String() string { - i -= 1 - if i >= MsgType(len(_MsgType_index)-1) { - return "MsgType(" + strconv.FormatInt(int64(i+1), 10) + ")" + idx := int(i) - 1 + if i < 1 || idx >= len(_MsgType_index)-1 { + return "MsgType(" + strconv.FormatInt(int64(i), 10) + ")" } - return _MsgType_name[_MsgType_index[i]:_MsgType_index[i+1]] + return _MsgType_name[_MsgType_index[idx]:_MsgType_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -51,11 +51,11 @@ const _ClientState_name = "initsolicitingrequestingboundrenewingrebinding" var _ClientState_index = [...]uint8{0, 4, 14, 24, 29, 37, 46} func (i ClientState) String() string { - i -= 1 - if i >= ClientState(len(_ClientState_index)-1) { - return "ClientState(" + strconv.FormatInt(int64(i+1), 10) + ")" + idx := int(i) - 1 + if i < 1 || idx >= len(_ClientState_index)-1 { + return "ClientState(" + strconv.FormatInt(int64(i), 10) + ")" } - return _ClientState_name[_ClientState_index[i]:_ClientState_index[i+1]] + return _ClientState_name[_ClientState_index[idx]:_ClientState_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -134,10 +134,11 @@ const _StatusCode_name = "successunspec-failno-addrs-availno-bindingnot-on-linku var _StatusCode_index = [...]uint8{0, 7, 18, 32, 42, 53, 66} func (i StatusCode) String() string { - if i >= StatusCode(len(_StatusCode_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_StatusCode_index)-1 { return "StatusCode(" + strconv.FormatInt(int64(i), 10) + ")" } - return _StatusCode_name[_StatusCode_index[i]:_StatusCode_index[i+1]] + return _StatusCode_name[_StatusCode_index[idx]:_StatusCode_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -153,9 +154,9 @@ const _DUIDType_name = "duid-lltduid-enduid-ll" var _DUIDType_index = [...]uint8{0, 8, 15, 22} func (i DUIDType) String() string { - i -= 1 - if i >= DUIDType(len(_DUIDType_index)-1) { - return "DUIDType(" + strconv.FormatInt(int64(i+1), 10) + ")" + idx := int(i) - 1 + if i < 1 || idx >= len(_DUIDType_index)-1 { + return "DUIDType(" + strconv.FormatInt(int64(i), 10) + ")" } - return _DUIDType_name[_DUIDType_index[i]:_DUIDType_index[i+1]] + return _DUIDType_name[_DUIDType_index[idx]:_DUIDType_index[idx+1]] } diff --git a/dns/stringers.go b/dns/stringers.go index f30e888..42f7947 100644 --- a/dns/stringers.go +++ b/dns/stringers.go @@ -119,10 +119,11 @@ const _RCode_name = "successformat errorserver failurename errornot implementedr var _RCode_index = [...]uint8{0, 7, 19, 33, 43, 58, 65} func (i RCode) String() string { - if i >= RCode(len(_RCode_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_RCode_index)-1 { return "RCode(" + strconv.FormatInt(int64(i), 10) + ")" } - return _RCode_name[_RCode_index[i]:_RCode_index[i+1]] + return _RCode_name[_RCode_index[idx]:_RCode_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -138,8 +139,9 @@ const _OpCode_name = "Standard queryInverse queryServer status request" var _OpCode_index = [...]uint8{0, 14, 27, 48} func (i OpCode) String() string { - if i >= OpCode(len(_OpCode_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_OpCode_index)-1 { return "OpCode(" + strconv.FormatInt(int64(i), 10) + ")" } - return _OpCode_name[_OpCode_index[i]:_OpCode_index[i+1]] + return _OpCode_name[_OpCode_index[idx]:_OpCode_index[idx+1]] } diff --git a/http/httphi/exchange_test.go b/http/httphi/exchange_test.go new file mode 100644 index 0000000..2368e25 --- /dev/null +++ b/http/httphi/exchange_test.go @@ -0,0 +1,281 @@ +package httphi + +import ( + "strings" + "testing" + "time" + + "github.com/soypat/lneto" +) + +func nopBackoff(consecutiveBackoffs uint) time.Duration { return lneto.BackoffFlagNop } + +// newExchange returns an Exchange acquired on conn, ready to serve a request. +func newExchange(t *testing.T, conn conn, bufferSize int, normalizeKeys bool) *Exchange { + t.Helper() + exch := new(Exchange) + exch.Configure(make([]byte, 2*bufferSize), bufferSize, normalizeKeys) + if !exch.Acquire(conn) { + t.Fatal("fresh exchange failed to acquire connection") + } + return exch +} + +// serve runs a single exchange to completion on the calling goroutine. +func serve(t *testing.T, request string, mux Mux) *rwconn { + t.Helper() + const bufferSize = 1024 + conn := newConn(request) + conn.Hangup() // Whole request already pending, nothing more will arrive. + exch := newExchange(t, conn, bufferSize, false) + err := Handle(exch, mux, nopBackoff) + if err != nil { + t.Fatalf("Handle(%q): %s", request, err) + } + return conn +} + +// WriteHeader must emit a complete status line terminated in CRLF followed by +// the end-of-headers CRLF, for every status code including the longest text. +func TestExchangeWriteHeader(t *testing.T) { + for _, test := range []struct { + code int + want string + }{ + {code: 200, want: "HTTP/1.1 200 OK\r\n\r\n"}, + {code: 404, want: "HTTP/1.1 404 Not Found\r\n\r\n"}, + {code: 500, want: "HTTP/1.1 500 Internal Server Error\r\n\r\n"}, + // Longest status text in status.go: worst case for the status line buffer. + {code: 511, want: "HTTP/1.1 511 Network Authentication Required\r\n\r\n"}, + } { + exch := newExchange(t, newConn(""), 128, false) + exch.WriteHeader(test.code) + if got := exch.rw.(*rwconn).ViewWritten(); got != test.want { + t.Errorf("code %d: want %q, got %q", test.code, test.want, got) + } + } +} + +// Status line is written once: a second WriteHeader must not reach the wire. +func TestExchangeWriteHeaderOnce(t *testing.T) { + conn := newConn("") + exch := newExchange(t, conn, 128, false) + exch.WriteHeader(404) + exch.WriteHeader(500) + const want = "HTTP/1.1 404 Not Found\r\n\r\n" + if got := conn.ViewWritten(); got != want { + t.Errorf("want %q, got %q", want, got) + } +} + +// Write with no prior WriteHeader must flush a 200 header ahead of the body. +func TestExchangeWriteFlushesHeader(t *testing.T) { + const body = "hello" + conn := newConn("") + exch := newExchange(t, conn, 128, false) + n, err := exch.Write([]byte(body)) + if err != nil { + t.Fatal(err) + } + if n != len(body) { + t.Errorf("want %d bytes written, got %d", len(body), n) + } + const want = "HTTP/1.1 200 OK\r\n\r\n" + body + if got := conn.ViewWritten(); got != want { + t.Errorf("want %q, got %q", want, got) + } +} + +func TestExchangeSetHeader(t *testing.T) { + for _, test := range []struct { + name string + normalize bool + set [][2]string + want string // Header block emitted after the status line. + }{ + {name: "none", want: "\r\n"}, + {name: "single", set: [][2]string{{"Content-Type", "text/plain"}}, want: "Content-Type:text/plain\r\n\r\n"}, + { + name: "multiple", + set: [][2]string{{"Content-Type", "text/plain"}, {"Content-Length", "5"}}, + want: "Content-Type:text/plain\r\nContent-Length:5\r\n\r\n", + }, + { + name: "normalized key", + normalize: true, + set: [][2]string{{"content-TYPE", "text/plain"}}, + want: "Content-Type:text/plain\r\n\r\n", + }, + { + name: "key kept verbatim when not normalizing", + set: [][2]string{{"content-TYPE", "text/plain"}}, + want: "content-TYPE:text/plain\r\n\r\n", + }, + {name: "empty value", set: [][2]string{{"X-Empty", ""}}, want: "X-Empty:\r\n\r\n"}, + } { + t.Run(test.name, func(t *testing.T) { + conn := newConn("") + exch := newExchange(t, conn, 128, test.normalize) + for _, kv := range test.set { + if !exch.SetHeader(kv[0], kv[1]) { + t.Fatalf("SetHeader(%q,%q) reported insufficient memory", kv[0], kv[1]) + } + } + exch.WriteHeader(200) + got, found := strings.CutPrefix(conn.ViewWritten(), "HTTP/1.1 200 OK\r\n") + if !found { + t.Fatalf("want 200 status line, got %q", conn.ViewWritten()) + } + if got != test.want { + t.Errorf("want header block %q, got %q", test.want, got) + } + }) + } +} + +// SetHeader must refuse to write past the buffer and say so, never panic nor +// emit a truncated field. +func TestExchangeSetHeaderOOM(t *testing.T) { + const bufferSize = 32 + conn := newConn("") + exch := newExchange(t, conn, bufferSize, false) + if exch.SetHeader("X-Big", strings.Repeat("v", 4*bufferSize)) { + t.Fatal("want insufficient memory reported for oversized header value") + } + exch.WriteHeader(200) + if got := conn.ViewWritten(); strings.Contains(got, "X-Big") { + t.Errorf("dropped header must not appear in response, got %q", got) + } +} + +// Request line and fields the handler observes, over a spread of well formed +// and awkward but legal request headers. +func TestHandleRequestFields(t *testing.T) { + for _, test := range []struct { + name string + request string + wantMethod string + wantURI string + wantHost string + }{ + { + name: "minimal", + request: "GET / HTTP/1.1\r\nHost: h\r\n\r\n", + wantMethod: "GET", wantURI: "/", wantHost: "h", + }, + { + name: "query string", + request: "GET /search?q=go&n=1 HTTP/1.1\r\nHost: h\r\n\r\n", + wantMethod: "GET", wantURI: "/search?q=go&n=1", wantHost: "h", + }, + { + name: "no fields", + request: "GET /x HTTP/1.1\r\n\r\n", + wantMethod: "GET", wantURI: "/x", wantHost: "", + }, + { + name: "post", + request: "POST /submit HTTP/1.1\r\nHost: h\r\nContent-Length: 0\r\n\r\n", + wantMethod: "POST", wantURI: "/submit", wantHost: "h", + }, + { + name: "extension method", + request: "FROBNICATE / HTTP/1.1\r\nHost: h\r\n\r\n", + wantMethod: "FROBNICATE", wantURI: "/", wantHost: "h", + }, + } { + t.Run(test.name, func(t *testing.T) { + var gotMethod, gotURI, gotHost string + var sm sliceMux + sm.Handle(test.wantURI, func(ex *Exchange) { + gotMethod = string(ex.RequestMethod()) + gotURI = string(ex.RequestURI()) + gotHost = string(ex.RequestHeader("Host")) + ex.WriteHeader(200) + }) + serve(t, test.request, &sm) + + if gotMethod != test.wantMethod { + t.Errorf("want method %q, got %q", test.wantMethod, gotMethod) + } + if gotURI != test.wantURI { + t.Errorf("want URI %q, got %q", test.wantURI, gotURI) + } + if gotHost != test.wantHost { + t.Errorf("want Host %q, got %q", test.wantHost, gotHost) + } + }) + } +} + +// Malformed request headers must fail the exchange, never reach a handler. +func TestHandleMalformedRequest(t *testing.T) { + for _, test := range []struct { + name string + request string + }{ + {name: "no colon in field", request: "GET / HTTP/1.1\r\nBadFieldNoColon\r\n\r\n"}, + {name: "no protocol", request: "GET /\r\nHost: h\r\n\r\n"}, + {name: "empty request line", request: "\r\n\r\n"}, + {name: "truncated header", request: "GET / HTTP/1.1\r\nHost: h\r\n"}, + } { + t.Run(test.name, func(t *testing.T) { + var handled bool + var sm sliceMux + sm.Handle("/", func(ex *Exchange) { handled = true }) + conn := newConn(test.request) + conn.Hangup() + exch := newExchange(t, conn, 1024, false) + if err := Handle(exch, &sm, nopBackoff); err == nil { + t.Error("want error on malformed request, got nil") + } + if handled { + t.Error("handler must not run on malformed request") + } + }) + } +} + +// No registered handler must yield 404, not an empty response. +func TestHandleNoHandler(t *testing.T) { + var sm sliceMux + sm.Handle("GET /", func(ex *Exchange) { t.Error("handler must not run") }) + conn := serve(t, "GET /nowhere HTTP/1.1\r\nHost: h\r\n\r\n", &sm) + const want = "HTTP/1.1 404 Not Found\r\n\r\n" + if got := conn.ViewWritten(); got != want { + t.Errorf("want %q, got %q", want, got) + } +} + +// A handler that writes nothing must still produce a valid response. +func TestHandleSilentHandler(t *testing.T) { + var sm sliceMux + sm.Handle("/", func(ex *Exchange) {}) + conn := serve(t, "GET / HTTP/1.1\r\nHost: h\r\n\r\n", &sm) + const want = "HTTP/1.1 200 OK\r\n\r\n" + if got := conn.ViewWritten(); got != want { + t.Errorf("want %q, got %q", want, got) + } +} + +// Body bytes arriving in the same segment as the header must be readable. +func TestExchangeReadBody(t *testing.T) { + const body = "message body" + var got string + var readErr error + var sm sliceMux + sm.Handle("POST /", func(ex *Exchange) { + dst := make([]byte, len(body)) + n, err := ex.ReadBody(dst) + got, readErr = string(dst[:n]), err + ex.WriteHeader(200) + }) + serve(t, "POST / HTTP/1.1\r\nHost: h\r\nContent-Length: 12\r\n\r\n"+body, &sm) + + if readErr != nil { + t.Fatal(readErr) + } + if got != body { + t.Errorf("want body %q, got %q", body, got) + } +} diff --git a/http/httphi/httphi.go b/http/httphi/httphi.go index f401725..dd24305 100644 --- a/http/httphi/httphi.go +++ b/http/httphi/httphi.go @@ -1,6 +1,7 @@ package httphi import ( + "errors" "io" "log/slog" "strconv" @@ -16,6 +17,8 @@ import ( //go:generate stringer -type Method,status -linecomment -output stringers.go +var errNoRequestProto = errors.New("httphi: request line with no HTTP version") + type conn = io.ReadWriteCloser // Router hosts concurrent safe data. @@ -160,6 +163,13 @@ func Handle(exch *Exchange, mux Mux, backoff lneto.BackoffStrategy) error { exch.respRemains = reqhdr.BufferReceived() - parsed exch.respHeaderOff = uint16(parsed) exch.respHeaderLen = 0 + if len(reqhdr.Protocol()) == 0 { + // Request line with no HTTP version is a HTTP/0.9 simple-request, which + // httpraw tolerates. It is not a valid HTTP/1.1 request-line, RFC 9112 3. + exch.WriteHeader(int(StatusBadRequest)) + exch.rw.Close() + return errNoRequestProto + } // Mux URI. uri := reqhdr.RequestURI() meth := reqhdr.Method() @@ -272,9 +282,13 @@ func (r *Router) info(msg string, attrs ...slog.Attr) { internal.LogAttrs(r.log, slog.LevelInfo, msg, attrs...) } +// maxStatusLine bounds the response status line: "HTTP/1.1 " + 3 digit code + +// " " + longest [StatusText] + CRLF. +const maxStatusLine = len("HTTP/1.1 ") + 3 + 1 + len("Network Authentication Required") + 2 + type Exchange struct { used atomic.Bool - respTopBuf [32]byte + respTopBuf [maxStatusLine]byte respTopWritten uint8 rawbuf []byte @@ -357,7 +371,7 @@ func (exch *Exchange) StageWriteStatus(code int) { n += copy(exch.respTopBuf[n:], text) exch.respTopBuf[n] = '\r' exch.respTopBuf[n+1] = '\n' - exch.respTopWritten = uint8(n) + exch.respTopWritten = uint8(n + 2) } func (exch *Exchange) WriteHeader(code int) { diff --git a/http/httphi/router_test.go b/http/httphi/router_test.go index 3f11e56..6a5ca99 100644 --- a/http/httphi/router_test.go +++ b/http/httphi/router_test.go @@ -16,11 +16,16 @@ import ( // rwconn is a in-memory conn. The router handles connections on another // goroutine so every field is guarded; onClose lets tests await the handler. +// +// A drained rwconn reads (0,nil) as a live socket with no data pending would, +// so a partial request can be completed with AddReadable mid-handling. Tests +// that need the peer to hang up call Hangup. type rwconn struct { mu sync.Mutex readable bytes.Buffer written bytes.Buffer closed bool + hangup bool onClose chan struct{} deadline time.Time } @@ -33,6 +38,14 @@ func newConn(request string) *rwconn { return r } +// Hangup makes reads past the pending data return [io.EOF], as a peer that +// closed its side of the connection would. +func (r *rwconn) Hangup() { + r.mu.Lock() + defer r.mu.Unlock() + r.hangup = true +} + func (r *rwconn) Close() error { r.mu.Lock() defer r.mu.Unlock() @@ -63,7 +76,10 @@ func (r *rwconn) Read(b []byte) (int, error) { } else if r.deadlineExceeded() { return 0, context.DeadlineExceeded } else if r.readable.Len() == 0 { - return 0, io.EOF + if r.hangup { + return 0, io.EOF + } + return 0, nil // No data pending, handler backs off and retries. } return r.readable.Read(b) } diff --git a/http/httphi/stringers.go b/http/httphi/stringers.go new file mode 100644 index 0000000..599ba7d --- /dev/null +++ b/http/httphi/stringers.go @@ -0,0 +1,175 @@ +// Code generated by "stringer -type Method,status -linecomment -output stringers.go"; DO NOT EDIT. + +package httphi + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[MethUndefined-0] + _ = x[MethGet-1] + _ = x[MethHead-2] + _ = x[MethPost-3] + _ = x[MethPut-4] + _ = x[MethPatch-5] + _ = x[MethDelete-6] + _ = x[MethConnect-7] + _ = x[MethOptions-8] + _ = x[MethTrace-9] + _ = x[MethUnknown-10] +} + +const _Method_name = "undefinedGETHEADPOSTPUTPATCHDELETECONNECTOPTIONSTRACEunknown" + +var _Method_index = [...]uint8{0, 9, 12, 16, 20, 23, 28, 34, 41, 48, 53, 60} + +func (i Method) String() string { + idx := int(i) - 0 + if i < 0 || idx >= len(_Method_index)-1 { + return "Method(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Method_name[_Method_index[idx]:_Method_index[idx+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[StatusContinue-100] + _ = x[StatusSwitchingProtocols-101] + _ = x[StatusProcessing-102] + _ = x[StatusEarlyHints-103] + _ = x[StatusOK-200] + _ = x[StatusCreated-201] + _ = x[StatusAccepted-202] + _ = x[StatusNonAuthoritativeInfo-203] + _ = x[StatusNoContent-204] + _ = x[StatusResetContent-205] + _ = x[StatusPartialContent-206] + _ = x[StatusMultiStatus-207] + _ = x[StatusAlreadyReported-208] + _ = x[StatusIMUsed-226] + _ = x[StatusMultipleChoices-300] + _ = x[StatusMovedPermanently-301] + _ = x[StatusFound-302] + _ = x[StatusSeeOther-303] + _ = x[StatusNotModified-304] + _ = x[StatusUseProxy-305] + _ = x[StatusTemporaryRedirect-307] + _ = x[StatusPermanentRedirect-308] + _ = x[StatusBadRequest-400] + _ = x[StatusUnauthorized-401] + _ = x[StatusPaymentRequired-402] + _ = x[StatusForbidden-403] + _ = x[StatusNotFound-404] + _ = x[StatusMethodNotAllowed-405] + _ = x[StatusNotAcceptable-406] + _ = x[StatusProxyAuthRequired-407] + _ = x[StatusRequestTimeout-408] + _ = x[StatusConflict-409] + _ = x[StatusGone-410] + _ = x[StatusLengthRequired-411] + _ = x[StatusPreconditionFailed-412] + _ = x[StatusRequestEntityTooLarge-413] + _ = x[StatusRequestURITooLong-414] + _ = x[StatusUnsupportedMediaType-415] + _ = x[StatusRequestedRangeNotSatisfiable-416] + _ = x[StatusExpectationFailed-417] + _ = x[StatusTeapot-418] + _ = x[StatusMisdirectedRequest-421] + _ = x[StatusUnprocessableEntity-422] + _ = x[StatusLocked-423] + _ = x[StatusFailedDependency-424] + _ = x[StatusTooEarly-425] + _ = x[StatusUpgradeRequired-426] + _ = x[StatusPreconditionRequired-428] + _ = x[StatusTooManyRequests-429] + _ = x[StatusRequestHeaderFieldsTooLarge-431] + _ = x[StatusUnavailableForLegalReasons-451] + _ = x[StatusInternalServerError-500] + _ = x[StatusNotImplemented-501] + _ = x[StatusBadGateway-502] + _ = x[StatusServiceUnavailable-503] + _ = x[StatusGatewayTimeout-504] + _ = x[StatusHTTPVersionNotSupported-505] + _ = x[StatusVariantAlsoNegotiates-506] + _ = x[StatusInsufficientStorage-507] + _ = x[StatusLoopDetected-508] + _ = x[StatusNotExtended-510] + _ = x[StatusNetworkAuthenticationRequired-511] +} + +const _status_name = "ContinueSwitching ProtocolsProcessingEarly HintsOKCreatedAcceptedNon-Authoritative InformationNo ContentReset ContentPartial ContentMulti-StatusAlready ReportedIM UsedMultiple ChoicesMoved PermanentlyFoundSee OtherNot ModifiedUse ProxyTemporary RedirectPermanent RedirectBad RequestUnauthorizedPayment RequiredForbiddenNot FoundMethod Not AllowedNot AcceptableProxy Authentication RequiredRequest TimeoutConflictGoneLength RequiredPrecondition FailedRequest Entity Too LargeRequest URI Too LongUnsupported Media TypeRequested Range Not SatisfiableExpectation FailedI'm a teapotMisdirected RequestUnprocessable EntityLockedFailed DependencyToo EarlyUpgrade RequiredPrecondition RequiredToo Many RequestsRequest Header Fields Too LargeUnavailable For Legal ReasonsInternal Server ErrorNot ImplementedBad GatewayService UnavailableGateway TimeoutHTTP Version Not SupportedVariant Also NegotiatesInsufficient StorageLoop DetectedNot ExtendedNetwork Authentication Required" + +var _status_map = map[status]string{ + 100: _status_name[0:8], + 101: _status_name[8:27], + 102: _status_name[27:37], + 103: _status_name[37:48], + 200: _status_name[48:50], + 201: _status_name[50:57], + 202: _status_name[57:65], + 203: _status_name[65:94], + 204: _status_name[94:104], + 205: _status_name[104:117], + 206: _status_name[117:132], + 207: _status_name[132:144], + 208: _status_name[144:160], + 226: _status_name[160:167], + 300: _status_name[167:183], + 301: _status_name[183:200], + 302: _status_name[200:205], + 303: _status_name[205:214], + 304: _status_name[214:226], + 305: _status_name[226:235], + 307: _status_name[235:253], + 308: _status_name[253:271], + 400: _status_name[271:282], + 401: _status_name[282:294], + 402: _status_name[294:310], + 403: _status_name[310:319], + 404: _status_name[319:328], + 405: _status_name[328:346], + 406: _status_name[346:360], + 407: _status_name[360:389], + 408: _status_name[389:404], + 409: _status_name[404:412], + 410: _status_name[412:416], + 411: _status_name[416:431], + 412: _status_name[431:450], + 413: _status_name[450:474], + 414: _status_name[474:494], + 415: _status_name[494:516], + 416: _status_name[516:547], + 417: _status_name[547:565], + 418: _status_name[565:577], + 421: _status_name[577:596], + 422: _status_name[596:616], + 423: _status_name[616:622], + 424: _status_name[622:639], + 425: _status_name[639:648], + 426: _status_name[648:664], + 428: _status_name[664:685], + 429: _status_name[685:702], + 431: _status_name[702:733], + 451: _status_name[733:762], + 500: _status_name[762:783], + 501: _status_name[783:798], + 502: _status_name[798:809], + 503: _status_name[809:828], + 504: _status_name[828:843], + 505: _status_name[843:869], + 506: _status_name[869:892], + 507: _status_name[892:912], + 508: _status_name[912:925], + 510: _status_name[925:937], + 511: _status_name[937:968], +} + +func (i status) String() string { + if str, ok := _status_map[i]; ok { + return str + } + return "status(" + strconv.FormatInt(int64(i), 10) + ")" +} diff --git a/internet/pcap/stringers.go b/internet/pcap/stringers.go index ef2dae0..0b4da7b 100644 --- a/internet/pcap/stringers.go +++ b/internet/pcap/stringers.go @@ -33,8 +33,9 @@ const _FieldClass_name = "undefinedsourcedestinationprotocolversiontypesizeflags var _FieldClass_index = [...]uint8{0, 9, 15, 26, 34, 41, 45, 49, 54, 68, 76, 83, 90, 94, 101, 112, 114, 123, 131} func (i FieldClass) String() string { - if i >= FieldClass(len(_FieldClass_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_FieldClass_index)-1 { return "FieldClass(" + strconv.FormatInt(int64(i), 10) + ")" } - return _FieldClass_name[_FieldClass_index[i]:_FieldClass_index[i+1]] + return _FieldClass_name[_FieldClass_index[idx]:_FieldClass_index[idx+1]] } diff --git a/ipv4/icmpv4/stringers.go b/ipv4/icmpv4/stringers.go index 5481f09..defc5bd 100644 --- a/ipv4/icmpv4/stringers.go +++ b/ipv4/icmpv4/stringers.go @@ -66,10 +66,11 @@ const _CodeDestinationUnreachable_name = "net unreachablehost unreachableprotoco var _CodeDestinationUnreachable_index = [...]uint8{0, 15, 31, 51, 67, 98, 117} func (i CodeDestinationUnreachable) String() string { - if i >= CodeDestinationUnreachable(len(_CodeDestinationUnreachable_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_CodeDestinationUnreachable_index)-1 { return "CodeDestinationUnreachable(" + strconv.FormatInt(int64(i), 10) + ")" } - return _CodeDestinationUnreachable_name[_CodeDestinationUnreachable_index[i]:_CodeDestinationUnreachable_index[i+1]] + return _CodeDestinationUnreachable_name[_CodeDestinationUnreachable_index[idx]:_CodeDestinationUnreachable_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -86,8 +87,9 @@ const _CodeRedirect_name = "redirect for networkredirect for hostredirect for To var _CodeRedirect_index = [...]uint8{0, 20, 37, 61, 82} func (i CodeRedirect) String() string { - if i >= CodeRedirect(len(_CodeRedirect_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_CodeRedirect_index)-1 { return "CodeRedirect(" + strconv.FormatInt(int64(i), 10) + ")" } - return _CodeRedirect_name[_CodeRedirect_index[i]:_CodeRedirect_index[i+1]] + return _CodeRedirect_name[_CodeRedirect_index[idx]:_CodeRedirect_index[idx+1]] } diff --git a/ipv6/icmpv6/stringers.go b/ipv6/icmpv6/stringers.go index a184f29..8b3cf93 100644 --- a/ipv6/icmpv6/stringers.go +++ b/ipv6/icmpv6/stringers.go @@ -66,10 +66,11 @@ const _CodeDestinationUnreachable_name = "no route to destinationcommunication a var _CodeDestinationUnreachable_index = [...]uint8{0, 23, 64, 94, 113, 129, 172, 199} func (i CodeDestinationUnreachable) String() string { - if i >= CodeDestinationUnreachable(len(_CodeDestinationUnreachable_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_CodeDestinationUnreachable_index)-1 { return "CodeDestinationUnreachable(" + strconv.FormatInt(int64(i), 10) + ")" } - return _CodeDestinationUnreachable_name[_CodeDestinationUnreachable_index[i]:_CodeDestinationUnreachable_index[i+1]] + return _CodeDestinationUnreachable_name[_CodeDestinationUnreachable_index[idx]:_CodeDestinationUnreachable_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -85,8 +86,9 @@ const _CodeParameterProblem_name = "erroneous header field encounteredunrecogniz var _CodeParameterProblem_index = [...]uint8{0, 34, 75, 111} func (i CodeParameterProblem) String() string { - if i >= CodeParameterProblem(len(_CodeParameterProblem_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_CodeParameterProblem_index)-1 { return "CodeParameterProblem(" + strconv.FormatInt(int64(i), 10) + ")" } - return _CodeParameterProblem_name[_CodeParameterProblem_index[i]:_CodeParameterProblem_index[i+1]] + return _CodeParameterProblem_name[_CodeParameterProblem_index[idx]:_CodeParameterProblem_index[idx+1]] } diff --git a/phy/phy_stringers.go b/phy/phy_stringers.go index 772c694..8b18474 100644 --- a/phy/phy_stringers.go +++ b/phy/phy_stringers.go @@ -29,8 +29,9 @@ const _LinkMode_name = "down10M-H10M-F100M-H100M-F100M-T41000M-H1000M-F2.5G-F5G- var _LinkMode_index = [...]uint8{0, 4, 9, 14, 20, 26, 33, 40, 47, 53, 57, 62, 67, 72, 78} func (i LinkMode) String() string { - if i >= LinkMode(len(_LinkMode_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_LinkMode_index)-1 { return "LinkMode(" + strconv.FormatInt(int64(i), 10) + ")" } - return _LinkMode_name[_LinkMode_index[i]:_LinkMode_index[i+1]] + return _LinkMode_name[_LinkMode_index[idx]:_LinkMode_index[idx+1]] } diff --git a/stringers.go b/stringers.go index 58e5b74..2b117d8 100644 --- a/stringers.go +++ b/stringers.go @@ -212,16 +212,17 @@ func _() { _ = x[ErrAlreadyRegistered-17] _ = x[ErrTruncatedFrame-18] _ = x[ErrMissingHALConfig-19] + _ = x[ErrBadState-20] } const ( _errGeneric_name_0 = "lneto-bug(use build tag \"debugheaplog\")packet droppedincorrect checksumzero source(port/addr)zero destination(port/addr)short bufferbuffer fullinvalid addressunsupportedmismatchmismatched lengthinvalid configuration" - _errGeneric_name_1 = "invalid fieldinvalid length fieldresource exhaustedprotocol already registeredtruncated framemissing HAL configuration" + _errGeneric_name_1 = "invalid fieldinvalid length fieldresource exhaustedprotocol already registeredtruncated framemissing HAL configurationoperation invalid in current state" ) var ( _errGeneric_index_0 = [...]uint8{0, 39, 53, 71, 93, 120, 132, 143, 158, 169, 177, 194, 215} - _errGeneric_index_1 = [...]uint8{0, 13, 33, 51, 78, 93, 118} + _errGeneric_index_1 = [...]uint8{0, 13, 33, 51, 78, 93, 118, 152} ) func (i errGeneric) String() string { @@ -229,7 +230,7 @@ func (i errGeneric) String() string { case 1 <= i && i <= 12: i -= 1 return _errGeneric_name_0[_errGeneric_index_0[i]:_errGeneric_index_0[i+1]] - case 14 <= i && i <= 19: + case 14 <= i && i <= 20: i -= 14 return _errGeneric_name_1[_errGeneric_index_1[i]:_errGeneric_index_1[i+1]] default: diff --git a/tcp/stringers.go b/tcp/stringers.go index 52c90c7..abc7bb6 100644 --- a/tcp/stringers.go +++ b/tcp/stringers.go @@ -26,10 +26,11 @@ const _State_name = "CLOSEDLISTENSYN-RECEIVEDSYN-SENTESTABLISHEDFIN-WAIT-1FIN-WA var _State_index = [...]uint8{0, 6, 12, 24, 32, 43, 53, 63, 70, 79, 89, 97} func (i State) String() string { - if i >= State(len(_State_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_State_index)-1 { return "State(" + strconv.FormatInt(int64(i), 10) + ")" } - return _State_name[_State_index[i]:_State_index[i+1]] + return _State_name[_State_index[idx]:_State_index[idx+1]] } func _() { // An "invalid array index" compiler error signifies that the constant values have changed.