update with changes from go1.20.5 to go1.21.4

This commit is contained in:
Scott Feldman
2023-11-13 23:28:14 -08:00
committed by deadprogram
parent be25e1a28e
commit 7c11b88ce6
32 changed files with 139 additions and 347 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ packages in a TinyGo application.
## "net" Package ## "net" Package
The "net" package is ported from Go 1.20.5. The tree listings below shows the The "net" package is ported from Go 1.21.4. The tree listings below shows the
files copied. If the file is marked with an '\*', it is copied _and_ modified files copied. If the file is marked with an '\*', it is copied _and_ modified
to work with netdev. If the file is marked with an '+', the file is new. If to work with netdev. If the file is marked with an '+', the file is new. If
there is no mark, it is a straight copy. there is no mark, it is a straight copy.
+4 -3
View File
@@ -1,9 +1,10 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// TINYGO: Omit DualStack support // TINYGO: Omit DualStack support
// TINYGO: Omit Fast Fallback support // TINYGO: Omit Fast Fallback support
// TINYGO: Don't allow alternate resolver // TINYGO: Don't allow alternate resolver
// TINYGO: Omit DialTimeout // TINYGO: Omit DialTimeout
// TINYGO: Omit Multipath TCP
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
@@ -17,9 +18,9 @@ import (
"time" "time"
) )
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See golang.org/issue/31510
const ( const (
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
// See go.dev/issue/31510
defaultTCPKeepAlive = 15 * time.Second defaultTCPKeepAlive = 15 * time.Second
) )
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2019 The Go Authors. All rights reserved. // Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// TINYGO: Removed trace stuff // TINYGO: Removed trace stuff
+9 -3
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2016 The Go Authors. All rights reserved. // Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
@@ -88,14 +88,20 @@ func hexEscapeNonASCII(s string) string {
return s return s
} }
b := make([]byte, 0, newLen) b := make([]byte, 0, newLen)
var pos int
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
if s[i] >= utf8.RuneSelf { if s[i] >= utf8.RuneSelf {
if pos < i {
b = append(b, s[pos:i]...)
}
b = append(b, '%') b = append(b, '%')
b = strconv.AppendInt(b, int64(s[i]), 16) b = strconv.AppendInt(b, int64(s[i]), 16)
} else { pos = i + 1
b = append(b, s[i])
} }
} }
if pos < len(s) {
b = append(b, s[pos:]...)
}
return string(b) return string(b)
} }
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2021 The Go Authors. All rights reserved. // Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2021 The Go Authors. All rights reserved. // Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2015 The Go Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+38 -33
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// TINYGO: Removed multipart stuff // TINYGO: Removed multipart stuff
// TINYGO: Removed trace stuff // TINYGO: Removed trace stuff
@@ -22,7 +22,6 @@ import (
"io" "io"
"mime" "mime"
"mime/multipart" "mime/multipart"
"net"
"net/http/internal/ascii" "net/http/internal/ascii"
"net/textproto" "net/textproto"
"net/url" "net/url"
@@ -30,6 +29,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"golang.org/x/net/http/httpguts"
) )
const ( const (
@@ -50,6 +51,11 @@ type ProtocolError struct {
func (pe *ProtocolError) Error() string { return pe.ErrorString } func (pe *ProtocolError) Error() string { return pe.ErrorString }
// Is lets http.ErrNotSupported match errors.ErrUnsupported.
func (pe *ProtocolError) Is(err error) bool {
return pe == ErrNotSupported && err == errors.ErrUnsupported
}
var ( var (
// ErrNotSupported indicates that a feature is not supported. // ErrNotSupported indicates that a feature is not supported.
// //
@@ -573,12 +579,40 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
// is not given, use the host from the request URL. // is not given, use the host from the request URL.
// //
// Clean the host, in case it arrives with unexpected stuff in it. // Clean the host, in case it arrives with unexpected stuff in it.
host := cleanHost(r.Host) host := r.Host
if host == "" { if host == "" {
if r.URL == nil { if r.URL == nil {
return errMissingHost return errMissingHost
} }
host = cleanHost(r.URL.Host) host = r.URL.Host
}
host, err = httpguts.PunycodeHostPort(host)
if err != nil {
return err
}
// Validate that the Host header is a valid header in general,
// but don't validate the host itself. This is sufficient to avoid
// header or request smuggling via the Host field.
// The server can (and will, if it's a net/http server) reject
// the request if it doesn't consider the host valid.
if !httpguts.ValidHostHeader(host) {
// Historically, we would truncate the Host header after '/' or ' '.
// Some users have relied on this truncation to convert a network
// address such as Unix domain socket path into a valid, ignored
// Host header (see https://go.dev/issue/61431).
//
// We don't preserve the truncation, because sending an altered
// header field opens a smuggling vector. Instead, zero out the
// Host header entirely if it isn't valid. (An empty Host is valid;
// see RFC 9112 Section 3.2.)
//
// Return an error if we're sending to a proxy, since the proxy
// probably can't do anything useful with an empty Host header.
if !usingProxy {
host = ""
} else {
return errors.New("http: invalid Host header")
}
} }
// According to RFC 6874, an HTTP client, proxy, or other // According to RFC 6874, an HTTP client, proxy, or other
@@ -706,35 +740,6 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
// This error type should not escape the net/http package to users. // This error type should not escape the net/http package to users.
type requestBodyReadError struct{ error } type requestBodyReadError struct{ error }
// cleanHost cleans up the host sent in request's Host header.
//
// It both strips anything after '/' or ' ', and puts the value
// into Punycode form, if necessary.
//
// Ideally we'd clean the Host header according to the spec:
//
// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
// https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host)
//
// But practically, what we are trying to avoid is the situation in
// issue 11206, where a malformed Host header used in the proxy context
// would create a bad request. So it is enough to just truncate at the
// first offending character.
// TINYGO: Removed IDNA checks...it doubled the binary size
func cleanHost(in string) string {
if i := strings.IndexAny(in, " /"); i != -1 {
in = in[:i]
}
host, port, err := net.SplitHostPort(in)
if err != nil { // input was just a host
return in
}
return net.JoinHostPort(host, port)
}
// removeZone removes IPv6 zone identifier from host. // removeZone removes IPv6 zone identifier from host.
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
func removeZone(host string) string { func removeZone(host string) string {
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// TINYGO: Removed TLS connection state // TINYGO: Removed TLS connection state
// TINYGO: Added onEOF hook to get callback when response has been read // TINYGO: Added onEOF hook to get callback when response has been read
+29 -32
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// TINYGO: atomic.Pointer and atomic.Uint64 are added in Go 1.19, so keep // TINYGO: atomic.Pointer and atomic.Uint64 are added in Go 1.19, so keep
// pre-1.19 code to cover min TinyGo. If TinyGo min moves to 1.19 or higher, // pre-1.19 code to cover min TinyGo. If TinyGo min moves to 1.19 or higher,
@@ -469,6 +469,10 @@ type response struct {
// Content-Length. // Content-Length.
closeAfterReply bool closeAfterReply bool
// When fullDuplex is false (the default), we consume any remaining
// request body before starting to write a response.
fullDuplex bool
// requestBodyLimitHit is set by requestTooLarge when // requestBodyLimitHit is set by requestTooLarge when
// maxBytesReader hits its max size. It is checked in // maxBytesReader hits its max size. It is checked in
// WriteHeader, to make sure we don't consume the // WriteHeader, to make sure we don't consume the
@@ -506,6 +510,11 @@ func (c *response) SetWriteDeadline(deadline time.Time) error {
return c.conn.rwc.SetWriteDeadline(deadline) return c.conn.rwc.SetWriteDeadline(deadline)
} }
func (c *response) EnableFullDuplex() error {
c.fullDuplex = true
return nil
}
// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys // TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
// that, if present, signals that the map entry is actually for // that, if present, signals that the map entry is actually for
// the response trailers, and not the response headers. The prefix // the response trailers, and not the response headers. The prefix
@@ -1162,8 +1171,11 @@ func (w *response) WriteHeader(code int) {
} }
checkWriteHeaderCode(code) checkWriteHeaderCode(code)
// Handle informational headers // Handle informational headers.
if code >= 100 && code <= 199 { //
// We shouldn't send any further headers after 101 Switching Protocols,
// so it takes the non-informational path.
if code >= 100 && code <= 199 && code != StatusSwitchingProtocols {
// Prevent a potential race with an automatically-sent 100 Continue triggered by Request.Body.Read() // Prevent a potential race with an automatically-sent 100 Continue triggered by Request.Body.Read()
if code == 100 && w.canWriteContinue.isSet() { if code == 100 && w.canWriteContinue.isSet() {
w.writeContinueMu.Lock() w.writeContinueMu.Lock()
@@ -1325,7 +1337,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// send a Content-Length header. // send a Content-Length header.
// Further, we don't send an automatic Content-Length if they // Further, we don't send an automatic Content-Length if they
// set a Transfer-Encoding, because they're generally incompatible. // set a Transfer-Encoding, because they're generally incompatible.
if w.handlerDone.isSet() && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) { if w.handlerDone.isSet() && !trailers && !hasTE && bodyAllowedForStatus(w.status) && !header.has("Content-Length") && (!isHEAD || len(p) > 0) {
w.contentLength = int64(len(p)) w.contentLength = int64(len(p))
setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10) setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
} }
@@ -1371,14 +1383,14 @@ func (cw *chunkWriter) writeHeader(p []byte) {
w.closeAfterReply = true w.closeAfterReply = true
} }
// Per RFC 2616, we should consume the request body before // We do this by default because there are a number of clients that
// replying, if the handler hasn't already done so. But we // send a full request before starting to read the response, and they
// don't want to do an unbounded amount of reading here for // can deadlock if we start writing the response with unconsumed body
// DoS reasons, so we only try up to a threshold. // remaining. See Issue 15527 for some history.
// TODO(bradfitz): where does RFC 2616 say that? See Issue 15527 //
// about HTTP/1.x Handlers concurrently reading and writing, like // If full duplex mode has been enabled with ResponseController.EnableFullDuplex,
// HTTP/2 handlers can do. Maybe this code should be relaxed? // then leave the request body alone.
if w.req.ContentLength != 0 && !w.closeAfterReply { if w.req.ContentLength != 0 && !w.closeAfterReply && !w.fullDuplex {
var discard, tooBig bool var discard, tooBig bool
switch bdy := w.req.Body.(type) { switch bdy := w.req.Body.(type) {
@@ -1766,7 +1778,7 @@ type closeWriter interface {
var _ closeWriter = (*net.TCPConn)(nil) var _ closeWriter = (*net.TCPConn)(nil)
// closeWrite flushes any outstanding data and sends a FIN packet (if // closeWriteAndWait flushes any outstanding data and sends a FIN packet (if
// client is connected via TCP), signaling that we're done. We then // client is connected via TCP), signaling that we're done. We then
// pause for a bit, hoping the client processes it before any // pause for a bit, hoping the client processes it before any
// subsequent RST. // subsequent RST.
@@ -1861,7 +1873,9 @@ func isCommonNetReadError(err error) bool {
// Serve a new connection. // Serve a new connection.
func (c *conn) serve(ctx context.Context) { func (c *conn) serve(ctx context.Context) {
c.remoteAddr = c.rwc.RemoteAddr().String() if ra := c.rwc.RemoteAddr(); ra != nil {
c.remoteAddr = ra.String()
}
ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr()) ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
var inFlightResponse *response var inFlightResponse *response
defer func() { defer func() {
@@ -2258,7 +2272,7 @@ func RedirectHandler(url string, code int) Handler {
// Longer patterns take precedence over shorter ones, so that // Longer patterns take precedence over shorter ones, so that
// if there are handlers registered for both "/images/" // if there are handlers registered for both "/images/"
// and "/images/thumbnails/", the latter handler will be // and "/images/thumbnails/", the latter handler will be
// called for paths beginning "/images/thumbnails/" and the // called for paths beginning with "/images/thumbnails/" and the
// former will receive requests for any other paths in the // former will receive requests for any other paths in the
// "/images/" subtree. // "/images/" subtree.
// //
@@ -2873,23 +2887,9 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler = globalOptionsHandler{} handler = globalOptionsHandler{}
} }
if req.URL != nil && strings.Contains(req.URL.RawQuery, ";") {
var allowQuerySemicolonsInUse int32
req = req.WithContext(context.WithValue(req.Context(), silenceSemWarnContextKey, func() {
atomic.StoreInt32(&allowQuerySemicolonsInUse, 1)
}))
defer func() {
if atomic.LoadInt32(&allowQuerySemicolonsInUse) == 0 {
sh.srv.logf("http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192")
}
}()
}
handler.ServeHTTP(rw, req) handler.ServeHTTP(rw, req)
} }
var silenceSemWarnContextKey = &contextKey{"silence-semicolons"}
// AllowQuerySemicolons returns a handler that serves requests by converting any // AllowQuerySemicolons returns a handler that serves requests by converting any
// unescaped semicolons in the URL query to ampersands, and invoking the handler h. // unescaped semicolons in the URL query to ampersands, and invoking the handler h.
// //
@@ -2901,9 +2901,6 @@ var silenceSemWarnContextKey = &contextKey{"silence-semicolons"}
// AllowQuerySemicolons should be invoked before Request.ParseForm is called. // AllowQuerySemicolons should be invoked before Request.ParseForm is called.
func AllowQuerySemicolons(h Handler) Handler { func AllowQuerySemicolons(h Handler) Handler {
return HandlerFunc(func(w ResponseWriter, r *Request) { return HandlerFunc(func(w ResponseWriter, r *Request) {
if silenceSemicolonsWarning, ok := r.Context().Value(silenceSemWarnContextKey).(func()); ok {
silenceSemicolonsWarning()
}
if strings.Contains(r.URL.RawQuery, ";") { if strings.Contains(r.URL.RawQuery, ";") {
r2 := new(Request) r2 := new(Request)
*r2 = *r *r2 = *r
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+2 -2
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// TINYGO: Removed trace stuff // TINYGO: Removed trace stuff
// TINYGO: Hook readTransfer is onEOF callback to get notified when request of // TINYGO: Hook readTransfer is onEOF callback to get notified when request of
@@ -409,7 +409,7 @@ func (t *transferWriter) doBodyCopy(dst io.Writer, src io.Reader) (n int64, err
return return
} }
// unwrapBodyReader unwraps the body's inner reader if it's a // unwrapBody unwraps the body's inner reader if it's a
// nopCloser. This is to ensure that body writes sourced from local // nopCloser. This is to ensure that body writes sourced from local
// files (*os.File types) are properly optimized. // files (*os.File types) are properly optimized.
// //
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+31 -248
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
@@ -17,6 +17,7 @@ package net
import ( import (
"internal/bytealg" "internal/bytealg"
"internal/itoa" "internal/itoa"
"net/netip"
) )
// IP address lengths (bytes). // IP address lengths (bytes).
@@ -287,25 +288,6 @@ func (ip IP) Mask(mask IPMask) IP {
return out return out
} }
// ubtoa encodes the string form of the integer v to dst[start:] and
// returns the number of bytes written to dst. The caller must ensure
// that dst has sufficient length.
func ubtoa(dst []byte, start int, v byte) int {
if v < 10 {
dst[start] = v + '0'
return 1
} else if v < 100 {
dst[start+1] = v%10 + '0'
dst[start] = v/10 + '0'
return 2
}
dst[start+2] = v%10 + '0'
dst[start+1] = (v/10)%10 + '0'
dst[start] = v/100 + '0'
return 3
}
// String returns the string form of the IP address ip. // String returns the string form of the IP address ip.
// It returns one of 4 forms: // It returns one of 4 forms:
// - "<nil>", if ip has length 0 // - "<nil>", if ip has length 0
@@ -313,73 +295,18 @@ func ubtoa(dst []byte, start int, v byte) int {
// - IPv6 conforming to RFC 5952 ("2001:db8::1"), if ip is a valid IPv6 address // - IPv6 conforming to RFC 5952 ("2001:db8::1"), if ip is a valid IPv6 address
// - the hexadecimal form of ip, without punctuation, if no other cases apply // - the hexadecimal form of ip, without punctuation, if no other cases apply
func (ip IP) String() string { func (ip IP) String() string {
p := ip
if len(ip) == 0 { if len(ip) == 0 {
return "<nil>" return "<nil>"
} }
// If IPv4, use dotted notation. if len(ip) != IPv4len && len(ip) != IPv6len {
if p4 := p.To4(); len(p4) == IPv4len {
const maxIPv4StringLen = len("255.255.255.255")
b := make([]byte, maxIPv4StringLen)
n := ubtoa(b, 0, p4[0])
b[n] = '.'
n++
n += ubtoa(b, n, p4[1])
b[n] = '.'
n++
n += ubtoa(b, n, p4[2])
b[n] = '.'
n++
n += ubtoa(b, n, p4[3])
return string(b[:n])
}
if len(p) != IPv6len {
return "?" + hexString(ip) return "?" + hexString(ip)
} }
// If IPv4, use dotted notation.
// Find longest run of zeros. if p4 := ip.To4(); len(p4) == IPv4len {
e0 := -1 return netip.AddrFrom4([4]byte(p4)).String()
e1 := -1
for i := 0; i < IPv6len; i += 2 {
j := i
for j < IPv6len && p[j] == 0 && p[j+1] == 0 {
j += 2
}
if j > i && j-i > e1-e0 {
e0 = i
e1 = j
i = j
}
} }
// The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field. return netip.AddrFrom16([16]byte(ip)).String()
if e1-e0 <= 2 {
e0 = -1
e1 = -1
}
const maxLen = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
b := make([]byte, 0, maxLen)
// Print with possible :: in place of run of zeros
for i := 0; i < IPv6len; i += 2 {
if i == e0 {
b = append(b, ':', ':')
i = e1
if i >= IPv6len {
break
}
} else if i > 0 {
b = append(b, ':')
}
b = appendHex(b, (uint32(p[i])<<8)|uint32(p[i+1]))
}
return string(b)
} }
func hexString(b []byte) string { func hexString(b []byte) string {
@@ -561,175 +488,24 @@ func (n *IPNet) String() string {
return nn.String() + "/" + itoa.Uitoa(uint(l)) return nn.String() + "/" + itoa.Uitoa(uint(l))
} }
// Parse IPv4 address (d.d.d.d).
func parseIPv4(s string) IP {
var p [IPv4len]byte
for i := 0; i < IPv4len; i++ {
if len(s) == 0 {
// Missing octets.
return nil
}
if i > 0 {
if s[0] != '.' {
return nil
}
s = s[1:]
}
n, c, ok := dtoi(s)
if !ok || n > 0xFF {
return nil
}
if c > 1 && s[0] == '0' {
// Reject non-zero components with leading zeroes.
return nil
}
s = s[c:]
p[i] = byte(n)
}
if len(s) != 0 {
return nil
}
return IPv4(p[0], p[1], p[2], p[3])
}
// parseIPv6Zone parses s as a literal IPv6 address and its associated zone
// identifier which is described in RFC 4007.
func parseIPv6Zone(s string) (IP, string) {
s, zone := splitHostZone(s)
return parseIPv6(s), zone
}
// parseIPv6 parses s as a literal IPv6 address described in RFC 4291
// and RFC 5952.
func parseIPv6(s string) (ip IP) {
ip = make(IP, IPv6len)
ellipsis := -1 // position of ellipsis in ip
// Might have leading ellipsis
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
ellipsis = 0
s = s[2:]
// Might be only ellipsis
if len(s) == 0 {
return ip
}
}
// Loop, parsing hex numbers followed by colon.
i := 0
for i < IPv6len {
// Hex number.
n, c, ok := xtoi(s)
if !ok || n > 0xFFFF {
return nil
}
// If followed by dot, might be in trailing IPv4.
if c < len(s) && s[c] == '.' {
if ellipsis < 0 && i != IPv6len-IPv4len {
// Not the right place.
return nil
}
if i+IPv4len > IPv6len {
// Not enough room.
return nil
}
ip4 := parseIPv4(s)
if ip4 == nil {
return nil
}
ip[i] = ip4[12]
ip[i+1] = ip4[13]
ip[i+2] = ip4[14]
ip[i+3] = ip4[15]
s = ""
i += IPv4len
break
}
// Save this 16-bit chunk.
ip[i] = byte(n >> 8)
ip[i+1] = byte(n)
i += 2
// Stop at end of string.
s = s[c:]
if len(s) == 0 {
break
}
// Otherwise must be followed by colon and more.
if s[0] != ':' || len(s) == 1 {
return nil
}
s = s[1:]
// Look for ellipsis.
if s[0] == ':' {
if ellipsis >= 0 { // already have one
return nil
}
ellipsis = i
s = s[1:]
if len(s) == 0 { // can be at end
break
}
}
}
// Must have used entire string.
if len(s) != 0 {
return nil
}
// If didn't parse enough, expand ellipsis.
if i < IPv6len {
if ellipsis < 0 {
return nil
}
n := IPv6len - i
for j := i - 1; j >= ellipsis; j-- {
ip[j+n] = ip[j]
}
for j := ellipsis + n - 1; j >= ellipsis; j-- {
ip[j] = 0
}
} else if ellipsis >= 0 {
// Ellipsis must represent at least one 0 group.
return nil
}
return ip
}
// ParseIP parses s as an IP address, returning the result. // ParseIP parses s as an IP address, returning the result.
// The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6 // The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6
// ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form. // ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form.
// If s is not a valid textual representation of an IP address, // If s is not a valid textual representation of an IP address,
// ParseIP returns nil. // ParseIP returns nil.
func ParseIP(s string) IP { func ParseIP(s string) IP {
for i := 0; i < len(s); i++ { if addr, valid := parseIP(s); valid {
switch s[i] { return IP(addr[:])
case '.':
return parseIPv4(s)
case ':':
return parseIPv6(s)
}
} }
return nil return nil
} }
// parseIPZone parses s as an IP address, return it and its associated zone func parseIP(s string) ([16]byte, bool) {
// identifier (IPv6 only). ip, err := netip.ParseAddr(s)
func parseIPZone(s string) (IP, string) { if err != nil || ip.Zone() != "" {
for i := 0; i < len(s); i++ { return [16]byte{}, false
switch s[i] {
case '.':
return parseIPv4(s), ""
case ':':
return parseIPv6Zone(s)
}
} }
return nil, "" return ip.As16(), true
} }
// ParseCIDR parses s as a CIDR notation IP address and prefix length, // ParseCIDR parses s as a CIDR notation IP address and prefix length,
@@ -746,16 +522,23 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
return nil, nil, &ParseError{Type: "CIDR address", Text: s} return nil, nil, &ParseError{Type: "CIDR address", Text: s}
} }
addr, mask := s[:i], s[i+1:] addr, mask := s[:i], s[i+1:]
iplen := IPv4len
ip := parseIPv4(addr) ipAddr, err := netip.ParseAddr(addr)
if ip == nil { if err != nil || ipAddr.Zone() != "" {
iplen = IPv6len
ip = parseIPv6(addr)
}
n, i, ok := dtoi(mask)
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
return nil, nil, &ParseError{Type: "CIDR address", Text: s} return nil, nil, &ParseError{Type: "CIDR address", Text: s}
} }
m := CIDRMask(n, 8*iplen)
return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil n, i, ok := dtoi(mask)
if !ok || i != len(mask) || n < 0 || n > ipAddr.BitLen() {
return nil, nil, &ParseError{Type: "CIDR address", Text: s}
}
m := CIDRMask(n, ipAddr.BitLen())
addr16 := ipAddr.As16()
return IP(addr16[:]), &IPNet{IP: IP(addr16[:]).Mask(m), Mask: m}, nil
}
func copyIP(x IP) IP {
y := make(IP, len(x))
copy(y, x)
return y
} }
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied from Go 1.20.5 official implementation. // TINYGO: The following is copied from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// The following is copied from Go 1.20.5 official implementation. // The following is copied from Go 1.21.4 official implementation.
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
+1 -1
View File
@@ -1,4 +1,4 @@
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation. // TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style