mirror of
https://github.com/tinygo-org/net.git
synced 2026-08-20 12:28:59 +00:00
update 'net' package from 1.19.3 to 1.20.5
This commit is contained in:
committed by
deadprogram
parent
d0c97a5292
commit
c3616d9365
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation.
|
||||||
|
|
||||||
// TINYGO: Omit DualStack support
|
// TINYGO: Omit DualStack support
|
||||||
// TINYGO: Omit Fast Fallback support
|
// TINYGO: Omit Fast Fallback support
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
|
||||||
|
|||||||
+88
-72
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
@@ -11,6 +11,7 @@ package http
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"internal/safefilepath"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"mime"
|
"mime"
|
||||||
@@ -71,14 +72,15 @@ func mapOpenError(originalErr error, name string, sep rune, stat func(string) (f
|
|||||||
// Open implements FileSystem using os.Open, opening files for reading rooted
|
// Open implements FileSystem using os.Open, opening files for reading rooted
|
||||||
// and relative to the directory d.
|
// and relative to the directory d.
|
||||||
func (d Dir) Open(name string) (File, error) {
|
func (d Dir) Open(name string) (File, error) {
|
||||||
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
|
path, err := safefilepath.FromFS(path.Clean("/" + name))
|
||||||
return nil, errors.New("http: invalid character in file path")
|
if err != nil {
|
||||||
|
return nil, errors.New("http: invalid or unsafe file path")
|
||||||
}
|
}
|
||||||
dir := string(d)
|
dir := string(d)
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
dir = "."
|
dir = "."
|
||||||
}
|
}
|
||||||
fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
|
fullName := filepath.Join(dir, path)
|
||||||
f, err := os.Open(fullName)
|
f, err := os.Open(fullName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mapOpenError(err, fullName, filepath.Separator, os.Stat)
|
return nil, mapOpenError(err, fullName, filepath.Separator, os.Stat)
|
||||||
@@ -256,81 +258,95 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
|
|||||||
Error(w, err.Error(), StatusInternalServerError)
|
Error(w, err.Error(), StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if size < 0 {
|
||||||
|
// Should never happen but just to be sure
|
||||||
|
Error(w, "negative content size computed", StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// handle Content-Range header.
|
// handle Content-Range header.
|
||||||
sendSize := size
|
sendSize := size
|
||||||
var sendContent io.Reader = content
|
var sendContent io.Reader = content
|
||||||
if size >= 0 {
|
ranges, err := parseRange(rangeReq, size)
|
||||||
ranges, err := parseRange(rangeReq, size)
|
switch err {
|
||||||
if err != nil {
|
case nil:
|
||||||
if err == errNoOverlap {
|
case errNoOverlap:
|
||||||
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size))
|
if size == 0 {
|
||||||
}
|
// Some clients add a Range header to all requests to
|
||||||
|
// limit the size of the response. If the file is empty,
|
||||||
|
// ignore the range header and respond with a 200 rather
|
||||||
|
// than a 416.
|
||||||
|
ranges = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size))
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if sumRangesSize(ranges) > size {
|
||||||
|
// The total number of bytes in all the ranges
|
||||||
|
// is larger than the size of the file by
|
||||||
|
// itself, so this is probably an attack, or a
|
||||||
|
// dumb client. Ignore the range request.
|
||||||
|
ranges = nil
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case len(ranges) == 1:
|
||||||
|
// RFC 7233, Section 4.1:
|
||||||
|
// "If a single part is being transferred, the server
|
||||||
|
// generating the 206 response MUST generate a
|
||||||
|
// Content-Range header field, describing what range
|
||||||
|
// of the selected representation is enclosed, and a
|
||||||
|
// payload consisting of the range.
|
||||||
|
// ...
|
||||||
|
// A server MUST NOT generate a multipart response to
|
||||||
|
// a request for a single range, since a client that
|
||||||
|
// does not request multiple parts might not support
|
||||||
|
// multipart responses."
|
||||||
|
ra := ranges[0]
|
||||||
|
if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
|
||||||
Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
|
Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if sumRangesSize(ranges) > size {
|
sendSize = ra.length
|
||||||
// The total number of bytes in all the ranges
|
code = StatusPartialContent
|
||||||
// is larger than the size of the file by
|
w.Header().Set("Content-Range", ra.contentRange(size))
|
||||||
// itself, so this is probably an attack, or a
|
case len(ranges) > 1:
|
||||||
// dumb client. Ignore the range request.
|
sendSize = rangesMIMESize(ranges, ctype, size)
|
||||||
ranges = nil
|
code = StatusPartialContent
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case len(ranges) == 1:
|
|
||||||
// RFC 7233, Section 4.1:
|
|
||||||
// "If a single part is being transferred, the server
|
|
||||||
// generating the 206 response MUST generate a
|
|
||||||
// Content-Range header field, describing what range
|
|
||||||
// of the selected representation is enclosed, and a
|
|
||||||
// payload consisting of the range.
|
|
||||||
// ...
|
|
||||||
// A server MUST NOT generate a multipart response to
|
|
||||||
// a request for a single range, since a client that
|
|
||||||
// does not request multiple parts might not support
|
|
||||||
// multipart responses."
|
|
||||||
ra := ranges[0]
|
|
||||||
if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
|
|
||||||
Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sendSize = ra.length
|
|
||||||
code = StatusPartialContent
|
|
||||||
w.Header().Set("Content-Range", ra.contentRange(size))
|
|
||||||
case len(ranges) > 1:
|
|
||||||
sendSize = rangesMIMESize(ranges, ctype, size)
|
|
||||||
code = StatusPartialContent
|
|
||||||
|
|
||||||
pr, pw := io.Pipe()
|
pr, pw := io.Pipe()
|
||||||
mw := multipart.NewWriter(pw)
|
mw := multipart.NewWriter(pw)
|
||||||
w.Header().Set("Content-Type", "multipart/byteranges; boundary="+mw.Boundary())
|
w.Header().Set("Content-Type", "multipart/byteranges; boundary="+mw.Boundary())
|
||||||
sendContent = pr
|
sendContent = pr
|
||||||
defer pr.Close() // cause writing goroutine to fail and exit if CopyN doesn't finish.
|
defer pr.Close() // cause writing goroutine to fail and exit if CopyN doesn't finish.
|
||||||
go func() {
|
go func() {
|
||||||
for _, ra := range ranges {
|
for _, ra := range ranges {
|
||||||
part, err := mw.CreatePart(ra.mimeHeader(ctype, size))
|
part, err := mw.CreatePart(ra.mimeHeader(ctype, size))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pw.CloseWithError(err)
|
pw.CloseWithError(err)
|
||||||
return
|
return
|
||||||
}
|
|
||||||
if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
|
|
||||||
pw.CloseWithError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := io.CopyN(part, content, ra.length); err != nil {
|
|
||||||
pw.CloseWithError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mw.Close()
|
if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
|
||||||
pw.Close()
|
pw.CloseWithError(err)
|
||||||
}()
|
return
|
||||||
}
|
}
|
||||||
|
if _, err := io.CopyN(part, content, ra.length); err != nil {
|
||||||
|
pw.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mw.Close()
|
||||||
|
pw.Close()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
w.Header().Set("Accept-Ranges", "bytes")
|
w.Header().Set("Accept-Ranges", "bytes")
|
||||||
if w.Header().Get("Content-Encoding") == "" {
|
if w.Header().Get("Content-Encoding") == "" {
|
||||||
w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10))
|
w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
@@ -433,7 +449,7 @@ func checkIfUnmodifiedSince(r *Request, modtime time.Time) condResult {
|
|||||||
// The Last-Modified header truncates sub-second precision so
|
// The Last-Modified header truncates sub-second precision so
|
||||||
// the modtime needs to be truncated too.
|
// the modtime needs to be truncated too.
|
||||||
modtime = modtime.Truncate(time.Second)
|
modtime = modtime.Truncate(time.Second)
|
||||||
if modtime.Before(t) || modtime.Equal(t) {
|
if ret := modtime.Compare(t); ret <= 0 {
|
||||||
return condTrue
|
return condTrue
|
||||||
}
|
}
|
||||||
return condFalse
|
return condFalse
|
||||||
@@ -484,7 +500,7 @@ func checkIfModifiedSince(r *Request, modtime time.Time) condResult {
|
|||||||
// The Last-Modified header truncates sub-second precision so
|
// The Last-Modified header truncates sub-second precision so
|
||||||
// the modtime needs to be truncated too.
|
// the modtime needs to be truncated too.
|
||||||
modtime = modtime.Truncate(time.Second)
|
modtime = modtime.Truncate(time.Second)
|
||||||
if modtime.Before(t) || modtime.Equal(t) {
|
if ret := modtime.Compare(t); ret <= 0 {
|
||||||
return condFalse
|
return condFalse
|
||||||
}
|
}
|
||||||
return condTrue
|
return condTrue
|
||||||
@@ -644,7 +660,6 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
|
|||||||
defer ff.Close()
|
defer ff.Close()
|
||||||
dd, err := ff.Stat()
|
dd, err := ff.Stat()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
name = index
|
|
||||||
d = dd
|
d = dd
|
||||||
f = ff
|
f = ff
|
||||||
}
|
}
|
||||||
@@ -820,6 +835,7 @@ func (f ioFile) Readdir(count int) ([]fs.FileInfo, error) {
|
|||||||
|
|
||||||
// FS converts fsys to a FileSystem implementation,
|
// FS converts fsys to a FileSystem implementation,
|
||||||
// for use with FileServer and NewFileTransport.
|
// for use with FileServer and NewFileTransport.
|
||||||
|
// The files provided by fsys must implement io.Seeker.
|
||||||
func FS(fsys fs.FS) FileSystem {
|
func FS(fsys fs.FS) FileSystem {
|
||||||
return ioFS{fsys}
|
return ioFS{fsys}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation.
|
||||||
|
|
||||||
// TINYGO: Removed trace stuff
|
// TINYGO: Removed trace stuff
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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,3 +1,5 @@
|
|||||||
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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,3 +1,5 @@
|
|||||||
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
|
|||||||
+17
-11
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 official implementation.
|
||||||
|
|
||||||
// TINYGO: Removed multipart stuff
|
// TINYGO: Removed multipart stuff
|
||||||
// TINYGO: Removed trace stuff
|
// TINYGO: Removed trace stuff
|
||||||
@@ -51,9 +51,12 @@ type ProtocolError struct {
|
|||||||
func (pe *ProtocolError) Error() string { return pe.ErrorString }
|
func (pe *ProtocolError) Error() string { return pe.ErrorString }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrNotSupported is returned by the Push method of Pusher
|
// ErrNotSupported indicates that a feature is not supported.
|
||||||
// implementations to indicate that HTTP/2 Push support is not
|
//
|
||||||
// available.
|
// It is returned by ResponseController methods to indicate that
|
||||||
|
// the handler does not support the method, and by the Push method
|
||||||
|
// of Pusher implementations to indicate that HTTP/2 Push support
|
||||||
|
// is not available.
|
||||||
ErrNotSupported = &ProtocolError{"feature not supported"}
|
ErrNotSupported = &ProtocolError{"feature not supported"}
|
||||||
|
|
||||||
// Deprecated: ErrUnexpectedTrailer is no longer returned by
|
// Deprecated: ErrUnexpectedTrailer is no longer returned by
|
||||||
@@ -319,7 +322,7 @@ type Request struct {
|
|||||||
Response *Response
|
Response *Response
|
||||||
|
|
||||||
// ctx is either the client or server context. It should only
|
// ctx is either the client or server context. It should only
|
||||||
// be modified via copying the whole Request using WithContext.
|
// be modified via copying the whole Request using Clone or WithContext.
|
||||||
// It is unexported to prevent people from using Context wrong
|
// It is unexported to prevent people from using Context wrong
|
||||||
// and mutating the contexts held by callers of the same request.
|
// and mutating the contexts held by callers of the same request.
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@@ -330,7 +333,7 @@ type Request struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Context returns the request's context. To change the context, use
|
// Context returns the request's context. To change the context, use
|
||||||
// WithContext.
|
// Clone or WithContext.
|
||||||
//
|
//
|
||||||
// The returned context is always non-nil; it defaults to the
|
// The returned context is always non-nil; it defaults to the
|
||||||
// background context.
|
// background context.
|
||||||
@@ -355,9 +358,7 @@ func (r *Request) Context() context.Context {
|
|||||||
// sending the request, and reading the response headers and body.
|
// sending the request, and reading the response headers and body.
|
||||||
//
|
//
|
||||||
// To create a new request with a context, use NewRequestWithContext.
|
// To create a new request with a context, use NewRequestWithContext.
|
||||||
// To change the context of a request, such as an incoming request you
|
// To make a deep copy of a request with a new context, use Request.Clone.
|
||||||
// want to modify before sending back out, use Request.Clone. Between
|
|
||||||
// those two uses, it's rare to need WithContext.
|
|
||||||
func (r *Request) WithContext(ctx context.Context) *Request {
|
func (r *Request) WithContext(ctx context.Context) *Request {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
panic("nil context")
|
panic("nil context")
|
||||||
@@ -424,6 +425,9 @@ var ErrNoCookie = errors.New("http: named cookie not present")
|
|||||||
// If multiple cookies match the given name, only one cookie will
|
// If multiple cookies match the given name, only one cookie will
|
||||||
// be returned.
|
// be returned.
|
||||||
func (r *Request) Cookie(name string) (*Cookie, error) {
|
func (r *Request) Cookie(name string) (*Cookie, error) {
|
||||||
|
if name == "" {
|
||||||
|
return nil, ErrNoCookie
|
||||||
|
}
|
||||||
for _, c := range readCookies(r.Header, name) {
|
for _, c := range readCookies(r.Header, name) {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
@@ -993,6 +997,8 @@ func ReadRequest(b *bufio.Reader) (*Request, error) {
|
|||||||
|
|
||||||
func readRequest(b *bufio.Reader) (req *Request, err error) {
|
func readRequest(b *bufio.Reader) (req *Request, err error) {
|
||||||
tp := newTextprotoReader(b)
|
tp := newTextprotoReader(b)
|
||||||
|
defer putTextprotoReader(tp)
|
||||||
|
|
||||||
req = new(Request)
|
req = new(Request)
|
||||||
|
|
||||||
// First line: GET /index.html HTTP/1.0
|
// First line: GET /index.html HTTP/1.0
|
||||||
@@ -1001,7 +1007,6 @@ func readRequest(b *bufio.Reader) (req *Request, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
putTextprotoReader(tp)
|
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
err = io.ErrUnexpectedEOF
|
err = io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
@@ -1132,7 +1137,8 @@ func (l *maxBytesReader) Read(p []byte) (n int, err error) {
|
|||||||
// If they asked for a 32KB byte read but only 5 bytes are
|
// If they asked for a 32KB byte read but only 5 bytes are
|
||||||
// remaining, no need to read 32KB. 6 bytes will answer the
|
// remaining, no need to read 32KB. 6 bytes will answer the
|
||||||
// question of the whether we hit the limit or go past it.
|
// question of the whether we hit the limit or go past it.
|
||||||
if int64(len(p)) > l.n+1 {
|
// 0 < len(p) < 2^63
|
||||||
|
if int64(len(p))-1 > l.n {
|
||||||
p = p[:l.n+1]
|
p = p[:l.n+1]
|
||||||
}
|
}
|
||||||
n, err = l.r.Read(p)
|
n, err = l.r.Read(p)
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
|
||||||
|
|||||||
+50
-52
@@ -1,4 +1,8 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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,
|
||||||
|
// then these can be converted to atomic.Pointer and atomic.Uint64.
|
||||||
|
|
||||||
// TINYGO: Removed ALPN protocol support
|
// TINYGO: Removed ALPN protocol support
|
||||||
// TINYGO: Removed some HTTP/2 support
|
// TINYGO: Removed some HTTP/2 support
|
||||||
@@ -400,11 +404,11 @@ func (cw *chunkWriter) Write(p []byte) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cw *chunkWriter) flush() {
|
func (cw *chunkWriter) flush() error {
|
||||||
if !cw.wroteHeader {
|
if !cw.wroteHeader {
|
||||||
cw.writeHeader(nil)
|
cw.writeHeader(nil)
|
||||||
}
|
}
|
||||||
cw.res.conn.bufw.Flush()
|
return cw.res.conn.bufw.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cw *chunkWriter) close() {
|
func (cw *chunkWriter) close() {
|
||||||
@@ -435,9 +439,9 @@ type response struct {
|
|||||||
wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
|
wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
|
||||||
wantsClose bool // HTTP request has Connection "close"
|
wantsClose bool // HTTP request has Connection "close"
|
||||||
|
|
||||||
// canWriteContinue is a boolean value accessed as an atomic int32
|
// canWriteContinue is an atomic boolean that says whether or
|
||||||
// that says whether or not a 100 Continue header can be written
|
// not a 100 Continue header can be written to the
|
||||||
// to the connection.
|
// connection.
|
||||||
// writeContinueMu must be held while writing the header.
|
// writeContinueMu must be held while writing the header.
|
||||||
// These two fields together synchronize the body reader (the
|
// These two fields together synchronize the body reader (the
|
||||||
// expectContinueReader, which wants to write 100 Continue)
|
// expectContinueReader, which wants to write 100 Continue)
|
||||||
@@ -494,6 +498,14 @@ type response struct {
|
|||||||
didCloseNotify int32 // atomic (only 0->1 winner should send)
|
didCloseNotify int32 // atomic (only 0->1 winner should send)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *response) SetReadDeadline(deadline time.Time) error {
|
||||||
|
return c.conn.rwc.SetReadDeadline(deadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *response) SetWriteDeadline(deadline time.Time) error {
|
||||||
|
return c.conn.rwc.SetWriteDeadline(deadline)
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -514,11 +526,11 @@ const TrailerPrefix = "Trailer:"
|
|||||||
func (w *response) finalTrailers() Header {
|
func (w *response) finalTrailers() Header {
|
||||||
var t Header
|
var t Header
|
||||||
for k, vv := range w.handlerHeader {
|
for k, vv := range w.handlerHeader {
|
||||||
if strings.HasPrefix(k, TrailerPrefix) {
|
if kk, found := strings.CutPrefix(k, TrailerPrefix); found {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
t = make(Header)
|
t = make(Header)
|
||||||
}
|
}
|
||||||
t[strings.TrimPrefix(k, TrailerPrefix)] = vv
|
t[kk] = vv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, k := range w.trailers {
|
for _, k := range w.trailers {
|
||||||
@@ -560,12 +572,6 @@ func (w *response) requestTooLarge() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// needsSniff reports whether a Content-Type still needs to be sniffed.
|
|
||||||
func (w *response) needsSniff() bool {
|
|
||||||
_, haveType := w.handlerHeader["Content-Type"]
|
|
||||||
return !w.cw.wroteHeader && !haveType && w.written < sniffLen
|
|
||||||
}
|
|
||||||
|
|
||||||
// writerOnly hides an io.Writer value's optional ReadFrom method
|
// writerOnly hides an io.Writer value's optional ReadFrom method
|
||||||
// from io.Copy.
|
// from io.Copy.
|
||||||
type writerOnly struct {
|
type writerOnly struct {
|
||||||
@@ -754,8 +760,8 @@ func (cr *connReader) handleReadError(_ error) {
|
|||||||
|
|
||||||
// may be called from multiple goroutines.
|
// may be called from multiple goroutines.
|
||||||
func (cr *connReader) closeNotify() {
|
func (cr *connReader) closeNotify() {
|
||||||
res, _ := cr.conn.curReq.Load().(*response)
|
res := cr.conn.curReq.Load()
|
||||||
if res != nil && atomic.CompareAndSwapInt32(&res.didCloseNotify, 0, 1) {
|
if res != nil && !res.didCloseNotify.Swap(true) {
|
||||||
res.closeNotifyCh <- true
|
res.closeNotifyCh <- true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1706,11 +1712,19 @@ func (w *response) closedRequestBodyEarly() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *response) Flush() {
|
func (w *response) Flush() {
|
||||||
|
w.FlushError()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *response) FlushError() error {
|
||||||
if !w.wroteHeader {
|
if !w.wroteHeader {
|
||||||
w.WriteHeader(StatusOK)
|
w.WriteHeader(StatusOK)
|
||||||
}
|
}
|
||||||
w.w.Flush()
|
err := w.w.Flush()
|
||||||
w.cw.flush()
|
e2 := w.cw.flush()
|
||||||
|
if err == nil {
|
||||||
|
err = e2
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) finalFlush() {
|
func (c *conn) finalFlush() {
|
||||||
@@ -1964,6 +1978,7 @@ func (c *conn) serve(ctx context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.finishRequest()
|
w.finishRequest()
|
||||||
|
c.rwc.SetWriteDeadline(time.Time{})
|
||||||
if !w.shouldReuseConnection() {
|
if !w.shouldReuseConnection() {
|
||||||
if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
|
if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
|
||||||
c.closeWriteAndWait()
|
c.closeWriteAndWait()
|
||||||
@@ -1983,10 +1998,18 @@ func (c *conn) serve(ctx context.Context) {
|
|||||||
|
|
||||||
if d := c.server.idleTimeout(); d != 0 {
|
if d := c.server.idleTimeout(); d != 0 {
|
||||||
c.rwc.SetReadDeadline(time.Now().Add(d))
|
c.rwc.SetReadDeadline(time.Now().Add(d))
|
||||||
if _, err := c.bufr.Peek(4); err != nil {
|
} else {
|
||||||
return
|
c.rwc.SetReadDeadline(time.Time{})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the connection to become readable again before trying to
|
||||||
|
// read the next request. This prevents a ReadHeaderTimeout or
|
||||||
|
// ReadTimeout from starting until the first bytes of the next request
|
||||||
|
// have been received.
|
||||||
|
if _, err := c.bufr.Peek(4); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.rwc.SetReadDeadline(time.Time{})
|
c.rwc.SetReadDeadline(time.Time{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2548,6 +2571,10 @@ type Server struct {
|
|||||||
|
|
||||||
Handler Handler // handler to invoke, http.DefaultServeMux if nil
|
Handler Handler // handler to invoke, http.DefaultServeMux if nil
|
||||||
|
|
||||||
|
// DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler,
|
||||||
|
// otherwise responds with 200 OK and Content-Length: 0.
|
||||||
|
DisableGeneralOptionsHandler bool
|
||||||
|
|
||||||
// TLSConfig optionally provides a TLS configuration for use
|
// TLSConfig optionally provides a TLS configuration for use
|
||||||
// by ServeTLS and ListenAndServeTLS. Note that this value is
|
// by ServeTLS and ListenAndServeTLS. Note that this value is
|
||||||
// cloned by ServeTLS and ListenAndServeTLS, so it's not
|
// cloned by ServeTLS and ListenAndServeTLS, so it's not
|
||||||
@@ -2629,37 +2656,11 @@ type Server struct {
|
|||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
listeners map[*net.Listener]struct{}
|
listeners map[*net.Listener]struct{}
|
||||||
activeConn map[*conn]struct{}
|
activeConn map[*conn]struct{}
|
||||||
doneChan chan struct{}
|
|
||||||
onShutdown []func()
|
onShutdown []func()
|
||||||
|
|
||||||
listenerGroup sync.WaitGroup
|
listenerGroup sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getDoneChan() <-chan struct{} {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
return s.getDoneChanLocked()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) getDoneChanLocked() chan struct{} {
|
|
||||||
if s.doneChan == nil {
|
|
||||||
s.doneChan = make(chan struct{})
|
|
||||||
}
|
|
||||||
return s.doneChan
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) closeDoneChanLocked() {
|
|
||||||
ch := s.getDoneChanLocked()
|
|
||||||
select {
|
|
||||||
case <-ch:
|
|
||||||
// Already closed. Don't close again.
|
|
||||||
default:
|
|
||||||
// Safe to close here. We're the only closer, guarded
|
|
||||||
// by s.mu.
|
|
||||||
close(ch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close immediately closes all active net.Listeners and any
|
// Close immediately closes all active net.Listeners and any
|
||||||
// connections in state StateNew, StateActive, or StateIdle. For a
|
// connections in state StateNew, StateActive, or StateIdle. For a
|
||||||
// graceful shutdown, use Shutdown.
|
// graceful shutdown, use Shutdown.
|
||||||
@@ -2725,7 +2726,6 @@ func (srv *Server) Shutdown(ctx context.Context) error {
|
|||||||
|
|
||||||
srv.mu.Lock()
|
srv.mu.Lock()
|
||||||
lnerr := srv.closeListenersLocked()
|
lnerr := srv.closeListenersLocked()
|
||||||
srv.closeDoneChanLocked()
|
|
||||||
for _, f := range srv.onShutdown {
|
for _, f := range srv.onShutdown {
|
||||||
go f()
|
go f()
|
||||||
}
|
}
|
||||||
@@ -2869,7 +2869,7 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
|
|||||||
if handler == nil {
|
if handler == nil {
|
||||||
handler = DefaultServeMux
|
handler = DefaultServeMux
|
||||||
}
|
}
|
||||||
if req.RequestURI == "*" && req.Method == "OPTIONS" {
|
if !sh.srv.DisableGeneralOptionsHandler && req.RequestURI == "*" && req.Method == "OPTIONS" {
|
||||||
handler = globalOptionsHandler{}
|
handler = globalOptionsHandler{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2984,10 +2984,8 @@ func (srv *Server) Serve(l net.Listener) error {
|
|||||||
for {
|
for {
|
||||||
rw, err := l.Accept()
|
rw, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
if srv.shuttingDown() {
|
||||||
case <-srv.getDoneChan():
|
|
||||||
return ErrServerClosed
|
return ErrServerClosed
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
if ne, ok := err.(net.Error); ok && ne.Temporary() {
|
if ne, ok := err.(net.Error); ok && ne.Temporary() {
|
||||||
if tempDelay == 0 {
|
if tempDelay == 0 {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
|
|||||||
+4
-11
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
|
||||||
@@ -553,7 +553,7 @@ func readTransfer(msg any, r *bufio.Reader, onEOF func()) (err error) {
|
|||||||
// or close connection when finished, since multipart is not supported yet
|
// or close connection when finished, since multipart is not supported yet
|
||||||
switch {
|
switch {
|
||||||
case t.Chunked:
|
case t.Chunked:
|
||||||
if noResponseBodyExpected(t.RequestMethod) || !bodyAllowedForStatus(t.StatusCode) {
|
if isResponse && (noResponseBodyExpected(t.RequestMethod) || !bodyAllowedForStatus(t.StatusCode)) {
|
||||||
t.Body = NoBody
|
t.Body = NoBody
|
||||||
} else {
|
} else {
|
||||||
t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close, onHitEOF: onEOF}
|
t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close, onHitEOF: onEOF}
|
||||||
@@ -596,7 +596,7 @@ func readTransfer(msg any, r *bufio.Reader, onEOF func()) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether chunked is part of the encodings stack
|
// Checks whether chunked is part of the encodings stack.
|
||||||
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
|
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
|
||||||
|
|
||||||
// Checks whether the encoding is explicitly "identity".
|
// Checks whether the encoding is explicitly "identity".
|
||||||
@@ -687,14 +687,7 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Logic based on response type or status
|
// Logic based on response type or status
|
||||||
if noResponseBodyExpected(requestMethod) {
|
if isResponse && noResponseBodyExpected(requestMethod) {
|
||||||
// For HTTP requests, as part of hardening against request
|
|
||||||
// smuggling (RFC 7230), don't allow a Content-Length header for
|
|
||||||
// methods which don't permit bodies. As an exception, allow
|
|
||||||
// exactly one Content-Length header if its value is "0".
|
|
||||||
if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") {
|
|
||||||
return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens)
|
|
||||||
}
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
if status/100 == 1 {
|
if status/100 == 1 {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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,3 +1,5 @@
|
|||||||
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied from Go 1.20.5 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
|
||||||
@@ -238,7 +238,7 @@ func lowerASCII(b byte) byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// trimSpace returns x without any leading or trailing ASCII whitespace.
|
// trimSpace returns x without any leading or trailing ASCII whitespace.
|
||||||
func trimSpace(x []byte) []byte {
|
func trimSpace(x string) string {
|
||||||
for len(x) > 0 && isSpace(x[0]) {
|
for len(x) > 0 && isSpace(x[0]) {
|
||||||
x = x[1:]
|
x = x[1:]
|
||||||
}
|
}
|
||||||
@@ -255,37 +255,19 @@ func isSpace(b byte) bool {
|
|||||||
|
|
||||||
// removeComment returns line, removing any '#' byte and any following
|
// removeComment returns line, removing any '#' byte and any following
|
||||||
// bytes.
|
// bytes.
|
||||||
func removeComment(line []byte) []byte {
|
func removeComment(line string) string {
|
||||||
if i := bytealg.IndexByte(line, '#'); i != -1 {
|
if i := bytealg.IndexByteString(line, '#'); i != -1 {
|
||||||
return line[:i]
|
return line[:i]
|
||||||
}
|
}
|
||||||
return line
|
return line
|
||||||
}
|
}
|
||||||
|
|
||||||
// foreachLine runs fn on each line of x.
|
|
||||||
// Each line (except for possibly the last) ends in '\n'.
|
|
||||||
// It returns the first non-nil error returned by fn.
|
|
||||||
func foreachLine(x []byte, fn func(line []byte) error) error {
|
|
||||||
for len(x) > 0 {
|
|
||||||
nl := bytealg.IndexByte(x, '\n')
|
|
||||||
if nl == -1 {
|
|
||||||
return fn(x)
|
|
||||||
}
|
|
||||||
line := x[:nl+1]
|
|
||||||
x = x[nl+1:]
|
|
||||||
if err := fn(line); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// foreachField runs fn on each non-empty run of non-space bytes in x.
|
// foreachField runs fn on each non-empty run of non-space bytes in x.
|
||||||
// It returns the first non-nil error returned by fn.
|
// It returns the first non-nil error returned by fn.
|
||||||
func foreachField(x []byte, fn func(field []byte) error) error {
|
func foreachField(x string, fn func(field string) error) error {
|
||||||
x = trimSpace(x)
|
x = trimSpace(x)
|
||||||
for len(x) > 0 {
|
for len(x) > 0 {
|
||||||
sp := bytealg.IndexByte(x, ' ')
|
sp := bytealg.IndexByteString(x, ' ')
|
||||||
if sp == -1 {
|
if sp == -1 {
|
||||||
return fn(x)
|
return fn(x)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// The following is copied from Go 1.19.3 official implementation.
|
// The following is copied from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
@@ -1,4 +1,4 @@
|
|||||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
// TINYGO: The following is copied and modified from Go 1.20.5 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
|
||||||
|
|||||||
Reference in New Issue
Block a user