mirror of
https://github.com/tinygo-org/net.git
synced 2026-07-26 08:18:39 +00:00
update with changes from go1.20.5 to go1.21.4
This commit is contained in:
committed by
deadprogram
parent
be25e1a28e
commit
7c11b88ce6
@@ -19,7 +19,7 @@ packages in a TinyGo application.
|
||||
|
||||
## "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
|
||||
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.
|
||||
|
||||
@@ -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 Fast Fallback support
|
||||
// TINYGO: Don't allow alternate resolver
|
||||
// TINYGO: Omit DialTimeout
|
||||
// TINYGO: Omit Multipath TCP
|
||||
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
@@ -17,9 +18,9 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
|
||||
// See golang.org/issue/31510
|
||||
const (
|
||||
// defaultTCPKeepAlive is a default constant value for TCPKeepAlive times
|
||||
// See go.dev/issue/31510
|
||||
defaultTCPKeepAlive = 15 * time.Second
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
+9
-3
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
@@ -88,14 +88,20 @@ func hexEscapeNonASCII(s string) string {
|
||||
return s
|
||||
}
|
||||
b := make([]byte, 0, newLen)
|
||||
var pos int
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] >= utf8.RuneSelf {
|
||||
if pos < i {
|
||||
b = append(b, s[pos:i]...)
|
||||
}
|
||||
b = append(b, '%')
|
||||
b = strconv.AppendInt(b, int64(s[i]), 16)
|
||||
} else {
|
||||
b = append(b, s[i])
|
||||
pos = i + 1
|
||||
}
|
||||
}
|
||||
if pos < len(s) {
|
||||
b = append(b, s[pos:]...)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+38
-33
@@ -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 trace stuff
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http/internal/ascii"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
@@ -30,6 +29,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,6 +51,11 @@ type ProtocolError struct {
|
||||
|
||||
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 (
|
||||
// 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.
|
||||
//
|
||||
// Clean the host, in case it arrives with unexpected stuff in it.
|
||||
host := cleanHost(r.Host)
|
||||
host := r.Host
|
||||
if host == "" {
|
||||
if r.URL == nil {
|
||||
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
|
||||
@@ -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.
|
||||
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.
|
||||
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
|
||||
func removeZone(host string) string {
|
||||
|
||||
+1
-1
@@ -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: Added onEOF hook to get callback when response has been read
|
||||
|
||||
+29
-32
@@ -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
|
||||
// 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.
|
||||
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
|
||||
// maxBytesReader hits its max size. It is checked in
|
||||
// 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)
|
||||
}
|
||||
|
||||
func (c *response) EnableFullDuplex() error {
|
||||
c.fullDuplex = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
|
||||
// that, if present, signals that the map entry is actually for
|
||||
// the response trailers, and not the response headers. The prefix
|
||||
@@ -1162,8 +1171,11 @@ func (w *response) WriteHeader(code int) {
|
||||
}
|
||||
checkWriteHeaderCode(code)
|
||||
|
||||
// Handle informational headers
|
||||
if code >= 100 && code <= 199 {
|
||||
// Handle informational headers.
|
||||
//
|
||||
// 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()
|
||||
if code == 100 && w.canWriteContinue.isSet() {
|
||||
w.writeContinueMu.Lock()
|
||||
@@ -1325,7 +1337,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
||||
// send a Content-Length header.
|
||||
// Further, we don't send an automatic Content-Length if they
|
||||
// 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))
|
||||
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
|
||||
}
|
||||
|
||||
// Per RFC 2616, we should consume the request body before
|
||||
// replying, if the handler hasn't already done so. But we
|
||||
// don't want to do an unbounded amount of reading here for
|
||||
// DoS reasons, so we only try up to a threshold.
|
||||
// TODO(bradfitz): where does RFC 2616 say that? See Issue 15527
|
||||
// about HTTP/1.x Handlers concurrently reading and writing, like
|
||||
// HTTP/2 handlers can do. Maybe this code should be relaxed?
|
||||
if w.req.ContentLength != 0 && !w.closeAfterReply {
|
||||
// We do this by default because there are a number of clients that
|
||||
// send a full request before starting to read the response, and they
|
||||
// can deadlock if we start writing the response with unconsumed body
|
||||
// remaining. See Issue 15527 for some history.
|
||||
//
|
||||
// If full duplex mode has been enabled with ResponseController.EnableFullDuplex,
|
||||
// then leave the request body alone.
|
||||
if w.req.ContentLength != 0 && !w.closeAfterReply && !w.fullDuplex {
|
||||
var discard, tooBig bool
|
||||
|
||||
switch bdy := w.req.Body.(type) {
|
||||
@@ -1766,7 +1778,7 @@ type closeWriter interface {
|
||||
|
||||
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
|
||||
// pause for a bit, hoping the client processes it before any
|
||||
// subsequent RST.
|
||||
@@ -1861,7 +1873,9 @@ func isCommonNetReadError(err error) bool {
|
||||
|
||||
// Serve a new connection.
|
||||
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())
|
||||
var inFlightResponse *response
|
||||
defer func() {
|
||||
@@ -2258,7 +2272,7 @@ func RedirectHandler(url string, code int) Handler {
|
||||
// Longer patterns take precedence over shorter ones, so that
|
||||
// if there are handlers registered for both "/images/"
|
||||
// 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
|
||||
// "/images/" subtree.
|
||||
//
|
||||
@@ -2873,23 +2887,9 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
|
||||
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)
|
||||
}
|
||||
|
||||
var silenceSemWarnContextKey = &contextKey{"silence-semicolons"}
|
||||
|
||||
// AllowQuerySemicolons returns a handler that serves requests by converting any
|
||||
// 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.
|
||||
func AllowQuerySemicolons(h Handler) Handler {
|
||||
return HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
if silenceSemicolonsWarning, ok := r.Context().Value(silenceSemWarnContextKey).(func()); ok {
|
||||
silenceSemicolonsWarning()
|
||||
}
|
||||
if strings.Contains(r.URL.RawQuery, ";") {
|
||||
r2 := new(Request)
|
||||
*r2 = *r
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+2
-2
@@ -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: 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
|
||||
}
|
||||
|
||||
// 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
|
||||
// files (*os.File types) are properly optimized.
|
||||
//
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
@@ -17,6 +17,7 @@ package net
|
||||
import (
|
||||
"internal/bytealg"
|
||||
"internal/itoa"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
// IP address lengths (bytes).
|
||||
@@ -287,25 +288,6 @@ func (ip IP) Mask(mask IPMask) IP {
|
||||
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.
|
||||
// It returns one of 4 forms:
|
||||
// - "<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
|
||||
// - the hexadecimal form of ip, without punctuation, if no other cases apply
|
||||
func (ip IP) String() string {
|
||||
p := ip
|
||||
|
||||
if len(ip) == 0 {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
// If IPv4, use dotted notation.
|
||||
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 {
|
||||
if len(ip) != IPv4len && len(ip) != IPv6len {
|
||||
return "?" + hexString(ip)
|
||||
}
|
||||
|
||||
// Find longest run of zeros.
|
||||
e0 := -1
|
||||
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
|
||||
}
|
||||
// If IPv4, use dotted notation.
|
||||
if p4 := ip.To4(); len(p4) == IPv4len {
|
||||
return netip.AddrFrom4([4]byte(p4)).String()
|
||||
}
|
||||
// The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
|
||||
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)
|
||||
return netip.AddrFrom16([16]byte(ip)).String()
|
||||
}
|
||||
|
||||
func hexString(b []byte) string {
|
||||
@@ -561,175 +488,24 @@ func (n *IPNet) String() string {
|
||||
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.
|
||||
// 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.
|
||||
// If s is not a valid textual representation of an IP address,
|
||||
// ParseIP returns nil.
|
||||
func ParseIP(s string) IP {
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '.':
|
||||
return parseIPv4(s)
|
||||
case ':':
|
||||
return parseIPv6(s)
|
||||
}
|
||||
if addr, valid := parseIP(s); valid {
|
||||
return IP(addr[:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseIPZone parses s as an IP address, return it and its associated zone
|
||||
// identifier (IPv6 only).
|
||||
func parseIPZone(s string) (IP, string) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '.':
|
||||
return parseIPv4(s), ""
|
||||
case ':':
|
||||
return parseIPv6Zone(s)
|
||||
}
|
||||
func parseIP(s string) ([16]byte, bool) {
|
||||
ip, err := netip.ParseAddr(s)
|
||||
if err != nil || ip.Zone() != "" {
|
||||
return [16]byte{}, false
|
||||
}
|
||||
return nil, ""
|
||||
return ip.As16(), true
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
addr, mask := s[:i], s[i+1:]
|
||||
iplen := IPv4len
|
||||
ip := parseIPv4(addr)
|
||||
if ip == nil {
|
||||
iplen = IPv6len
|
||||
ip = parseIPv6(addr)
|
||||
}
|
||||
n, i, ok := dtoi(mask)
|
||||
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
|
||||
|
||||
ipAddr, err := netip.ParseAddr(addr)
|
||||
if err != nil || ipAddr.Zone() != "" {
|
||||
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
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
+1
-1
@@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
Reference in New Issue
Block a user