aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-07-30 14:28:58 -0700
committerIan Lance Taylor <iant@golang.org>2021-08-12 20:23:07 -0700
commitc5b21c3f4c17b0649155035d2f9aa97b2da8a813 (patch)
treec6d3a68b503ba5b16182acbb958e3e5dbc95a43b /libgo/go/net
parent72be20e20299ec57b4bc9ba03d5b7d6bf10e97cc (diff)
downloadgcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.zip
gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.tar.gz
gcc-c5b21c3f4c17b0649155035d2f9aa97b2da8a813.tar.bz2
libgo: update to Go1.17rc2
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/341629
Diffstat (limited to 'libgo/go/net')
-rw-r--r--libgo/go/net/addrselect.go1
-rw-r--r--libgo/go/net/addrselect_test.go1
-rw-r--r--libgo/go/net/cgo_aix.go1
-rw-r--r--libgo/go/net/cgo_android.go1
-rw-r--r--libgo/go/net/cgo_bsd.go4
-rw-r--r--libgo/go/net/cgo_linux.go1
-rw-r--r--libgo/go/net/cgo_netbsd.go1
-rw-r--r--libgo/go/net/cgo_openbsd.go1
-rw-r--r--libgo/go/net/cgo_resnew.go4
-rw-r--r--libgo/go/net/cgo_resold.go4
-rw-r--r--libgo/go/net/cgo_socknew.go4
-rw-r--r--libgo/go/net/cgo_sockold.go4
-rw-r--r--libgo/go/net/cgo_solaris.go1
-rw-r--r--libgo/go/net/cgo_stub.go1
-rw-r--r--libgo/go/net/cgo_unix.go4
-rw-r--r--libgo/go/net/cgo_unix_test.go4
-rw-r--r--libgo/go/net/cgo_windows.go1
-rw-r--r--libgo/go/net/conf.go1
-rw-r--r--libgo/go/net/conf_netcgo.go1
-rw-r--r--libgo/go/net/conf_test.go1
-rw-r--r--libgo/go/net/conn_test.go1
-rw-r--r--libgo/go/net/dial.go9
-rw-r--r--libgo/go/net/dial_test.go62
-rw-r--r--libgo/go/net/dial_unix_test.go1
-rw-r--r--libgo/go/net/dnsclient.go3
-rw-r--r--libgo/go/net/dnsclient_unix.go22
-rw-r--r--libgo/go/net/dnsclient_unix_test.go259
-rw-r--r--libgo/go/net/dnsconfig_unix.go1
-rw-r--r--libgo/go/net/dnsconfig_unix_test.go1
-rw-r--r--libgo/go/net/dnsname_test.go1
-rw-r--r--libgo/go/net/error_posix.go1
-rw-r--r--libgo/go/net/error_posix_test.go1
-rw-r--r--libgo/go/net/error_test.go1
-rw-r--r--libgo/go/net/error_unix.go1
-rw-r--r--libgo/go/net/error_unix_test.go1
-rw-r--r--libgo/go/net/external_test.go1
-rw-r--r--libgo/go/net/fcntl_libc_test.go27
-rw-r--r--libgo/go/net/fcntl_syscall_test.go27
-rw-r--r--libgo/go/net/fd_posix.go7
-rw-r--r--libgo/go/net/fd_unix.go1
-rw-r--r--libgo/go/net/file_stub.go1
-rw-r--r--libgo/go/net/file_test.go1
-rw-r--r--libgo/go/net/file_unix.go1
-rw-r--r--libgo/go/net/hook_unix.go1
-rw-r--r--libgo/go/net/hosts_test.go4
-rw-r--r--libgo/go/net/http/cgi/integration_test.go29
-rw-r--r--libgo/go/net/http/cgi/posix_test.go1
-rw-r--r--libgo/go/net/http/client.go39
-rw-r--r--libgo/go/net/http/client_test.go8
-rw-r--r--libgo/go/net/http/cookie.go13
-rw-r--r--libgo/go/net/http/cookiejar/jar.go17
-rw-r--r--libgo/go/net/http/cookiejar/punycode.go14
-rw-r--r--libgo/go/net/http/example_test.go7
-rw-r--r--libgo/go/net/http/fcgi/child.go20
-rw-r--r--libgo/go/net/http/fcgi/fcgi_test.go53
-rw-r--r--libgo/go/net/http/filetransport_test.go6
-rw-r--r--libgo/go/net/http/fs.go6
-rw-r--r--libgo/go/net/http/fs_test.go19
-rw-r--r--libgo/go/net/http/h2_bundle.go271
-rw-r--r--libgo/go/net/http/header.go3
-rw-r--r--libgo/go/net/http/http.go9
-rw-r--r--libgo/go/net/http/http_test.go62
-rw-r--r--libgo/go/net/http/httptest/recorder.go19
-rw-r--r--libgo/go/net/http/httptest/recorder_test.go25
-rw-r--r--libgo/go/net/http/httptest/server.go11
-rw-r--r--libgo/go/net/http/httptrace/trace.go2
-rw-r--r--libgo/go/net/http/httputil/dump_test.go2
-rw-r--r--libgo/go/net/http/httputil/reverseproxy.go23
-rw-r--r--libgo/go/net/http/httputil/reverseproxy_test.go46
-rw-r--r--libgo/go/net/http/internal/ascii/print.go61
-rw-r--r--libgo/go/net/http/internal/ascii/print_test.go95
-rw-r--r--libgo/go/net/http/internal/testcert/testcert.go (renamed from libgo/go/net/http/internal/testcert.go)5
-rw-r--r--libgo/go/net/http/omithttp2.go1
-rw-r--r--libgo/go/net/http/pprof/pprof.go4
-rw-r--r--libgo/go/net/http/request.go49
-rw-r--r--libgo/go/net/http/request_test.go144
-rw-r--r--libgo/go/net/http/roundtrip.go1
-rw-r--r--libgo/go/net/http/roundtrip_js.go1
-rw-r--r--libgo/go/net/http/serve_test.go108
-rw-r--r--libgo/go/net/http/server.go120
-rw-r--r--libgo/go/net/http/sniff_test.go122
-rw-r--r--libgo/go/net/http/transfer.go3
-rw-r--r--libgo/go/net/http/transport.go24
-rw-r--r--libgo/go/net/http/transport_internal_test.go4
-rw-r--r--libgo/go/net/http/transport_test.go20
-rw-r--r--libgo/go/net/http/triv.go1
-rw-r--r--libgo/go/net/interface.go3
-rw-r--r--libgo/go/net/interface_bsd.go1
-rw-r--r--libgo/go/net/interface_bsd_test.go1
-rw-r--r--libgo/go/net/interface_bsdvar.go1
-rw-r--r--libgo/go/net/interface_freebsd.go6
-rw-r--r--libgo/go/net/interface_plan9.go5
-rw-r--r--libgo/go/net/interface_stub.go1
-rw-r--r--libgo/go/net/interface_test.go1
-rw-r--r--libgo/go/net/interface_unix_test.go1
-rw-r--r--libgo/go/net/internal/socktest/main_test.go1
-rw-r--r--libgo/go/net/internal/socktest/main_unix_test.go1
-rw-r--r--libgo/go/net/internal/socktest/switch_posix.go1
-rw-r--r--libgo/go/net/internal/socktest/switch_stub.go1
-rw-r--r--libgo/go/net/internal/socktest/switch_unix.go1
-rw-r--r--libgo/go/net/internal/socktest/sys_cloexec.go1
-rw-r--r--libgo/go/net/internal/socktest/sys_unix.go1
-rw-r--r--libgo/go/net/ip.go30
-rw-r--r--libgo/go/net/ip_test.go31
-rw-r--r--libgo/go/net/iprawsock_posix.go3
-rw-r--r--libgo/go/net/iprawsock_test.go1
-rw-r--r--libgo/go/net/ipsock.go8
-rw-r--r--libgo/go/net/ipsock_plan9.go7
-rw-r--r--libgo/go/net/ipsock_posix.go5
-rw-r--r--libgo/go/net/listen_test.go1
-rw-r--r--libgo/go/net/lookup.go99
-rw-r--r--libgo/go/net/lookup_fake.go1
-rw-r--r--libgo/go/net/lookup_plan9.go5
-rw-r--r--libgo/go/net/lookup_test.go1
-rw-r--r--libgo/go/net/lookup_unix.go5
-rw-r--r--libgo/go/net/lookup_windows_test.go2
-rw-r--r--libgo/go/net/main_cloexec_test.go1
-rw-r--r--libgo/go/net/main_conf_test.go1
-rw-r--r--libgo/go/net/main_noconf_test.go1
-rw-r--r--libgo/go/net/main_posix_test.go1
-rw-r--r--libgo/go/net/main_test.go1
-rw-r--r--libgo/go/net/main_unix_test.go1
-rw-r--r--libgo/go/net/mockserver_test.go1
-rw-r--r--libgo/go/net/net.go6
-rw-r--r--libgo/go/net/net_fake.go3
-rw-r--r--libgo/go/net/net_test.go21
-rw-r--r--libgo/go/net/nss.go1
-rw-r--r--libgo/go/net/nss_test.go1
-rw-r--r--libgo/go/net/packetconn_test.go1
-rw-r--r--libgo/go/net/parse.go26
-rw-r--r--libgo/go/net/port_unix.go1
-rw-r--r--libgo/go/net/protoconn_test.go1
-rw-r--r--libgo/go/net/rawconn_stub_test.go1
-rw-r--r--libgo/go/net/rawconn_test.go1
-rw-r--r--libgo/go/net/rawconn_unix_test.go1
-rw-r--r--libgo/go/net/rpc/server.go2
-rw-r--r--libgo/go/net/sendfile_stub.go1
-rw-r--r--libgo/go/net/sendfile_test.go4
-rw-r--r--libgo/go/net/sendfile_unix_alt.go1
-rw-r--r--libgo/go/net/server_test.go8
-rw-r--r--libgo/go/net/sock_bsd.go1
-rw-r--r--libgo/go/net/sock_cloexec.go5
-rw-r--r--libgo/go/net/sock_posix.go1
-rw-r--r--libgo/go/net/sock_stub.go1
-rw-r--r--libgo/go/net/sockaddr_posix.go1
-rw-r--r--libgo/go/net/sockopt_bsd.go3
-rw-r--r--libgo/go/net/sockopt_posix.go1
-rw-r--r--libgo/go/net/sockopt_stub.go1
-rw-r--r--libgo/go/net/sockoptip_bsdvar.go1
-rw-r--r--libgo/go/net/sockoptip_posix.go1
-rw-r--r--libgo/go/net/sockoptip_stub.go1
-rw-r--r--libgo/go/net/splice_stub.go1
-rw-r--r--libgo/go/net/splice_test.go1
-rw-r--r--libgo/go/net/sys_cloexec.go5
-rw-r--r--libgo/go/net/tcpsock.go5
-rw-r--r--libgo/go/net/tcpsock_posix.go1
-rw-r--r--libgo/go/net/tcpsock_test.go1
-rw-r--r--libgo/go/net/tcpsock_unix_test.go1
-rw-r--r--libgo/go/net/tcpsockopt_plan9.go3
-rw-r--r--libgo/go/net/tcpsockopt_posix.go1
-rw-r--r--libgo/go/net/tcpsockopt_stub.go1
-rw-r--r--libgo/go/net/tcpsockopt_unix.go1
-rw-r--r--libgo/go/net/testdata/ipv4-hosts8
-rw-r--r--libgo/go/net/timeout_test.go1
-rw-r--r--libgo/go/net/udpsock.go27
-rw-r--r--libgo/go/net/udpsock_plan9.go7
-rw-r--r--libgo/go/net/udpsock_posix.go13
-rw-r--r--libgo/go/net/udpsock_test.go51
-rw-r--r--libgo/go/net/unixsock_posix.go7
-rw-r--r--libgo/go/net/unixsock_readmsg_cloexec.go31
-rw-r--r--libgo/go/net/unixsock_readmsg_cmsg_cloexec.go14
-rw-r--r--libgo/go/net/unixsock_readmsg_other.go12
-rw-r--r--libgo/go/net/unixsock_readmsg_test.go105
-rw-r--r--libgo/go/net/unixsock_test.go1
-rw-r--r--libgo/go/net/unixsock_windows_test.go1
-rw-r--r--libgo/go/net/url/url.go90
-rw-r--r--libgo/go/net/url/url_test.go134
-rw-r--r--libgo/go/net/write_unix_test.go1
-rw-r--r--libgo/go/net/writev_test.go1
-rw-r--r--libgo/go/net/writev_unix.go1
180 files changed, 2205 insertions, 596 deletions
diff --git a/libgo/go/net/addrselect.go b/libgo/go/net/addrselect.go
index 6fb6baf..4603c55 100644
--- a/libgo/go/net/addrselect.go
+++ b/libgo/go/net/addrselect.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
// Minimal RFC 6724 address selection.
diff --git a/libgo/go/net/addrselect_test.go b/libgo/go/net/addrselect_test.go
index a43ac5e..18784fe 100644
--- a/libgo/go/net/addrselect_test.go
+++ b/libgo/go/net/addrselect_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/cgo_aix.go b/libgo/go/net/cgo_aix.go
index 4f23d9b..577649f 100644
--- a/libgo/go/net/cgo_aix.go
+++ b/libgo/go/net/cgo_aix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build cgo && !netgo
// +build cgo,!netgo
package net
diff --git a/libgo/go/net/cgo_android.go b/libgo/go/net/cgo_android.go
index ab0368d..4b1a2e3 100644
--- a/libgo/go/net/cgo_android.go
+++ b/libgo/go/net/cgo_android.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build cgo && !netgo
// +build cgo,!netgo
package net
diff --git a/libgo/go/net/cgo_bsd.go b/libgo/go/net/cgo_bsd.go
index c1adf20..1268c89 100644
--- a/libgo/go/net/cgo_bsd.go
+++ b/libgo/go/net/cgo_bsd.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!netgo
+//go:build cgo && !netgo && (darwin || dragonfly || freebsd)
+// +build cgo
+// +build !netgo
// +build darwin dragonfly freebsd
package net
diff --git a/libgo/go/net/cgo_linux.go b/libgo/go/net/cgo_linux.go
index 36bac34..4b45dad 100644
--- a/libgo/go/net/cgo_linux.go
+++ b/libgo/go/net/cgo_linux.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !android && cgo && !netgo
// +build !android,cgo,!netgo
package net
diff --git a/libgo/go/net/cgo_netbsd.go b/libgo/go/net/cgo_netbsd.go
index 1ce0139..e23899d 100644
--- a/libgo/go/net/cgo_netbsd.go
+++ b/libgo/go/net/cgo_netbsd.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build cgo && !netgo
// +build cgo,!netgo
package net
diff --git a/libgo/go/net/cgo_openbsd.go b/libgo/go/net/cgo_openbsd.go
index 4610246..3714793 100644
--- a/libgo/go/net/cgo_openbsd.go
+++ b/libgo/go/net/cgo_openbsd.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build cgo && !netgo
// +build cgo,!netgo
package net
diff --git a/libgo/go/net/cgo_resnew.go b/libgo/go/net/cgo_resnew.go
index 8bc1c1c..6611fd7 100644
--- a/libgo/go/net/cgo_resnew.go
+++ b/libgo/go/net/cgo_resnew.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!netgo
+//go:build cgo && !netgo && (aix || darwin || hurd || (linux && !android) || netbsd || solaris)
+// +build cgo
+// +build !netgo
// +build aix darwin hurd linux,!android netbsd solaris
package net
diff --git a/libgo/go/net/cgo_resold.go b/libgo/go/net/cgo_resold.go
index 8e13e41..33f664c 100644
--- a/libgo/go/net/cgo_resold.go
+++ b/libgo/go/net/cgo_resold.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!netgo
+//go:build cgo && !netgo && (android || freebsd || dragonfly || openbsd)
+// +build cgo
+// +build !netgo
// +build android freebsd dragonfly openbsd
package net
diff --git a/libgo/go/net/cgo_socknew.go b/libgo/go/net/cgo_socknew.go
index 9dcd158..84b40c9 100644
--- a/libgo/go/net/cgo_socknew.go
+++ b/libgo/go/net/cgo_socknew.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!netgo
+//go:build cgo && !netgo && (android || linux || solaris)
+// +build cgo
+// +build !netgo
// +build android linux solaris
package net
diff --git a/libgo/go/net/cgo_sockold.go b/libgo/go/net/cgo_sockold.go
index f514679..703b41b 100644
--- a/libgo/go/net/cgo_sockold.go
+++ b/libgo/go/net/cgo_sockold.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!netgo
+//go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || hurd || netbsd || openbsd)
+// +build cgo
+// +build !netgo
// +build aix darwin dragonfly freebsd hurd netbsd openbsd
package net
diff --git a/libgo/go/net/cgo_solaris.go b/libgo/go/net/cgo_solaris.go
index bd1e8f3..95d5db5 100644
--- a/libgo/go/net/cgo_solaris.go
+++ b/libgo/go/net/cgo_solaris.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build cgo && !netgo
// +build cgo,!netgo
package net
diff --git a/libgo/go/net/cgo_stub.go b/libgo/go/net/cgo_stub.go
index 041f8af..039e4be 100644
--- a/libgo/go/net/cgo_stub.go
+++ b/libgo/go/net/cgo_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !cgo || netgo
// +build !cgo netgo
package net
diff --git a/libgo/go/net/cgo_unix.go b/libgo/go/net/cgo_unix.go
index 0c9a488..462bf12 100644
--- a/libgo/go/net/cgo_unix.go
+++ b/libgo/go/net/cgo_unix.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!netgo
+//go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris)
+// +build cgo
+// +build !netgo
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/cgo_unix_test.go b/libgo/go/net/cgo_unix_test.go
index e844ef5..98b3b4a 100644
--- a/libgo/go/net/cgo_unix_test.go
+++ b/libgo/go/net/cgo_unix_test.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!netgo
+//go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris)
+// +build cgo
+// +build !netgo
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/cgo_windows.go b/libgo/go/net/cgo_windows.go
index 8968b75..1fd1f297 100644
--- a/libgo/go/net/cgo_windows.go
+++ b/libgo/go/net/cgo_windows.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build cgo && !netgo
// +build cgo,!netgo
package net
diff --git a/libgo/go/net/conf.go b/libgo/go/net/conf.go
index b0f1b79..fe7ebf1 100644
--- a/libgo/go/net/conf.go
+++ b/libgo/go/net/conf.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/conf_netcgo.go b/libgo/go/net/conf_netcgo.go
index abc33ce..c705152 100644
--- a/libgo/go/net/conf_netcgo.go
+++ b/libgo/go/net/conf_netcgo.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build netcgo
// +build netcgo
package net
diff --git a/libgo/go/net/conf_test.go b/libgo/go/net/conf_test.go
index a8e1807..f5e4d86 100644
--- a/libgo/go/net/conf_test.go
+++ b/libgo/go/net/conf_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/conn_test.go b/libgo/go/net/conn_test.go
index 771cabc..45e271c 100644
--- a/libgo/go/net/conn_test.go
+++ b/libgo/go/net/conn_test.go
@@ -5,6 +5,7 @@
// This file implements API tests across platforms and will never have a build
// tag.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 13a312a..486ced0 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -344,6 +344,9 @@ type sysDialer struct {
//
// See func Dial for a description of the network and address
// parameters.
+//
+// Dial uses context.Background internally; to specify the context, use
+// DialContext.
func (d *Dialer) Dial(network, address string) (Conn, error) {
return d.DialContext(context.Background(), network, address)
}
@@ -701,6 +704,9 @@ type sysListener struct {
//
// See func Dial for a description of the network and address
// parameters.
+//
+// Listen uses context.Background internally; to specify the context, use
+// ListenConfig.Listen.
func Listen(network, address string) (Listener, error) {
var lc ListenConfig
return lc.Listen(context.Background(), network, address)
@@ -728,6 +734,9 @@ func Listen(network, address string) (Listener, error) {
//
// See func Dial for a description of the network and address
// parameters.
+//
+// ListenPacket uses context.Background internally; to specify the context, use
+// ListenConfig.ListenPacket.
func ListenPacket(network, address string) (PacketConn, error) {
var lc ListenConfig
return lc.ListenPacket(context.Background(), network, address)
diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go
index 57cf555..723038c 100644
--- a/libgo/go/net/dial_test.go
+++ b/libgo/go/net/dial_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
@@ -154,40 +155,27 @@ func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*T
return c, err
}
-func dialClosedPort(t *testing.T) (actual, expected time.Duration) {
- // Estimate the expected time for this platform.
- // On Windows, dialing a closed port takes roughly 1 second,
- // but other platforms should be instantaneous.
- if runtime.GOOS == "windows" {
- expected = 1500 * time.Millisecond
- } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
- expected = 150 * time.Millisecond
- } else {
- expected = 95 * time.Millisecond
- }
+func dialClosedPort(t *testing.T) (dialLatency time.Duration) {
+ // On most platforms, dialing a closed port should be nearly instantaneous —
+ // less than a few hundred milliseconds. However, on some platforms it may be
+ // much slower: on Windows and OpenBSD, it has been observed to take up to a
+ // few seconds.
l, err := Listen("tcp", "127.0.0.1:0")
if err != nil {
- t.Logf("dialClosedPort: Listen failed: %v", err)
- return 999 * time.Hour, expected
+ t.Fatalf("dialClosedPort: Listen failed: %v", err)
}
addr := l.Addr().String()
l.Close()
- // On OpenBSD, interference from TestTCPSelfConnect is mysteriously
- // causing the first attempt to hang for a few seconds, so we throw
- // away the first result and keep the second.
- for i := 1; ; i++ {
- startTime := time.Now()
- c, err := Dial("tcp", addr)
- if err == nil {
- c.Close()
- }
- elapsed := time.Now().Sub(startTime)
- if i == 2 {
- t.Logf("dialClosedPort: measured delay %v", elapsed)
- return elapsed, expected
- }
+
+ startTime := time.Now()
+ c, err := Dial("tcp", addr)
+ if err == nil {
+ c.Close()
}
+ elapsed := time.Now().Sub(startTime)
+ t.Logf("dialClosedPort: measured delay %v", elapsed)
+ return elapsed
}
func TestDialParallel(t *testing.T) {
@@ -197,10 +185,7 @@ func TestDialParallel(t *testing.T) {
t.Skip("both IPv4 and IPv6 are required")
}
- closedPortDelay, expectClosedPortDelay := dialClosedPort(t)
- if closedPortDelay > expectClosedPortDelay {
- t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
- }
+ closedPortDelay := dialClosedPort(t)
const instant time.Duration = 0
const fallbackDelay = 200 * time.Millisecond
@@ -655,15 +640,7 @@ func TestDialerLocalAddr(t *testing.T) {
}
c, err := d.Dial(tt.network, addr)
if err == nil && tt.error != nil || err != nil && tt.error == nil {
- // A suspected kernel bug in macOS 10.12 occasionally results in
- // timeout errors when dialing address ::1. The errors have not
- // been observed on newer versions of the OS, so we don't plan to work
- // around them. See https://golang.org/issue/22019.
- if tt.raddr == "::1" && os.Getenv("GO_BUILDER_NAME") == "darwin-amd64-10_12" && os.IsTimeout(err) {
- t.Logf("ignoring timeout error on Darwin; see https://golang.org/issue/22019")
- } else {
- t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
- }
+ t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
}
if err != nil {
if perr := parseDialError(err); perr != nil {
@@ -682,10 +659,7 @@ func TestDialerDualStack(t *testing.T) {
t.Skip("both IPv4 and IPv6 are required")
}
- closedPortDelay, expectClosedPortDelay := dialClosedPort(t)
- if closedPortDelay > expectClosedPortDelay {
- t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
- }
+ closedPortDelay := dialClosedPort(t)
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
diff --git a/libgo/go/net/dial_unix_test.go b/libgo/go/net/dial_unix_test.go
index 1891d8c..4b9bc27 100644
--- a/libgo/go/net/dial_unix_test.go
+++ b/libgo/go/net/dial_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
index e9c7384..1bbe396 100644
--- a/libgo/go/net/dnsclient.go
+++ b/libgo/go/net/dnsclient.go
@@ -5,6 +5,7 @@
package net
import (
+ "internal/itoa"
"sort"
"golang.org/x/net/dns/dnsmessage"
@@ -33,7 +34,7 @@ func reverseaddr(addr string) (arpa string, err error) {
return "", &DNSError{Err: "unrecognized address", Name: addr}
}
if ip.To4() != nil {
- return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
+ return itoa.Uitoa(uint(ip[15])) + "." + itoa.Uitoa(uint(ip[14])) + "." + itoa.Uitoa(uint(ip[13])) + "." + itoa.Uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
}
// Must be IPv6
buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go
index c5bfab9..a326319 100644
--- a/libgo/go/net/dnsclient_unix.go
+++ b/libgo/go/net/dnsclient_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
// DNS client: see RFC 1035.
@@ -17,6 +18,7 @@ package net
import (
"context"
"errors"
+ "internal/itoa"
"io"
"os"
"sync"
@@ -509,7 +511,7 @@ func (o hostLookupOrder) String() string {
if s, ok := lookupOrderName[o]; ok {
return s
}
- return "hostLookupOrder=" + itoa(int(o)) + "??"
+ return "hostLookupOrder=" + itoa.Itoa(int(o)) + "??"
}
// goLookupHost is the native Go implementation of LookupHost.
@@ -530,7 +532,7 @@ func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hos
return
}
}
- ips, _, err := r.goLookupIPCNAMEOrder(ctx, name, order)
+ ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order)
if err != nil {
return
}
@@ -556,13 +558,13 @@ func goLookupIPFiles(name string) (addrs []IPAddr) {
// goLookupIP is the native Go implementation of LookupIP.
// The libc versions are in cgo_*.go.
-func (r *Resolver) goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+func (r *Resolver) goLookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
order := systemConf().hostLookupOrder(r, host)
- addrs, _, err = r.goLookupIPCNAMEOrder(ctx, host, order)
+ addrs, _, err = r.goLookupIPCNAMEOrder(ctx, network, host, order)
return
}
-func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
+func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name string, order hostLookupOrder) (addrs []IPAddr, cname dnsmessage.Name, err error) {
if order == hostLookupFilesDNS || order == hostLookupFiles {
addrs = goLookupIPFiles(name)
if len(addrs) > 0 || order == hostLookupFiles {
@@ -583,7 +585,13 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, name string, order
error
}
lane := make(chan result, 1)
- qtypes := [...]dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
+ qtypes := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
+ switch ipVersion(network) {
+ case '4':
+ qtypes = []dnsmessage.Type{dnsmessage.TypeA}
+ case '6':
+ qtypes = []dnsmessage.Type{dnsmessage.TypeAAAA}
+ }
var queryFn func(fqdn string, qtype dnsmessage.Type)
var responseFn func(fqdn string, qtype dnsmessage.Type) result
if conf.singleRequest {
@@ -728,7 +736,7 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, name string, order
// goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
func (r *Resolver) goLookupCNAME(ctx context.Context, host string) (string, error) {
order := systemConf().hostLookupOrder(r, host)
- _, cname, err := r.goLookupIPCNAMEOrder(ctx, host, order)
+ _, cname, err := r.goLookupIPCNAMEOrder(ctx, "ip", host, order)
return cname.String(), err
}
diff --git a/libgo/go/net/dnsclient_unix_test.go b/libgo/go/net/dnsclient_unix_test.go
index 3c9ada3..ce1a4f3 100644
--- a/libgo/go/net/dnsclient_unix_test.go
+++ b/libgo/go/net/dnsclient_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
@@ -600,14 +601,14 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
name := fmt.Sprintf("order %v", order)
// First ensure that we get an error when contacting a non-existent host.
- _, _, err := r.goLookupIPCNAMEOrder(context.Background(), "notarealhost", order)
+ _, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "notarealhost", order)
if err == nil {
t.Errorf("%s: expected error while looking up name not in hosts file", name)
continue
}
// Now check that we get an address when the name appears in the hosts file.
- addrs, _, err := r.goLookupIPCNAMEOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
+ addrs, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "thor", order) // entry is in "testdata/hosts"
if err != nil {
t.Errorf("%s: expected to successfully lookup host entry", name)
continue
@@ -1845,6 +1846,17 @@ func TestCVE202133195(t *testing.T) {
Target: dnsmessage.MustNewName("<html>.golang.org."),
},
},
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: n,
+ Type: dnsmessage.TypeSRV,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.SRVResource{
+ Target: dnsmessage.MustNewName("good.golang.org."),
+ },
+ },
)
case dnsmessage.TypeMX:
r.Answers = append(r.Answers,
@@ -1859,6 +1871,17 @@ func TestCVE202133195(t *testing.T) {
MX: dnsmessage.MustNewName("<html>.golang.org."),
},
},
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: dnsmessage.MustNewName("good.golang.org."),
+ Type: dnsmessage.TypeMX,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.MXResource{
+ MX: dnsmessage.MustNewName("good.golang.org."),
+ },
+ },
)
case dnsmessage.TypeNS:
r.Answers = append(r.Answers,
@@ -1873,6 +1896,17 @@ func TestCVE202133195(t *testing.T) {
NS: dnsmessage.MustNewName("<html>.golang.org."),
},
},
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: dnsmessage.MustNewName("good.golang.org."),
+ Type: dnsmessage.TypeNS,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.NSResource{
+ NS: dnsmessage.MustNewName("good.golang.org."),
+ },
+ },
)
case dnsmessage.TypePTR:
r.Answers = append(r.Answers,
@@ -1887,6 +1921,17 @@ func TestCVE202133195(t *testing.T) {
PTR: dnsmessage.MustNewName("<html>.golang.org."),
},
},
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: dnsmessage.MustNewName("good.golang.org."),
+ Type: dnsmessage.TypePTR,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.PTRResource{
+ PTR: dnsmessage.MustNewName("good.golang.org."),
+ },
+ },
)
}
return r, nil
@@ -1902,57 +1947,177 @@ func TestCVE202133195(t *testing.T) {
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
testHookHostsPath = "testdata/hosts"
- _, err := r.LookupCNAME(context.Background(), "golang.org")
- if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected)
- }
- _, err = LookupCNAME("golang.org")
- if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected)
- }
-
- _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
- if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
- }
- _, _, err = LookupSRV("target", "tcp", "golang.org")
- if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
+ tests := []struct {
+ name string
+ f func(*testing.T)
+ }{
+ {
+ name: "CNAME",
+ f: func(t *testing.T) {
+ expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
+ _, err := r.LookupCNAME(context.Background(), "golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ _, err = LookupCNAME("golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ },
+ },
+ {
+ name: "SRV (bad record)",
+ f: func(t *testing.T) {
+ expected := []*SRV{
+ {
+ Target: "good.golang.org.",
+ },
+ }
+ expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
+ _, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ _, records, err = LookupSRV("target", "tcp", "golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Errorf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ },
+ },
+ {
+ name: "SRV (bad header)",
+ f: func(t *testing.T) {
+ _, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.")
+ if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
+ }
+ _, _, err = LookupSRV("hdr", "tcp", "golang.org.")
+ if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
+ }
+ },
+ },
+ {
+ name: "MX",
+ f: func(t *testing.T) {
+ expected := []*MX{
+ {
+ Host: "good.golang.org.",
+ },
+ }
+ expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
+ records, err := r.LookupMX(context.Background(), "golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ records, err = LookupMX("golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ },
+ },
+ {
+ name: "NS",
+ f: func(t *testing.T) {
+ expected := []*NS{
+ {
+ Host: "good.golang.org.",
+ },
+ }
+ expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
+ records, err := r.LookupNS(context.Background(), "golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ records, err = LookupNS("golang.org")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ },
+ },
+ {
+ name: "Addr",
+ f: func(t *testing.T) {
+ expected := []string{"good.golang.org."}
+ expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"}
+ records, err := r.LookupAddr(context.Background(), "192.0.2.42")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ records, err = LookupAddr("192.0.2.42")
+ if err.Error() != expectedErr.Error() {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if !reflect.DeepEqual(records, expected) {
+ t.Error("Unexpected record set")
+ }
+ },
+ },
}
- _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org")
- if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
- t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
- }
- _, _, err = LookupSRV("hdr", "tcp", "golang.org")
- if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
- t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
+ for _, tc := range tests {
+ t.Run(tc.name, tc.f)
}
- _, err = r.LookupMX(context.Background(), "golang.org")
- if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected)
- }
- _, err = LookupMX("golang.org")
- if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected)
- }
+}
- _, err = r.LookupNS(context.Background(), "golang.org")
- if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected)
- }
- _, err = LookupNS("golang.org")
- if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected)
+func TestNullMX(t *testing.T) {
+ fake := fakeDNSServer{
+ rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
+ r := dnsmessage.Message{
+ Header: dnsmessage.Header{
+ ID: q.Header.ID,
+ Response: true,
+ RCode: dnsmessage.RCodeSuccess,
+ },
+ Questions: q.Questions,
+ Answers: []dnsmessage.Resource{
+ {
+ Header: dnsmessage.ResourceHeader{
+ Name: q.Questions[0].Name,
+ Type: dnsmessage.TypeMX,
+ Class: dnsmessage.ClassINET,
+ },
+ Body: &dnsmessage.MXResource{
+ MX: dnsmessage.MustNewName("."),
+ },
+ },
+ },
+ }
+ return r, nil
+ },
}
-
- _, err = r.LookupAddr(context.Background(), "192.0.2.42")
- if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected)
+ r := Resolver{PreferGo: true, Dial: fake.DialContext}
+ rrset, err := r.LookupMX(context.Background(), "golang.org")
+ if err != nil {
+ t.Fatalf("LookupMX: %v", err)
}
- _, err = LookupAddr("192.0.2.42")
- if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
- t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected)
+ if want := []*MX{&MX{Host: "."}}; !reflect.DeepEqual(rrset, want) {
+ records := []string{}
+ for _, rr := range rrset {
+ records = append(records, fmt.Sprintf("%v", rr))
+ }
+ t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0])
}
}
diff --git a/libgo/go/net/dnsconfig_unix.go b/libgo/go/net/dnsconfig_unix.go
index b76b32f..4b11602 100644
--- a/libgo/go/net/dnsconfig_unix.go
+++ b/libgo/go/net/dnsconfig_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
// Read system DNS config from /etc/resolv.conf
diff --git a/libgo/go/net/dnsconfig_unix_test.go b/libgo/go/net/dnsconfig_unix_test.go
index f6edffc..59e21d6 100644
--- a/libgo/go/net/dnsconfig_unix_test.go
+++ b/libgo/go/net/dnsconfig_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go
index 2964982..d851bf7 100644
--- a/libgo/go/net/dnsname_test.go
+++ b/libgo/go/net/dnsname_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/error_posix.go b/libgo/go/net/error_posix.go
index c13d5bc..017f2cb 100644
--- a/libgo/go/net/error_posix.go
+++ b/libgo/go/net/error_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/error_posix_test.go b/libgo/go/net/error_posix_test.go
index b411a37..ea52a45 100644
--- a/libgo/go/net/error_posix_test.go
+++ b/libgo/go/net/error_posix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9
// +build !plan9
package net
diff --git a/libgo/go/net/error_test.go b/libgo/go/net/error_test.go
index 556eb8c..c304390 100644
--- a/libgo/go/net/error_test.go
+++ b/libgo/go/net/error_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/error_unix.go b/libgo/go/net/error_unix.go
index 415e928..3de4e76 100644
--- a/libgo/go/net/error_unix.go
+++ b/libgo/go/net/error_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || js || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd js linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/error_unix_test.go b/libgo/go/net/error_unix_test.go
index 9ce9e12..533a45e 100644
--- a/libgo/go/net/error_unix_test.go
+++ b/libgo/go/net/error_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9 && !windows
// +build !plan9,!windows
package net
diff --git a/libgo/go/net/external_test.go b/libgo/go/net/external_test.go
index f3c69c4..b8753cc 100644
--- a/libgo/go/net/external_test.go
+++ b/libgo/go/net/external_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/fcntl_libc_test.go b/libgo/go/net/fcntl_libc_test.go
new file mode 100644
index 0000000..02511c5
--- /dev/null
+++ b/libgo/go/net/fcntl_libc_test.go
@@ -0,0 +1,27 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || darwin || solaris
+// +build aix darwin solaris
+
+package net
+
+import "syscall"
+
+// Use a helper function to call fcntl. This is defined in C in
+// libgo/runtime.
+//extern __go_fcntl_uintptr
+func libc_fcntl(uintptr, uintptr, uintptr) (uintptr, uintptr)
+
+// Implemented in the syscall package.
+//go:linkname fcntl syscall.fcntl
+func fcntl(fd int, cmd int, arg int) (int, error) {
+ syscall.Entersyscall()
+ r, e := libc_fcntl(uintptr(fd), uintptr(cmd), uintptr(arg))
+ syscall.Exitsyscall()
+ if e != 0 {
+ return int(r), syscall.Errno(e)
+ }
+ return int(r), nil
+}
diff --git a/libgo/go/net/fcntl_syscall_test.go b/libgo/go/net/fcntl_syscall_test.go
new file mode 100644
index 0000000..59ba1a1
--- /dev/null
+++ b/libgo/go/net/fcntl_syscall_test.go
@@ -0,0 +1,27 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build dragonfly || freebsd || linux || netbsd || openbsd
+// +build dragonfly freebsd linux netbsd openbsd
+
+package net
+
+import (
+ "syscall"
+)
+
+// Use a helper function to call fcntl. This is defined in C in
+// libgo/runtime.
+//extern __go_fcntl_uintptr
+func libc_fcntl(uintptr, uintptr, uintptr) (uintptr, uintptr)
+
+func fcntl(fd int, cmd int, arg int) (int, error) {
+ syscall.Entersyscall()
+ r, e := libc_fcntl(uintptr(fd), uintptr(cmd), uintptr(arg))
+ syscall.Exitsyscall()
+ if e != 0 {
+ return int(r), syscall.Errno(e)
+ }
+ return int(r), nil
+}
diff --git a/libgo/go/net/fd_posix.go b/libgo/go/net/fd_posix.go
index b2f99bc..a0f1f5a 100644
--- a/libgo/go/net/fd_posix.go
+++ b/libgo/go/net/fd_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows
package net
@@ -63,10 +64,10 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return n, sa, wrapSyscallError(readFromSyscallName, err)
}
-func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
- n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
+func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
+ n, oobn, retflags, sa, err = fd.pfd.ReadMsg(p, oob, flags)
runtime.KeepAlive(fd)
- return n, oobn, flags, sa, wrapSyscallError(readMsgSyscallName, err)
+ return n, oobn, retflags, sa, wrapSyscallError(readMsgSyscallName, err)
}
func (fd *netFD) Write(p []byte) (nn int, err error) {
diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go
index ad79c06..e2db165 100644
--- a/libgo/go/net/fd_unix.go
+++ b/libgo/go/net/fd_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/file_stub.go b/libgo/go/net/file_stub.go
index bfb8100..9f988fe 100644
--- a/libgo/go/net/file_stub.go
+++ b/libgo/go/net/file_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build js && wasm
// +build js,wasm
package net
diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go
index 8c09c0d..a70ef1b 100644
--- a/libgo/go/net/file_test.go
+++ b/libgo/go/net/file_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/file_unix.go b/libgo/go/net/file_unix.go
index 25caafb..d36a881 100644
--- a/libgo/go/net/file_unix.go
+++ b/libgo/go/net/file_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/hook_unix.go b/libgo/go/net/hook_unix.go
index 780b23c..618c6c2 100644
--- a/libgo/go/net/hook_unix.go
+++ b/libgo/go/net/hook_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
index f850e2f..19c4399 100644
--- a/libgo/go/net/hosts_test.go
+++ b/libgo/go/net/hosts_test.go
@@ -36,7 +36,7 @@ var lookupStaticHostTests = []struct {
},
},
{
- "testdata/ipv4-hosts", // see golang.org/issue/8996
+ "testdata/ipv4-hosts",
[]staticHostEntry{
{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}},
{"localhost.localdomain", []string{"127.0.0.3"}},
@@ -102,7 +102,7 @@ var lookupStaticAddrTests = []struct {
},
},
{
- "testdata/ipv4-hosts", // see golang.org/issue/8996
+ "testdata/ipv4-hosts",
[]staticHostEntry{
{"127.0.0.1", []string{"localhost"}},
{"127.0.0.2", []string{"localhost"}},
diff --git a/libgo/go/net/http/cgi/integration_test.go b/libgo/go/net/http/cgi/integration_test.go
index 76cbca8..ef2eaf7 100644
--- a/libgo/go/net/http/cgi/integration_test.go
+++ b/libgo/go/net/http/cgi/integration_test.go
@@ -95,12 +95,6 @@ func (w *limitWriter) Write(p []byte) (n int, err error) {
func TestKillChildAfterCopyError(t *testing.T) {
testenv.MustHaveExec(t)
- defer func() { testHookStartProcess = nil }()
- proc := make(chan *os.Process, 1)
- testHookStartProcess = func(p *os.Process) {
- proc <- p
- }
-
h := &Handler{
Path: os.Args[0],
Root: "/test.go",
@@ -112,26 +106,9 @@ func TestKillChildAfterCopyError(t *testing.T) {
const writeLen = 50 << 10
rw := &customWriterRecorder{&limitWriter{&out, writeLen}, rec}
- donec := make(chan bool, 1)
- go func() {
- h.ServeHTTP(rw, req)
- donec <- true
- }()
-
- select {
- case <-donec:
- if out.Len() != writeLen || out.Bytes()[0] != 'a' {
- t.Errorf("unexpected output: %q", out.Bytes())
- }
- case <-time.After(5 * time.Second):
- t.Errorf("timeout. ServeHTTP hung and didn't kill the child process?")
- select {
- case p := <-proc:
- p.Kill()
- t.Logf("killed process")
- default:
- t.Logf("didn't kill process")
- }
+ h.ServeHTTP(rw, req)
+ if out.Len() != writeLen || out.Bytes()[0] != 'a' {
+ t.Errorf("unexpected output: %q", out.Bytes())
}
}
diff --git a/libgo/go/net/http/cgi/posix_test.go b/libgo/go/net/http/cgi/posix_test.go
index 9396ce0..bc58ea9 100644
--- a/libgo/go/net/http/cgi/posix_test.go
+++ b/libgo/go/net/http/cgi/posix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9
// +build !plan9
package cgi
diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go
index 88e2028..4d380c6 100644
--- a/libgo/go/net/http/client.go
+++ b/libgo/go/net/http/client.go
@@ -17,6 +17,7 @@ import (
"fmt"
"io"
"log"
+ "net/http/internal/ascii"
"net/url"
"reflect"
"sort"
@@ -432,8 +433,7 @@ func basicAuth(username, password string) string {
// An error is returned if there were too many redirects or if there
// was an HTTP protocol error. A non-2xx response doesn't cause an
// error. Any returned error will be of type *url.Error. The url.Error
-// value's Timeout method will report true if request timed out or was
-// canceled.
+// value's Timeout method will report true if the request timed out.
//
// When err is nil, resp always contains a non-nil resp.Body.
// Caller should close resp.Body when done reading from it.
@@ -442,6 +442,9 @@ func basicAuth(username, password string) string {
//
// To make a request with custom headers, use NewRequest and
// DefaultClient.Do.
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and DefaultClient.Do.
func Get(url string) (resp *Response, err error) {
return DefaultClient.Get(url)
}
@@ -466,6 +469,9 @@ func Get(url string) (resp *Response, err error) {
// Caller should close resp.Body when done reading from it.
//
// To make a request with custom headers, use NewRequest and Client.Do.
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and Client.Do.
func (c *Client) Get(url string) (resp *Response, err error) {
req, err := NewRequest("GET", url, nil)
if err != nil {
@@ -541,7 +547,10 @@ func urlErrorOp(method string) string {
if method == "" {
return "Get"
}
- return method[:1] + strings.ToLower(method[1:])
+ if lowerMethod, ok := ascii.ToLower(method); ok {
+ return method[:1] + lowerMethod[1:]
+ }
+ return method
}
// Do sends an HTTP request and returns an HTTP response, following
@@ -579,8 +588,7 @@ func urlErrorOp(method string) string {
// standard library body types.
//
// Any returned error will be of type *url.Error. The url.Error
-// value's Timeout method will report true if request timed out or was
-// canceled.
+// value's Timeout method will report true if the request timed out.
func (c *Client) Do(req *Request) (*Response, error) {
return c.do(req)
}
@@ -719,7 +727,6 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
reqBodyClosed = true
if !deadline.IsZero() && didTimeout() {
err = &httpError{
- // TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancellation/
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
timeout: true,
}
@@ -821,6 +828,9 @@ func defaultCheckRedirect(req *Request, via []*Request) error {
//
// See the Client.Do method documentation for details on how redirects
// are handled.
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and DefaultClient.Do.
func Post(url, contentType string, body io.Reader) (resp *Response, err error) {
return DefaultClient.Post(url, contentType, body)
}
@@ -834,6 +844,9 @@ func Post(url, contentType string, body io.Reader) (resp *Response, err error) {
//
// To set custom headers, use NewRequest and Client.Do.
//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and Client.Do.
+//
// See the Client.Do method documentation for details on how redirects
// are handled.
func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response, err error) {
@@ -858,6 +871,9 @@ func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response,
//
// See the Client.Do method documentation for details on how redirects
// are handled.
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and DefaultClient.Do.
func PostForm(url string, data url.Values) (resp *Response, err error) {
return DefaultClient.PostForm(url, data)
}
@@ -873,6 +889,9 @@ func PostForm(url string, data url.Values) (resp *Response, err error) {
//
// See the Client.Do method documentation for details on how redirects
// are handled.
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and Client.Do.
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
@@ -888,6 +907,9 @@ func (c *Client) PostForm(url string, data url.Values) (resp *Response, err erro
// 308 (Permanent Redirect)
//
// Head is a wrapper around DefaultClient.Head
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and DefaultClient.Do.
func Head(url string) (resp *Response, err error) {
return DefaultClient.Head(url)
}
@@ -901,6 +923,9 @@ func Head(url string) (resp *Response, err error) {
// 303 (See Other)
// 307 (Temporary Redirect)
// 308 (Permanent Redirect)
+//
+// To make a request with a specified context.Context, use NewRequestWithContext
+// and Client.Do.
func (c *Client) Head(url string) (resp *Response, err error) {
req, err := NewRequest("HEAD", url, nil)
if err != nil {
@@ -926,7 +951,7 @@ func (c *Client) CloseIdleConnections() {
}
// cancelTimerBody is an io.ReadCloser that wraps rc with two features:
-// 1) on Read error or close, the stop func is called.
+// 1) On Read error or close, the stop func is called.
// 2) On Read failure, if reqDidTimeout is true, the error is wrapped and
// marked as net.Error that hit its timeout.
type cancelTimerBody struct {
diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go
index d90b484..01d605c 100644
--- a/libgo/go/net/http/client_test.go
+++ b/libgo/go/net/http/client_test.go
@@ -257,12 +257,12 @@ func TestClientRedirects(t *testing.T) {
t.Fatalf("Get error: %v", err)
}
res.Body.Close()
- finalUrl := res.Request.URL.String()
+ finalURL := res.Request.URL.String()
if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
t.Errorf("with custom client, expected error %q, got %q", e, g)
}
- if !strings.HasSuffix(finalUrl, "/?n=15") {
- t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
+ if !strings.HasSuffix(finalURL, "/?n=15") {
+ t.Errorf("expected final url to end in /?n=15; got url %q", finalURL)
}
if e, g := 15, len(lastVia); e != g {
t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
@@ -1945,7 +1945,7 @@ func TestClientDoCanceledVsTimeout_h2(t *testing.T) {
}
// Issue 33545: lock-in the behavior promised by Client.Do's
-// docs about request cancelation vs timing out.
+// docs about request cancellation vs timing out.
func testClientDoCanceledVsTimeout(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go
index 141bc94..ca2c1c2 100644
--- a/libgo/go/net/http/cookie.go
+++ b/libgo/go/net/http/cookie.go
@@ -7,6 +7,7 @@ package http
import (
"log"
"net"
+ "net/http/internal/ascii"
"net/textproto"
"strconv"
"strings"
@@ -93,15 +94,23 @@ func readSetCookies(h Header) []*Cookie {
if j := strings.Index(attr, "="); j >= 0 {
attr, val = attr[:j], attr[j+1:]
}
- lowerAttr := strings.ToLower(attr)
+ lowerAttr, isASCII := ascii.ToLower(attr)
+ if !isASCII {
+ continue
+ }
val, ok = parseCookieValue(val, false)
if !ok {
c.Unparsed = append(c.Unparsed, parts[i])
continue
}
+
switch lowerAttr {
case "samesite":
- lowerVal := strings.ToLower(val)
+ lowerVal, ascii := ascii.ToLower(val)
+ if !ascii {
+ c.SameSite = SameSiteDefaultMode
+ continue
+ }
switch lowerVal {
case "lax":
c.SameSite = SameSiteLaxMode
diff --git a/libgo/go/net/http/cookiejar/jar.go b/libgo/go/net/http/cookiejar/jar.go
index 9f19917..e6583da 100644
--- a/libgo/go/net/http/cookiejar/jar.go
+++ b/libgo/go/net/http/cookiejar/jar.go
@@ -10,6 +10,7 @@ import (
"fmt"
"net"
"net/http"
+ "net/http/internal/ascii"
"net/url"
"sort"
"strings"
@@ -296,7 +297,6 @@ func (j *Jar) setCookies(u *url.URL, cookies []*http.Cookie, now time.Time) {
// host name.
func canonicalHost(host string) (string, error) {
var err error
- host = strings.ToLower(host)
if hasPort(host) {
host, _, err = net.SplitHostPort(host)
if err != nil {
@@ -307,7 +307,13 @@ func canonicalHost(host string) (string, error) {
// Strip trailing dot from fully qualified domain names.
host = host[:len(host)-1]
}
- return toASCII(host)
+ encoded, err := toASCII(host)
+ if err != nil {
+ return "", err
+ }
+ // We know this is ascii, no need to check.
+ lower, _ := ascii.ToLower(encoded)
+ return lower, nil
}
// hasPort reports whether host contains a port number. host may be a host
@@ -469,7 +475,12 @@ func (j *Jar) domainAndType(host, domain string) (string, bool, error) {
// both are illegal.
return "", false, errMalformedDomain
}
- domain = strings.ToLower(domain)
+
+ domain, isASCII := ascii.ToLower(domain)
+ if !isASCII {
+ // Received non-ASCII domain, e.g. "perché.com" instead of "xn--perch-fsa.com"
+ return "", false, errMalformedDomain
+ }
if domain[len(domain)-1] == '.' {
// We received stuff like "Domain=www.example.com.".
diff --git a/libgo/go/net/http/cookiejar/punycode.go b/libgo/go/net/http/cookiejar/punycode.go
index a9cc666..c7f438d 100644
--- a/libgo/go/net/http/cookiejar/punycode.go
+++ b/libgo/go/net/http/cookiejar/punycode.go
@@ -8,6 +8,7 @@ package cookiejar
import (
"fmt"
+ "net/http/internal/ascii"
"strings"
"unicode/utf8"
)
@@ -133,12 +134,12 @@ const acePrefix = "xn--"
// toASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
// toASCII("golang") is "golang".
func toASCII(s string) (string, error) {
- if ascii(s) {
+ if ascii.Is(s) {
return s, nil
}
labels := strings.Split(s, ".")
for i, label := range labels {
- if !ascii(label) {
+ if !ascii.Is(label) {
a, err := encode(acePrefix, label)
if err != nil {
return "", err
@@ -148,12 +149,3 @@ func toASCII(s string) (string, error) {
}
return strings.Join(labels, "."), nil
}
-
-func ascii(s string) bool {
- for i := 0; i < len(s); i++ {
- if s[i] >= utf8.RuneSelf {
- return false
- }
- }
- return true
-}
diff --git a/libgo/go/net/http/example_test.go b/libgo/go/net/http/example_test.go
index c677d52..2f411d1 100644
--- a/libgo/go/net/http/example_test.go
+++ b/libgo/go/net/http/example_test.go
@@ -45,12 +45,15 @@ func ExampleGet() {
if err != nil {
log.Fatal(err)
}
- robots, err := io.ReadAll(res.Body)
+ body, err := io.ReadAll(res.Body)
res.Body.Close()
+ if res.StatusCode > 299 {
+ log.Fatalf("Response failed with status code: %d and\nbody: %s\n", res.StatusCode, body)
+ }
if err != nil {
log.Fatal(err)
}
- fmt.Printf("%s", robots)
+ fmt.Printf("%s", body)
}
func ExampleFileServer() {
diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go
index 756722b..dc82bf7 100644
--- a/libgo/go/net/http/fcgi/child.go
+++ b/libgo/go/net/http/fcgi/child.go
@@ -16,7 +16,6 @@ import (
"net/http/cgi"
"os"
"strings"
- "sync"
"time"
)
@@ -154,7 +153,6 @@ type child struct {
conn *conn
handler http.Handler
- mu sync.Mutex // protects requests:
requests map[uint16]*request // keyed by request ID
}
@@ -193,9 +191,7 @@ var ErrRequestAborted = errors.New("fcgi: request aborted by web server")
var ErrConnClosed = errors.New("fcgi: connection to web server closed")
func (c *child) handleRecord(rec *record) error {
- c.mu.Lock()
req, ok := c.requests[rec.h.Id]
- c.mu.Unlock()
if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
// The spec says to ignore unknown request IDs.
return nil
@@ -218,9 +214,7 @@ func (c *child) handleRecord(rec *record) error {
return nil
}
req = newRequest(rec.h.Id, br.flags)
- c.mu.Lock()
c.requests[rec.h.Id] = req
- c.mu.Unlock()
return nil
case typeParams:
// NOTE(eds): Technically a key-value pair can straddle the boundary
@@ -248,8 +242,11 @@ func (c *child) handleRecord(rec *record) error {
// TODO(eds): This blocks until the handler reads from the pipe.
// If the handler takes a long time, it might be a problem.
req.pw.Write(content)
- } else if req.pw != nil {
- req.pw.Close()
+ } else {
+ delete(c.requests, req.reqId)
+ if req.pw != nil {
+ req.pw.Close()
+ }
}
return nil
case typeGetValues:
@@ -260,9 +257,7 @@ func (c *child) handleRecord(rec *record) error {
// If the filter role is implemented, read the data stream here.
return nil
case typeAbortRequest:
- c.mu.Lock()
delete(c.requests, rec.h.Id)
- c.mu.Unlock()
c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
if req.pw != nil {
req.pw.CloseWithError(ErrRequestAborted)
@@ -309,9 +304,6 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
// Make sure we serve something even if nothing was written to r
r.Write(nil)
r.Close()
- c.mu.Lock()
- delete(c.requests, req.reqId)
- c.mu.Unlock()
c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
// Consume the entire body, so the host isn't still writing to
@@ -330,8 +322,6 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
}
func (c *child) cleanUp() {
- c.mu.Lock()
- defer c.mu.Unlock()
for _, req := range c.requests {
if req.pw != nil {
// race with call to Close in c.serveRequest doesn't matter because
diff --git a/libgo/go/net/http/fcgi/fcgi_test.go b/libgo/go/net/http/fcgi/fcgi_test.go
index b58111d..5888783 100644
--- a/libgo/go/net/http/fcgi/fcgi_test.go
+++ b/libgo/go/net/http/fcgi/fcgi_test.go
@@ -11,6 +11,7 @@ import (
"net/http"
"strings"
"testing"
+ "time"
)
var sizeTests = []struct {
@@ -399,3 +400,55 @@ func TestResponseWriterSniffsContentType(t *testing.T) {
})
}
}
+
+type signallingNopCloser struct {
+ io.Reader
+ closed chan bool
+}
+
+func (*signallingNopCloser) Write(buf []byte) (int, error) {
+ return len(buf), nil
+}
+
+func (rc *signallingNopCloser) Close() error {
+ close(rc.closed)
+ return nil
+}
+
+// Test whether server properly closes connection when processing slow
+// requests
+func TestSlowRequest(t *testing.T) {
+ pr, pw := io.Pipe()
+ go func(w io.Writer) {
+ for _, buf := range [][]byte{
+ streamBeginTypeStdin,
+ makeRecord(typeStdin, 1, nil),
+ } {
+ pw.Write(buf)
+ time.Sleep(100 * time.Millisecond)
+ }
+ }(pw)
+
+ rc := &signallingNopCloser{pr, make(chan bool)}
+ handlerDone := make(chan bool)
+
+ c := newChild(rc, http.HandlerFunc(func(
+ w http.ResponseWriter,
+ r *http.Request,
+ ) {
+ w.WriteHeader(200)
+ close(handlerDone)
+ }))
+ go c.serve()
+ defer c.cleanUp()
+
+ timeout := time.After(2 * time.Second)
+
+ <-handlerDone
+ select {
+ case <-rc.closed:
+ t.Log("FastCGI child closed connection")
+ case <-timeout:
+ t.Error("FastCGI child did not close socket after handling request")
+ }
+}
diff --git a/libgo/go/net/http/filetransport_test.go b/libgo/go/net/http/filetransport_test.go
index b58888d..77fc8ee 100644
--- a/libgo/go/net/http/filetransport_test.go
+++ b/libgo/go/net/http/filetransport_test.go
@@ -23,12 +23,10 @@ func checker(t *testing.T) func(string, error) {
func TestFileTransport(t *testing.T) {
check := checker(t)
- dname, err := os.MkdirTemp("", "")
- check("TempDir", err)
+ dname := t.TempDir()
fname := filepath.Join(dname, "foo.txt")
- err = os.WriteFile(fname, []byte("Bar"), 0644)
+ err := os.WriteFile(fname, []byte("Bar"), 0644)
check("WriteFile", err)
- defer os.Remove(dname)
defer os.Remove(fname)
tr := &Transport{}
diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go
index a28ae85..57e731e 100644
--- a/libgo/go/net/http/fs.go
+++ b/libgo/go/net/http/fs.go
@@ -46,7 +46,7 @@ type Dir string
// to a possibly better non-nil error. In particular, it turns OS-specific errors
// about opening files in non-directories into fs.ErrNotExist. See Issue 18984.
func mapDirOpenError(originalErr error, name string) error {
- if os.IsNotExist(originalErr) || os.IsPermission(originalErr) {
+ if errors.Is(originalErr, fs.ErrNotExist) || errors.Is(originalErr, fs.ErrPermission) {
return originalErr
}
@@ -670,10 +670,10 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
// and historically Go's ServeContent always returned just "404 Not Found" for
// all errors. We don't want to start leaking information in error messages.
func toHTTPError(err error) (msg string, httpStatus int) {
- if os.IsNotExist(err) {
+ if errors.Is(err, fs.ErrNotExist) {
return "404 page not found", StatusNotFound
}
- if os.IsPermission(err) {
+ if errors.Is(err, fs.ErrPermission) {
return "403 Forbidden", StatusForbidden
}
// Default:
diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go
index 2499051..b42ade1 100644
--- a/libgo/go/net/http/fs_test.go
+++ b/libgo/go/net/http/fs_test.go
@@ -11,7 +11,6 @@ import (
"fmt"
"io"
"io/fs"
- "io/ioutil"
"mime"
"mime/multipart"
"net"
@@ -379,11 +378,7 @@ func mustRemoveAll(dir string) {
func TestFileServerImplicitLeadingSlash(t *testing.T) {
defer afterTest(t)
- tempDir, err := os.MkdirTemp("", "")
- if err != nil {
- t.Fatalf("TempDir: %v", err)
- }
- defer mustRemoveAll(tempDir)
+ tempDir := t.TempDir()
if err := os.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
@@ -593,7 +588,7 @@ func TestServeIndexHtml(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- b, err := ioutil.ReadAll(res.Body)
+ b, err := io.ReadAll(res.Body)
if err != nil {
t.Fatal("reading Body:", err)
}
@@ -1270,16 +1265,18 @@ func TestFileServerNotDirError(t *testing.T) {
if err == nil {
t.Fatal("err == nil; want != nil")
}
- if !os.IsNotExist(err) {
- t.Errorf("err = %v; os.IsNotExist(err) = %v; want true", err, os.IsNotExist(err))
+ if !errors.Is(err, fs.ErrNotExist) {
+ t.Errorf("err = %v; errors.Is(err, fs.ErrNotExist) = %v; want true", err,
+ errors.Is(err, fs.ErrNotExist))
}
_, err = dir.Open("/index.html/not-a-dir/not-a-file")
if err == nil {
t.Fatal("err == nil; want != nil")
}
- if !os.IsNotExist(err) {
- t.Errorf("err = %v; os.IsNotExist(err) = %v; want true", err, os.IsNotExist(err))
+ if !errors.Is(err, fs.ErrNotExist) {
+ t.Errorf("err = %v; errors.Is(err, fs.ErrNotExist) = %v; want true", err,
+ errors.Is(err, fs.ErrNotExist))
}
})
}
diff --git a/libgo/go/net/http/h2_bundle.go b/libgo/go/net/http/h2_bundle.go
index e13c661..0e5fbf8 100644
--- a/libgo/go/net/http/h2_bundle.go
+++ b/libgo/go/net/http/h2_bundle.go
@@ -1,3 +1,4 @@
+//go:build !nethttpomithttp2
// +build !nethttpomithttp2
// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
@@ -52,6 +53,48 @@ import (
"golang.org/x/net/idna"
)
+// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
+// are equal, ASCII-case-insensitively.
+func http2asciiEqualFold(s, t string) bool {
+ if len(s) != len(t) {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if http2lower(s[i]) != http2lower(t[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// lower returns the ASCII lowercase version of b.
+func http2lower(b byte) byte {
+ if 'A' <= b && b <= 'Z' {
+ return b + ('a' - 'A')
+ }
+ return b
+}
+
+// isASCIIPrint returns whether s is ASCII and printable according to
+// https://tools.ietf.org/html/rfc20#section-4.2.
+func http2isASCIIPrint(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] < ' ' || s[i] > '~' {
+ return false
+ }
+ }
+ return true
+}
+
+// asciiToLower returns the lowercase version of s if s is ASCII and printable,
+// and whether or not it was.
+func http2asciiToLower(s string) (lower string, ok bool) {
+ if !http2isASCIIPrint(s) {
+ return "", false
+ }
+ return strings.ToLower(s), true
+}
+
// A list of the possible cipher suite ids. Taken from
// https://www.iana.org/assignments/tls-parameters/tls-parameters.txt
@@ -754,61 +797,69 @@ func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMis
// It gets its own connection.
http2traceGetConn(req, addr)
const singleUse = true
- cc, err := p.t.dialClientConn(addr, singleUse)
+ cc, err := p.t.dialClientConn(req.Context(), addr, singleUse)
if err != nil {
return nil, err
}
return cc, nil
}
- p.mu.Lock()
- for _, cc := range p.conns[addr] {
- if st := cc.idleState(); st.canTakeNewRequest {
- if p.shouldTraceGetConn(st) {
- http2traceGetConn(req, addr)
+ for {
+ p.mu.Lock()
+ for _, cc := range p.conns[addr] {
+ if st := cc.idleState(); st.canTakeNewRequest {
+ if p.shouldTraceGetConn(st) {
+ http2traceGetConn(req, addr)
+ }
+ p.mu.Unlock()
+ return cc, nil
}
+ }
+ if !dialOnMiss {
p.mu.Unlock()
- return cc, nil
+ return nil, http2ErrNoCachedConn
}
- }
- if !dialOnMiss {
+ http2traceGetConn(req, addr)
+ call := p.getStartDialLocked(req.Context(), addr)
p.mu.Unlock()
- return nil, http2ErrNoCachedConn
+ <-call.done
+ if http2shouldRetryDial(call, req) {
+ continue
+ }
+ return call.res, call.err
}
- http2traceGetConn(req, addr)
- call := p.getStartDialLocked(addr)
- p.mu.Unlock()
- <-call.done
- return call.res, call.err
}
// dialCall is an in-flight Transport dial call to a host.
type http2dialCall struct {
- _ http2incomparable
- p *http2clientConnPool
+ _ http2incomparable
+ p *http2clientConnPool
+ // the context associated with the request
+ // that created this dialCall
+ ctx context.Context
done chan struct{} // closed when done
res *http2ClientConn // valid after done is closed
err error // valid after done is closed
}
// requires p.mu is held.
-func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall {
+func (p *http2clientConnPool) getStartDialLocked(ctx context.Context, addr string) *http2dialCall {
if call, ok := p.dialing[addr]; ok {
// A dial is already in-flight. Don't start another.
return call
}
- call := &http2dialCall{p: p, done: make(chan struct{})}
+ call := &http2dialCall{p: p, done: make(chan struct{}), ctx: ctx}
if p.dialing == nil {
p.dialing = make(map[string]*http2dialCall)
}
p.dialing[addr] = call
- go call.dial(addr)
+ go call.dial(call.ctx, addr)
return call
}
// run in its own goroutine.
-func (c *http2dialCall) dial(addr string) {
+func (c *http2dialCall) dial(ctx context.Context, addr string) {
const singleUse = false // shared conn
- c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
+ c.res, c.err = c.p.t.dialClientConn(ctx, addr, singleUse)
close(c.done)
c.p.mu.Lock()
@@ -953,6 +1004,31 @@ func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*ht
return p.getClientConn(req, addr, http2noDialOnMiss)
}
+// shouldRetryDial reports whether the current request should
+// retry dialing after the call finished unsuccessfully, for example
+// if the dial was canceled because of a context cancellation or
+// deadline expiry.
+func http2shouldRetryDial(call *http2dialCall, req *Request) bool {
+ if call.err == nil {
+ // No error, no need to retry
+ return false
+ }
+ if call.ctx == req.Context() {
+ // If the call has the same context as the request, the dial
+ // should not be retried, since any cancellation will have come
+ // from this request.
+ return false
+ }
+ if !errors.Is(call.err, context.Canceled) && !errors.Is(call.err, context.DeadlineExceeded) {
+ // If the call error is not because of a context cancellation or a deadline expiry,
+ // the dial should not be retried.
+ return false
+ }
+ // Only retry if the error is a context cancellation error or deadline expiry
+ // and the context associated with the call was canceled or expired.
+ return call.ctx.Err() != nil
+}
+
// Buffer chunks are allocated from a pool to reduce pressure on GC.
// The maximum wasted space per dataBuffer is 2x the largest size class,
// which happens when the dataBuffer has multiple chunks and there is
@@ -2873,6 +2949,20 @@ func http2traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textpr
return nil
}
+// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
+// connection.
+func (t *http2Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
+ dialer := &tls.Dialer{
+ Config: cfg,
+ }
+ cn, err := dialer.DialContext(ctx, network, addr)
+ if err != nil {
+ return nil, err
+ }
+ tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
+ return tlsCn, nil
+}
+
var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
type http2goroutineLock uint64
@@ -3094,12 +3184,12 @@ func http2buildCommonHeaderMaps() {
}
}
-func http2lowerHeader(v string) string {
+func http2lowerHeader(v string) (lower string, ascii bool) {
http2buildCommonHeaderMapsOnce()
if s, ok := http2commonLowerHeader[v]; ok {
- return s
+ return s, true
}
- return strings.ToLower(v)
+ return http2asciiToLower(v)
}
var (
@@ -3797,13 +3887,12 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
if s.TLSConfig == nil {
s.TLSConfig = new(tls.Config)
- } else if s.TLSConfig.CipherSuites != nil {
- // If they already provided a CipherSuite list, return
- // an error if it has a bad order or is missing
- // ECDHE_RSA_WITH_AES_128_GCM_SHA256 or ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
+ } else if s.TLSConfig.CipherSuites != nil && s.TLSConfig.MinVersion < tls.VersionTLS13 {
+ // If they already provided a TLS 1.0–1.2 CipherSuite list, return an
+ // error if it is missing ECDHE_RSA_WITH_AES_128_GCM_SHA256 or
+ // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
haveRequired := false
- sawBad := false
- for i, cs := range s.TLSConfig.CipherSuites {
+ for _, cs := range s.TLSConfig.CipherSuites {
switch cs {
case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
// Alternative MTI cipher to not discourage ECDSA-only servers.
@@ -3811,14 +3900,9 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
haveRequired = true
}
- if http2isBadCipher(cs) {
- sawBad = true
- } else if sawBad {
- return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs)
- }
}
if !haveRequired {
- return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).")
+ return fmt.Errorf("http2: TLSConfig.CipherSuites is missing an HTTP/2-required AES_128_GCM_SHA256 cipher (need at least one of TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)")
}
}
@@ -4864,7 +4948,9 @@ func (sc *http2serverConn) startGracefulShutdown() {
sc.shutdownOnce.Do(func() { sc.sendServeMsg(http2gracefulShutdownMsg) })
}
-// After sending GOAWAY, the connection will close after goAwayTimeout.
+// After sending GOAWAY with an error code (non-graceful shutdown), the
+// connection will close after goAwayTimeout.
+//
// If we close the connection immediately after sending GOAWAY, there may
// be unsent data in our kernel receive buffer, which will cause the kernel
// to send a TCP RST on close() instead of a FIN. This RST will abort the
@@ -5200,23 +5286,37 @@ func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
func (sc *http2serverConn) processData(f *http2DataFrame) error {
sc.serveG.check()
- if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
+ id := f.Header().StreamID
+ if sc.inGoAway && (sc.goAwayCode != http2ErrCodeNo || id > sc.maxClientStreamID) {
+ // Discard all DATA frames if the GOAWAY is due to an
+ // error, or:
+ //
+ // Section 6.8: After sending a GOAWAY frame, the sender
+ // can discard frames for streams initiated by the
+ // receiver with identifiers higher than the identified
+ // last stream.
return nil
}
- data := f.Data()
- // "If a DATA frame is received whose stream is not in "open"
- // or "half closed (local)" state, the recipient MUST respond
- // with a stream error (Section 5.4.2) of type STREAM_CLOSED."
- id := f.Header().StreamID
+ data := f.Data()
state, st := sc.state(id)
if id == 0 || state == http2stateIdle {
+ // Section 6.1: "DATA frames MUST be associated with a
+ // stream. If a DATA frame is received whose stream
+ // identifier field is 0x0, the recipient MUST respond
+ // with a connection error (Section 5.4.1) of type
+ // PROTOCOL_ERROR."
+ //
// Section 5.1: "Receiving any frame other than HEADERS
// or PRIORITY on a stream in this state MUST be
// treated as a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR."
return http2ConnectionError(http2ErrCodeProtocol)
}
+
+ // "If a DATA frame is received whose stream is not in "open"
+ // or "half closed (local)" state, the recipient MUST respond
+ // with a stream error (Section 5.4.2) of type STREAM_CLOSED."
if st == nil || state != http2stateOpen || st.gotTrailerHeader || st.resetQueued {
// This includes sending a RST_STREAM if the stream is
// in stateHalfClosedLocal (which currently means that
@@ -6344,8 +6444,12 @@ func (w *http2responseWriter) Push(target string, opts *PushOptions) error {
// but PUSH_PROMISE requests cannot have a body.
// http://tools.ietf.org/html/rfc7540#section-8.2
// Also disallow Host, since the promised URL must be absolute.
- switch strings.ToLower(k) {
- case "content-length", "content-encoding", "trailer", "te", "expect", "host":
+ if http2asciiEqualFold(k, "content-length") ||
+ http2asciiEqualFold(k, "content-encoding") ||
+ http2asciiEqualFold(k, "trailer") ||
+ http2asciiEqualFold(k, "te") ||
+ http2asciiEqualFold(k, "expect") ||
+ http2asciiEqualFold(k, "host") {
return fmt.Errorf("promised request headers cannot include %q", k)
}
}
@@ -7067,12 +7171,12 @@ func http2canRetryError(err error) bool {
return false
}
-func (t *http2Transport) dialClientConn(addr string, singleUse bool) (*http2ClientConn, error) {
+func (t *http2Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*http2ClientConn, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
- tconn, err := t.dialTLS()("tcp", addr, t.newTLSConfig(host))
+ tconn, err := t.dialTLS(ctx)("tcp", addr, t.newTLSConfig(host))
if err != nil {
return nil, err
}
@@ -7093,34 +7197,24 @@ func (t *http2Transport) newTLSConfig(host string) *tls.Config {
return cfg
}
-func (t *http2Transport) dialTLS() func(string, string, *tls.Config) (net.Conn, error) {
+func (t *http2Transport) dialTLS(ctx context.Context) func(string, string, *tls.Config) (net.Conn, error) {
if t.DialTLS != nil {
return t.DialTLS
}
- return t.dialTLSDefault
-}
-
-func (t *http2Transport) dialTLSDefault(network, addr string, cfg *tls.Config) (net.Conn, error) {
- cn, err := tls.Dial(network, addr, cfg)
- if err != nil {
- return nil, err
- }
- if err := cn.Handshake(); err != nil {
- return nil, err
- }
- if !cfg.InsecureSkipVerify {
- if err := cn.VerifyHostname(cfg.ServerName); err != nil {
+ return func(network, addr string, cfg *tls.Config) (net.Conn, error) {
+ tlsCn, err := t.dialTLSWithContext(ctx, network, addr, cfg)
+ if err != nil {
return nil, err
}
+ state := tlsCn.ConnectionState()
+ if p := state.NegotiatedProtocol; p != http2NextProtoTLS {
+ return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, http2NextProtoTLS)
+ }
+ if !state.NegotiatedProtocolIsMutual {
+ return nil, errors.New("http2: could not negotiate protocol mutually")
+ }
+ return tlsCn, nil
}
- state := cn.ConnectionState()
- if p := state.NegotiatedProtocol; p != http2NextProtoTLS {
- return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, http2NextProtoTLS)
- }
- if !state.NegotiatedProtocolIsMutual {
- return nil, errors.New("http2: could not negotiate protocol mutually")
- }
- return cn, nil
}
// disableKeepAlives reports whether connections should be closed as
@@ -7508,7 +7602,7 @@ func http2checkConnHeaders(req *Request) error {
if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv)
}
- if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !strings.EqualFold(vv[0], "close") && !strings.EqualFold(vv[0], "keep-alive")) {
+ if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !http2asciiEqualFold(vv[0], "close") && !http2asciiEqualFold(vv[0], "keep-alive")) {
return fmt.Errorf("http2: invalid Connection request header: %q", vv)
}
return nil
@@ -8049,19 +8143,21 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
var didUA bool
for k, vv := range req.Header {
- if strings.EqualFold(k, "host") || strings.EqualFold(k, "content-length") {
+ if http2asciiEqualFold(k, "host") || http2asciiEqualFold(k, "content-length") {
// Host is :authority, already sent.
// Content-Length is automatic, set below.
continue
- } else if strings.EqualFold(k, "connection") || strings.EqualFold(k, "proxy-connection") ||
- strings.EqualFold(k, "transfer-encoding") || strings.EqualFold(k, "upgrade") ||
- strings.EqualFold(k, "keep-alive") {
+ } else if http2asciiEqualFold(k, "connection") ||
+ http2asciiEqualFold(k, "proxy-connection") ||
+ http2asciiEqualFold(k, "transfer-encoding") ||
+ http2asciiEqualFold(k, "upgrade") ||
+ http2asciiEqualFold(k, "keep-alive") {
// Per 8.1.2.2 Connection-Specific Header
// Fields, don't send connection-specific
// fields. We have already checked if any
// are error-worthy so just ignore the rest.
continue
- } else if strings.EqualFold(k, "user-agent") {
+ } else if http2asciiEqualFold(k, "user-agent") {
// Match Go's http1 behavior: at most one
// User-Agent. If set to nil or empty string,
// then omit it. Otherwise if not mentioned,
@@ -8074,7 +8170,7 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
if vv[0] == "" {
continue
}
- } else if strings.EqualFold(k, "cookie") {
+ } else if http2asciiEqualFold(k, "cookie") {
// Per 8.1.2.5 To allow for better compression efficiency, the
// Cookie header field MAY be split into separate header fields,
// each with one or more cookie-pairs.
@@ -8133,7 +8229,12 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
// Header list size is ok. Write the headers.
enumerateHeaders(func(name, value string) {
- name = strings.ToLower(name)
+ name, ascii := http2asciiToLower(name)
+ if !ascii {
+ // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
+ // field names have to be ASCII characters (just as in HTTP/1.x).
+ return
+ }
cc.writeHeader(name, value)
if traceHeaders {
http2traceWroteHeaderField(trace, name, value)
@@ -8181,9 +8282,14 @@ func (cc *http2ClientConn) encodeTrailers(req *Request) ([]byte, error) {
}
for k, vv := range req.Trailer {
+ lowKey, ascii := http2asciiToLower(k)
+ if !ascii {
+ // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
+ // field names have to be ASCII characters (just as in HTTP/1.x).
+ continue
+ }
// Transfer-Encoding, etc.. have already been filtered at the
// start of RoundTrip
- lowKey := strings.ToLower(k)
for _, v := range vv {
cc.writeHeader(lowKey, v)
}
@@ -9606,7 +9712,12 @@ func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
}
for _, k := range keys {
vv := h[k]
- k = http2lowerHeader(k)
+ k, ascii := http2lowerHeader(k)
+ if !ascii {
+ // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
+ // field names have to be ASCII characters (just as in HTTP/1.x).
+ continue
+ }
if !http2validWireHeaderFieldName(k) {
// Skip it as backup paranoia. Per
// golang.org/issue/14048, these should
diff --git a/libgo/go/net/http/header.go b/libgo/go/net/http/header.go
index b9b5391..4c72dcb 100644
--- a/libgo/go/net/http/header.go
+++ b/libgo/go/net/http/header.go
@@ -7,6 +7,7 @@ package http
import (
"io"
"net/http/httptrace"
+ "net/http/internal/ascii"
"net/textproto"
"sort"
"strings"
@@ -251,7 +252,7 @@ func hasToken(v, token string) bool {
if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
continue
}
- if strings.EqualFold(v[sp:sp+len(token)], token) {
+ if ascii.EqualFold(v[sp:sp+len(token)], token) {
return true
}
}
diff --git a/libgo/go/net/http/http.go b/libgo/go/net/http/http.go
index 4c5054b..101799f 100644
--- a/libgo/go/net/http/http.go
+++ b/libgo/go/net/http/http.go
@@ -62,15 +62,6 @@ func isNotToken(r rune) bool {
return !httpguts.IsTokenRune(r)
}
-func isASCII(s string) bool {
- for i := 0; i < len(s); i++ {
- if s[i] >= utf8.RuneSelf {
- return false
- }
- }
- return true
-}
-
// stringContainsCTLByte reports whether s contains any ASCII control character.
func stringContainsCTLByte(s string) bool {
for i := 0; i < len(s); i++ {
diff --git a/libgo/go/net/http/http_test.go b/libgo/go/net/http/http_test.go
index 3f1d7ce..0d92fe5 100644
--- a/libgo/go/net/http/http_test.go
+++ b/libgo/go/net/http/http_test.go
@@ -9,9 +9,13 @@ package http
import (
"bytes"
"internal/testenv"
+ "io/fs"
"net/url"
+ "os"
"os/exec"
"reflect"
+ "regexp"
+ "strings"
"testing"
)
@@ -156,3 +160,61 @@ func BenchmarkCopyValues(b *testing.B) {
b.Fatal("Benchmark wasn't run")
}
}
+
+var forbiddenStringsFunctions = map[string]bool{
+ // Functions that use Unicode-aware case folding.
+ "EqualFold": true,
+ "Title": true,
+ "ToLower": true,
+ "ToLowerSpecial": true,
+ "ToTitle": true,
+ "ToTitleSpecial": true,
+ "ToUpper": true,
+ "ToUpperSpecial": true,
+
+ // Functions that use Unicode-aware spaces.
+ "Fields": true,
+ "TrimSpace": true,
+}
+
+// TestNoUnicodeStrings checks that nothing in net/http uses the Unicode-aware
+// strings and bytes package functions. HTTP is mostly ASCII based, and doing
+// Unicode-aware case folding or space stripping can introduce vulnerabilities.
+func TestNoUnicodeStrings(t *testing.T) {
+ if !testenv.HasSrc() {
+ t.Skip("source code not available")
+ }
+
+ re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`)
+ if err := fs.WalkDir(os.DirFS("."), ".", func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if path == "internal/ascii" {
+ return fs.SkipDir
+ }
+ if !strings.HasSuffix(path, ".go") ||
+ strings.HasSuffix(path, "_test.go") ||
+ path == "h2_bundle.go" || d.IsDir() {
+ return nil
+ }
+
+ contents, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for lineNum, line := range strings.Split(string(contents), "\n") {
+ for _, match := range re.FindAllStringSubmatch(line, -1) {
+ if !forbiddenStringsFunctions[match[2]] {
+ continue
+ }
+ t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1)
+ }
+ }
+
+ return nil
+ }); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/libgo/go/net/http/httptest/recorder.go b/libgo/go/net/http/httptest/recorder.go
index 2428482..1b712ef 100644
--- a/libgo/go/net/http/httptest/recorder.go
+++ b/libgo/go/net/http/httptest/recorder.go
@@ -122,11 +122,30 @@ func (rw *ResponseRecorder) WriteString(str string) (int, error) {
return len(str), nil
}
+func checkWriteHeaderCode(code int) {
+ // Issue 22880: require valid WriteHeader status codes.
+ // For now we only enforce that it's three digits.
+ // In the future we might block things over 599 (600 and above aren't defined
+ // at https://httpwg.org/specs/rfc7231.html#status.codes)
+ // and we might block under 200 (once we have more mature 1xx support).
+ // But for now any three digits.
+ //
+ // We used to send "HTTP/1.1 000 0" on the wire in responses but there's
+ // no equivalent bogus thing we can realistically send in HTTP/2,
+ // so we'll consistently panic instead and help people find their bugs
+ // early. (We can't return an error from WriteHeader even if we wanted to.)
+ if code < 100 || code > 999 {
+ panic(fmt.Sprintf("invalid WriteHeader code %v", code))
+ }
+}
+
// WriteHeader implements http.ResponseWriter.
func (rw *ResponseRecorder) WriteHeader(code int) {
if rw.wroteHeader {
return
}
+
+ checkWriteHeaderCode(code)
rw.Code = code
rw.wroteHeader = true
if rw.HeaderMap == nil {
diff --git a/libgo/go/net/http/httptest/recorder_test.go b/libgo/go/net/http/httptest/recorder_test.go
index a865e87..8cb32dd 100644
--- a/libgo/go/net/http/httptest/recorder_test.go
+++ b/libgo/go/net/http/httptest/recorder_test.go
@@ -345,3 +345,28 @@ func TestParseContentLength(t *testing.T) {
}
}
}
+
+// Ensure that httptest.Recorder panics when given a non-3 digit (XXX)
+// status HTTP code. See https://golang.org/issues/45353
+func TestRecorderPanicsOnNonXXXStatusCode(t *testing.T) {
+ badCodes := []int{
+ -100, 0, 99, 1000, 20000,
+ }
+ for _, badCode := range badCodes {
+ badCode := badCode
+ t.Run(fmt.Sprintf("Code=%d", badCode), func(t *testing.T) {
+ defer func() {
+ if r := recover(); r == nil {
+ t.Fatal("Expected a panic")
+ }
+ }()
+
+ handler := func(rw http.ResponseWriter, _ *http.Request) {
+ rw.WriteHeader(badCode)
+ }
+ r, _ := http.NewRequest("GET", "http://example.org/", nil)
+ rw := NewRecorder()
+ handler(rw, r)
+ })
+ }
+}
diff --git a/libgo/go/net/http/httptest/server.go b/libgo/go/net/http/httptest/server.go
index 8ebf681..a9faa9a 100644
--- a/libgo/go/net/http/httptest/server.go
+++ b/libgo/go/net/http/httptest/server.go
@@ -14,7 +14,7 @@ import (
"log"
"net"
"net/http"
- "net/http/internal"
+ "net/http/internal/testcert"
"os"
"strings"
"sync"
@@ -144,7 +144,7 @@ func (s *Server) StartTLS() {
if s.client == nil {
s.client = &http.Client{Transport: &http.Transport{}}
}
- cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+ cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
if err != nil {
panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
}
@@ -316,6 +316,13 @@ func (s *Server) wrap() {
s.Config.ConnState = func(c net.Conn, cs http.ConnState) {
s.mu.Lock()
defer s.mu.Unlock()
+
+ // Keep Close from returning until the user's ConnState hook
+ // (if any) finishes. Without this, the call to forgetConn
+ // below might send the count to 0 before we run the hook.
+ s.wg.Add(1)
+ defer s.wg.Done()
+
switch cs {
case http.StateNew:
s.wg.Add(1)
diff --git a/libgo/go/net/http/httptrace/trace.go b/libgo/go/net/http/httptrace/trace.go
index 6a5cbac..5777c91 100644
--- a/libgo/go/net/http/httptrace/trace.go
+++ b/libgo/go/net/http/httptrace/trace.go
@@ -127,7 +127,7 @@ type ClientTrace struct {
// ConnectDone is called when a new connection's Dial
// completes. The provided err indicates whether the
- // connection completedly successfully.
+ // connection completed successfully.
// If net.Dialer.DualStack ("Happy Eyeballs") support is
// enabled, this may be called multiple times.
ConnectDone func(network, addr string, err error)
diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go
index 8168b2e..366cc82 100644
--- a/libgo/go/net/http/httputil/dump_test.go
+++ b/libgo/go/net/http/httputil/dump_test.go
@@ -478,7 +478,7 @@ func TestDumpResponse(t *testing.T) {
}
}
-// Issue 38352: Check for deadlock on cancelled requests.
+// Issue 38352: Check for deadlock on canceled requests.
func TestDumpRequestOutIssue38352(t *testing.T) {
if testing.Short() {
return
diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go
index ccb8456..8b63368 100644
--- a/libgo/go/net/http/httputil/reverseproxy.go
+++ b/libgo/go/net/http/httputil/reverseproxy.go
@@ -13,6 +13,7 @@ import (
"log"
"net"
"net/http"
+ "net/http/internal/ascii"
"net/textproto"
"net/url"
"strings"
@@ -234,6 +235,15 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if req.ContentLength == 0 {
outreq.Body = nil // Issue 16036: nil Body for http.Transport retries
}
+ if outreq.Body != nil {
+ // Reading from the request body after returning from a handler is not
+ // allowed, and the RoundTrip goroutine that reads the Body can outlive
+ // this handler. This can lead to a crash if the handler panics (see
+ // Issue 46866). Although calling Close doesn't guarantee there isn't
+ // any Read in flight after the handle returns, in practice it's safe to
+ // read after closing it.
+ defer outreq.Body.Close()
+ }
if outreq.Header == nil {
outreq.Header = make(http.Header) // Issue 33142: historical behavior was to always allocate
}
@@ -242,6 +252,10 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
outreq.Close = false
reqUpType := upgradeType(outreq.Header)
+ if !ascii.IsPrint(reqUpType) {
+ p.getErrorHandler()(rw, req, fmt.Errorf("client tried to switch to invalid protocol %q", reqUpType))
+ return
+ }
removeConnectionHeaders(outreq.Header)
// Remove hop-by-hop headers to the backend. Especially
@@ -534,13 +548,16 @@ func upgradeType(h http.Header) string {
if !httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade") {
return ""
}
- return strings.ToLower(h.Get("Upgrade"))
+ return h.Get("Upgrade")
}
func (p *ReverseProxy) handleUpgradeResponse(rw http.ResponseWriter, req *http.Request, res *http.Response) {
reqUpType := upgradeType(req.Header)
resUpType := upgradeType(res.Header)
- if reqUpType != resUpType {
+ if !ascii.IsPrint(resUpType) { // We know reqUpType is ASCII, it's checked by the caller.
+ p.getErrorHandler()(rw, req, fmt.Errorf("backend tried to switch to invalid protocol %q", resUpType))
+ }
+ if !ascii.EqualFold(reqUpType, resUpType) {
p.getErrorHandler()(rw, req, fmt.Errorf("backend tried to switch protocol %q when %q was requested", resUpType, reqUpType))
return
}
@@ -558,7 +575,7 @@ func (p *ReverseProxy) handleUpgradeResponse(rw http.ResponseWriter, req *http.R
backConnCloseCh := make(chan bool)
go func() {
- // Ensure that the cancelation of a request closes the backend.
+ // Ensure that the cancellation of a request closes the backend.
// See issue https://golang.org/issue/35559.
select {
case <-req.Context().Done():
diff --git a/libgo/go/net/http/httputil/reverseproxy_test.go b/libgo/go/net/http/httputil/reverseproxy_test.go
index 3211463..4b6ad77 100644
--- a/libgo/go/net/http/httputil/reverseproxy_test.go
+++ b/libgo/go/net/http/httputil/reverseproxy_test.go
@@ -16,6 +16,7 @@ import (
"log"
"net/http"
"net/http/httptest"
+ "net/http/internal/ascii"
"net/url"
"os"
"reflect"
@@ -1121,6 +1122,45 @@ func TestReverseProxy_PanicBodyError(t *testing.T) {
rproxy.ServeHTTP(httptest.NewRecorder(), req)
}
+// Issue #46866: panic without closing incoming request body causes a panic
+func TestReverseProxy_PanicClosesIncomingBody(t *testing.T) {
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ out := "this call was relayed by the reverse proxy"
+ // Coerce a wrong content length to induce io.ErrUnexpectedEOF
+ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(out)*2))
+ fmt.Fprintln(w, out)
+ }))
+ defer backend.Close()
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests
+ frontend := httptest.NewServer(proxyHandler)
+ defer frontend.Close()
+ frontendClient := frontend.Client()
+
+ var wg sync.WaitGroup
+ for i := 0; i < 2; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for j := 0; j < 10; j++ {
+ const reqLen = 6 * 1024 * 1024
+ req, _ := http.NewRequest("POST", frontend.URL, &io.LimitedReader{R: neverEnding('x'), N: reqLen})
+ req.ContentLength = reqLen
+ resp, _ := frontendClient.Transport.RoundTrip(req)
+ if resp != nil {
+ io.Copy(io.Discard, resp.Body)
+ resp.Body.Close()
+ }
+ }
+ }()
+ }
+ wg.Wait()
+}
+
func TestSelectFlushInterval(t *testing.T) {
tests := []struct {
name string
@@ -1242,7 +1282,7 @@ func TestReverseProxyWebSocket(t *testing.T) {
t.Errorf("Header(XHeader) = %q; want %q", got, want)
}
- if upgradeType(res.Header) != "websocket" {
+ if !ascii.EqualFold(upgradeType(res.Header), "websocket") {
t.Fatalf("not websocket upgrade; got %#v", res.Header)
}
rwc, ok := res.Body.(io.ReadWriteCloser)
@@ -1267,7 +1307,7 @@ func TestReverseProxyWebSocket(t *testing.T) {
}
}
-func TestReverseProxyWebSocketCancelation(t *testing.T) {
+func TestReverseProxyWebSocketCancellation(t *testing.T) {
n := 5
triggerCancelCh := make(chan bool, n)
nthResponse := func(i int) string {
@@ -1359,7 +1399,7 @@ func TestReverseProxyWebSocketCancelation(t *testing.T) {
t.Errorf("X-Header mismatch\n\tgot: %q\n\twant: %q", g, w)
}
- if g, w := upgradeType(res.Header), "websocket"; g != w {
+ if g, w := upgradeType(res.Header), "websocket"; !ascii.EqualFold(g, w) {
t.Fatalf("Upgrade header mismatch\n\tgot: %q\n\twant: %q", g, w)
}
diff --git a/libgo/go/net/http/internal/ascii/print.go b/libgo/go/net/http/internal/ascii/print.go
new file mode 100644
index 0000000..585e5ba
--- /dev/null
+++ b/libgo/go/net/http/internal/ascii/print.go
@@ -0,0 +1,61 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ascii
+
+import (
+ "strings"
+ "unicode"
+)
+
+// EqualFold is strings.EqualFold, ASCII only. It reports whether s and t
+// are equal, ASCII-case-insensitively.
+func EqualFold(s, t string) bool {
+ if len(s) != len(t) {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if lower(s[i]) != lower(t[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// lower returns the ASCII lowercase version of b.
+func lower(b byte) byte {
+ if 'A' <= b && b <= 'Z' {
+ return b + ('a' - 'A')
+ }
+ return b
+}
+
+// IsPrint returns whether s is ASCII and printable according to
+// https://tools.ietf.org/html/rfc20#section-4.2.
+func IsPrint(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] < ' ' || s[i] > '~' {
+ return false
+ }
+ }
+ return true
+}
+
+// Is returns whether s is ASCII.
+func Is(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] > unicode.MaxASCII {
+ return false
+ }
+ }
+ return true
+}
+
+// ToLower returns the lowercase version of s if s is ASCII and printable.
+func ToLower(s string) (lower string, ok bool) {
+ if !IsPrint(s) {
+ return "", false
+ }
+ return strings.ToLower(s), true
+}
diff --git a/libgo/go/net/http/internal/ascii/print_test.go b/libgo/go/net/http/internal/ascii/print_test.go
new file mode 100644
index 0000000..0b7767ca
--- /dev/null
+++ b/libgo/go/net/http/internal/ascii/print_test.go
@@ -0,0 +1,95 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ascii
+
+import "testing"
+
+func TestEqualFold(t *testing.T) {
+ var tests = []struct {
+ name string
+ a, b string
+ want bool
+ }{
+ {
+ name: "empty",
+ want: true,
+ },
+ {
+ name: "simple match",
+ a: "CHUNKED",
+ b: "chunked",
+ want: true,
+ },
+ {
+ name: "same string",
+ a: "chunked",
+ b: "chunked",
+ want: true,
+ },
+ {
+ name: "Unicode Kelvin symbol",
+ a: "chunKed", // This "K" is 'KELVIN SIGN' (\u212A)
+ b: "chunked",
+ want: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := EqualFold(tt.a, tt.b); got != tt.want {
+ t.Errorf("AsciiEqualFold(%q,%q): got %v want %v", tt.a, tt.b, got, tt.want)
+ }
+ })
+ }
+}
+
+func TestIsPrint(t *testing.T) {
+ var tests = []struct {
+ name string
+ in string
+ want bool
+ }{
+ {
+ name: "empty",
+ want: true,
+ },
+ {
+ name: "ASCII low",
+ in: "This is a space: ' '",
+ want: true,
+ },
+ {
+ name: "ASCII high",
+ in: "This is a tilde: '~'",
+ want: true,
+ },
+ {
+ name: "ASCII low non-print",
+ in: "This is a unit separator: \x1F",
+ want: false,
+ },
+ {
+ name: "Ascii high non-print",
+ in: "This is a Delete: \x7F",
+ want: false,
+ },
+ {
+ name: "Unicode letter",
+ in: "Today it's 280K outside: it's freezing!", // This "K" is 'KELVIN SIGN' (\u212A)
+ want: false,
+ },
+ {
+ name: "Unicode emoji",
+ in: "Gophers like 🧀",
+ want: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := IsPrint(tt.in); got != tt.want {
+ t.Errorf("IsASCIIPrint(%q): got %v want %v", tt.in, got, tt.want)
+ }
+ })
+ }
+}
diff --git a/libgo/go/net/http/internal/testcert.go b/libgo/go/net/http/internal/testcert/testcert.go
index 2284a83..5f94704 100644
--- a/libgo/go/net/http/internal/testcert.go
+++ b/libgo/go/net/http/internal/testcert/testcert.go
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package internal
+// Package testcert contains a test-only localhost certificate.
+package testcert
import "strings"
@@ -25,7 +26,7 @@ h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
fblo6RBxUQ==
-----END CERTIFICATE-----`)
-// LocalhostKey is the private key for localhostCert.
+// LocalhostKey is the private key for LocalhostCert.
var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
diff --git a/libgo/go/net/http/omithttp2.go b/libgo/go/net/http/omithttp2.go
index 30c6e48..79599d0 100644
--- a/libgo/go/net/http/omithttp2.go
+++ b/libgo/go/net/http/omithttp2.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build nethttpomithttp2
// +build nethttpomithttp2
package http
diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go
index 5389a38..888ea35 100644
--- a/libgo/go/net/http/pprof/pprof.go
+++ b/libgo/go/net/http/pprof/pprof.go
@@ -287,7 +287,7 @@ func (name handler) serveDeltaProfile(w http.ResponseWriter, r *http.Request, p
err := r.Context().Err()
if err == context.DeadlineExceeded {
serveError(w, http.StatusRequestTimeout, err.Error())
- } else { // TODO: what's a good status code for cancelled requests? 400?
+ } else { // TODO: what's a good status code for canceled requests? 400?
serveError(w, http.StatusInternalServerError, err.Error())
}
return
@@ -431,7 +431,7 @@ Types of profiles available:
b.WriteString(`</table>
<a href="goroutine?debug=2">full goroutine stack dump</a>
-<br/>
+<br>
<p>
Profile Descriptions:
<ul>
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go
index adba540..09cb0c7 100644
--- a/libgo/go/net/http/request.go
+++ b/libgo/go/net/http/request.go
@@ -19,6 +19,7 @@ import (
"mime/multipart"
"net"
"net/http/httptrace"
+ "net/http/internal/ascii"
"net/textproto"
"net/url"
urlpkg "net/url"
@@ -723,7 +724,7 @@ func idnaASCII(v string) (string, error) {
// version does not.
// Note that for correct ASCII IDNs ToASCII will only do considerably more
// work, but it will not cause an allocation.
- if isASCII(v) {
+ if ascii.Is(v) {
return v, nil
}
return idna.Lookup.ToASCII(v)
@@ -779,7 +780,8 @@ func removeZone(host string) string {
}
// ParseHTTPVersion parses an HTTP version string.
-// "HTTP/1.0" returns (1, 0, true).
+// "HTTP/1.0" returns (1, 0, true). Note that strings without
+// a minor version, such as "HTTP/2", are not valid.
func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
const Big = 1000000 // arbitrary upper bound
switch vers {
@@ -823,7 +825,7 @@ func validMethod(method string) bool {
return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1
}
-// NewRequest wraps NewRequestWithContext using the background context.
+// NewRequest wraps NewRequestWithContext using context.Background.
func NewRequest(method, url string, body io.Reader) (*Request, error) {
return NewRequestWithContext(context.Background(), method, url, body)
}
@@ -947,7 +949,7 @@ func (r *Request) BasicAuth() (username, password string, ok bool) {
func parseBasicAuth(auth string) (username, password string, ok bool) {
const prefix = "Basic "
// Case insensitive prefix match. See Issue 22736.
- if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) {
+ if len(auth) < len(prefix) || !ascii.EqualFold(auth[:len(prefix)], prefix) {
return
}
c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
@@ -1009,16 +1011,16 @@ func putTextprotoReader(r *textproto.Reader) {
// requests and handle them via the Handler interface. ReadRequest
// only supports HTTP/1.x requests. For HTTP/2, use golang.org/x/net/http2.
func ReadRequest(b *bufio.Reader) (*Request, error) {
- return readRequest(b, deleteHostHeader)
-}
+ req, err := readRequest(b)
+ if err != nil {
+ return nil, err
+ }
-// Constants for readRequest's deleteHostHeader parameter.
-const (
- deleteHostHeader = true
- keepHostHeader = false
-)
+ delete(req.Header, "Host")
+ return req, err
+}
-func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err error) {
+func readRequest(b *bufio.Reader) (req *Request, err error) {
tp := newTextprotoReader(b)
req = new(Request)
@@ -1076,6 +1078,9 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
return nil, err
}
req.Header = Header(mimeHeader)
+ if len(req.Header["Host"]) > 1 {
+ return nil, fmt.Errorf("too many Host headers")
+ }
// RFC 7230, section 5.3: Must treat
// GET /index.html HTTP/1.1
@@ -1088,9 +1093,6 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
if req.Host == "" {
req.Host = req.Header.get("Host")
}
- if deleteHostHeader {
- delete(req.Header, "Host")
- }
fixPragmaCacheControl(req.Header)
@@ -1123,6 +1125,9 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
// MaxBytesReader prevents clients from accidentally or maliciously
// sending a large request and wasting server resources.
func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser {
+ if n < 0 { // Treat negative limits as equivalent to 0.
+ n = 0
+ }
return &maxBytesReader{w: w, r: r, n: n}
}
@@ -1288,16 +1293,18 @@ func (r *Request) ParseForm() error {
// its file parts are stored in memory, with the remainder stored on
// disk in temporary files.
// ParseMultipartForm calls ParseForm if necessary.
+// If ParseForm returns an error, ParseMultipartForm returns it but also
+// continues parsing the request body.
// After one call to ParseMultipartForm, subsequent calls have no effect.
func (r *Request) ParseMultipartForm(maxMemory int64) error {
if r.MultipartForm == multipartByReader {
return errors.New("http: multipart handled by MultipartReader")
}
+ var parseFormErr error
if r.Form == nil {
- err := r.ParseForm()
- if err != nil {
- return err
- }
+ // Let errors in ParseForm fall through, and just
+ // return it at the end.
+ parseFormErr = r.ParseForm()
}
if r.MultipartForm != nil {
return nil
@@ -1324,7 +1331,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
r.MultipartForm = f
- return nil
+ return parseFormErr
}
// FormValue returns the first value for the named component of the query.
@@ -1452,5 +1459,5 @@ func requestMethodUsuallyLacksBody(method string) bool {
// an HTTP/1 connection.
func (r *Request) requiresHTTP1() bool {
return hasToken(r.Header.Get("Connection"), "upgrade") &&
- strings.EqualFold(r.Header.Get("Upgrade"), "websocket")
+ ascii.EqualFold(r.Header.Get("Upgrade"), "websocket")
}
diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go
index 29297b0..4e0c4ba 100644
--- a/libgo/go/net/http/request_test.go
+++ b/libgo/go/net/http/request_test.go
@@ -32,9 +32,26 @@ func TestQuery(t *testing.T) {
}
}
+// Issue #25192: Test that ParseForm fails but still parses the form when an URL
+// containing a semicolon is provided.
+func TestParseFormSemicolonSeparator(t *testing.T) {
+ for _, method := range []string{"POST", "PATCH", "PUT", "GET"} {
+ req, _ := NewRequest(method, "http://www.google.com/search?q=foo;q=bar&a=1",
+ strings.NewReader("q"))
+ err := req.ParseForm()
+ if err == nil {
+ t.Fatalf(`for method %s, ParseForm expected an error, got success`, method)
+ }
+ wantForm := url.Values{"a": []string{"1"}}
+ if !reflect.DeepEqual(req.Form, wantForm) {
+ t.Fatalf("for method %s, ParseForm expected req.Form = %v, want %v", method, req.Form, wantForm)
+ }
+ }
+}
+
func TestParseFormQuery(t *testing.T) {
req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&orphan=nope&empty=not",
- strings.NewReader("z=post&both=y&prio=2&=nokey&orphan;empty=&"))
+ strings.NewReader("z=post&both=y&prio=2&=nokey&orphan&empty=&"))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
if q := req.FormValue("q"); q != "foo" {
@@ -245,6 +262,29 @@ func TestParseMultipartForm(t *testing.T) {
}
}
+// Issue 45789: multipart form should not include directory path in filename
+func TestParseMultipartFormFilename(t *testing.T) {
+ postData :=
+ `--xxx
+Content-Disposition: form-data; name="file"; filename="../usr/foobar.txt/"
+Content-Type: text/plain
+
+--xxx--
+`
+ req := &Request{
+ Method: "POST",
+ Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
+ Body: io.NopCloser(strings.NewReader(postData)),
+ }
+ _, hdr, err := req.FormFile("file")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if hdr.Filename != "foobar.txt" {
+ t.Errorf("expected only the last element of the path, got %q", hdr.Filename)
+ }
+}
+
// Issue #40430: Test that if maxMemory for ParseMultipartForm when combined with
// the payload size and the internal leeway buffer size of 10MiB overflows, that we
// correctly return an error.
@@ -342,6 +382,18 @@ func TestMultipartRequest(t *testing.T) {
validateTestMultipartContents(t, req, false)
}
+// Issue #25192: Test that ParseMultipartForm fails but still parses the
+// multi-part form when an URL containing a semicolon is provided.
+func TestParseMultipartFormSemicolonSeparator(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ req.URL = &url.URL{RawQuery: "q=foo;q=bar"}
+ if err := req.ParseMultipartForm(25); err == nil {
+ t.Fatal("ParseMultipartForm expected error due to invalid semicolon, got nil")
+ }
+ defer req.MultipartForm.RemoveAll()
+ validateTestMultipartContents(t, req, false)
+}
+
func TestMultipartRequestAuto(t *testing.T) {
// Test that FormValue and FormFile automatically invoke
// ParseMultipartForm and return the right values.
@@ -469,6 +521,10 @@ var readRequestErrorTests = []struct {
in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
header: Header{"Content-Length": {"0"}},
},
+ 11: {
+ in: "HEAD / HTTP/1.1\r\nHost: foo\r\nHost: bar\r\n\r\n\r\n\r\n",
+ err: "too many Host headers",
+ },
}
func TestReadRequestErrors(t *testing.T) {
@@ -850,6 +906,92 @@ func TestMaxBytesReaderStickyError(t *testing.T) {
}
}
+// Issue 45101: maxBytesReader's Read panicked when n < -1. This test
+// also ensures that Read treats negative limits as equivalent to 0.
+func TestMaxBytesReaderDifferentLimits(t *testing.T) {
+ const testStr = "1234"
+ tests := [...]struct {
+ limit int64
+ lenP int
+ wantN int
+ wantErr bool
+ }{
+ 0: {
+ limit: -123,
+ lenP: 0,
+ wantN: 0,
+ wantErr: false, // Ensure we won't return an error when the limit is negative, but we don't need to read.
+ },
+ 1: {
+ limit: -100,
+ lenP: 32 * 1024,
+ wantN: 0,
+ wantErr: true,
+ },
+ 2: {
+ limit: -2,
+ lenP: 1,
+ wantN: 0,
+ wantErr: true,
+ },
+ 3: {
+ limit: -1,
+ lenP: 2,
+ wantN: 0,
+ wantErr: true,
+ },
+ 4: {
+ limit: 0,
+ lenP: 3,
+ wantN: 0,
+ wantErr: true,
+ },
+ 5: {
+ limit: 1,
+ lenP: 4,
+ wantN: 1,
+ wantErr: true,
+ },
+ 6: {
+ limit: 2,
+ lenP: 5,
+ wantN: 2,
+ wantErr: true,
+ },
+ 7: {
+ limit: 3,
+ lenP: 2,
+ wantN: 2,
+ wantErr: false,
+ },
+ 8: {
+ limit: int64(len(testStr)),
+ lenP: len(testStr),
+ wantN: len(testStr),
+ wantErr: false,
+ },
+ 9: {
+ limit: 100,
+ lenP: 6,
+ wantN: len(testStr),
+ wantErr: false,
+ },
+ }
+ for i, tt := range tests {
+ rc := MaxBytesReader(nil, io.NopCloser(strings.NewReader(testStr)), tt.limit)
+
+ n, err := rc.Read(make([]byte, tt.lenP))
+
+ if n != tt.wantN {
+ t.Errorf("%d. n: %d, want n: %d", i, n, tt.wantN)
+ }
+
+ if (err != nil) != tt.wantErr {
+ t.Errorf("%d. error: %v", i, err)
+ }
+ }
+}
+
func TestWithContextDeepCopiesURL(t *testing.T) {
req, err := NewRequest("POST", "https://golang.org/", nil)
if err != nil {
diff --git a/libgo/go/net/http/roundtrip.go b/libgo/go/net/http/roundtrip.go
index 2ec736b..eef7c79 100644
--- a/libgo/go/net/http/roundtrip.go
+++ b/libgo/go/net/http/roundtrip.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js || !wasm
// +build !js !wasm
package http
diff --git a/libgo/go/net/http/roundtrip_js.go b/libgo/go/net/http/roundtrip_js.go
index c6a221a..74c83a9 100644
--- a/libgo/go/net/http/roundtrip_js.go
+++ b/libgo/go/net/http/roundtrip_js.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build js && wasm
// +build js,wasm
package http
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index f868741..6394da3 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -25,6 +25,7 @@ import (
"net/http/httptest"
"net/http/httputil"
"net/http/internal"
+ "net/http/internal/testcert"
"net/url"
"os"
"os/exec"
@@ -1475,7 +1476,7 @@ func TestServeTLS(t *testing.T) {
defer afterTest(t)
defer SetTestHookServerServe(nil)
- cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+ cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
if err != nil {
t.Fatal(err)
}
@@ -1599,7 +1600,7 @@ func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) {
}
func TestAutomaticHTTP2_ListenAndServe(t *testing.T) {
- cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+ cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
if err != nil {
t.Fatal(err)
}
@@ -1609,7 +1610,7 @@ func TestAutomaticHTTP2_ListenAndServe(t *testing.T) {
}
func TestAutomaticHTTP2_ListenAndServe_GetCertificate(t *testing.T) {
- cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+ cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
if err != nil {
t.Fatal(err)
}
@@ -6507,3 +6508,104 @@ func TestDisableKeepAliveUpgrade(t *testing.T) {
t.Fatalf("unexpected value read from body:\ngot: %q\nwant: %q", b, "hello")
}
}
+
+func TestMuxRedirectRelative(t *testing.T) {
+ setParallel(t)
+ req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET http://example.com HTTP/1.1\r\nHost: test\r\n\r\n")))
+ if err != nil {
+ t.Errorf("%s", err)
+ }
+ mux := NewServeMux()
+ resp := httptest.NewRecorder()
+ mux.ServeHTTP(resp, req)
+ if got, want := resp.Header().Get("Location"), "/"; got != want {
+ t.Errorf("Location header expected %q; got %q", want, got)
+ }
+ if got, want := resp.Code, StatusMovedPermanently; got != want {
+ t.Errorf("Expected response code %d; got %d", want, got)
+ }
+}
+
+// TestQuerySemicolon tests the behavior of semicolons in queries. See Issue 25192.
+func TestQuerySemicolon(t *testing.T) {
+ t.Cleanup(func() { afterTest(t) })
+
+ tests := []struct {
+ query string
+ xNoSemicolons string
+ xWithSemicolons string
+ warning bool
+ }{
+ {"?a=1;x=bad&x=good", "good", "bad", true},
+ {"?a=1;b=bad&x=good", "good", "good", true},
+ {"?a=1%3Bx=bad&x=good%3B", "good;", "good;", false},
+ {"?a=1;x=good;x=bad", "", "good", true},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.query+"/allow=false", func(t *testing.T) {
+ allowSemicolons := false
+ testQuerySemicolon(t, tt.query, tt.xNoSemicolons, allowSemicolons, tt.warning)
+ })
+ t.Run(tt.query+"/allow=true", func(t *testing.T) {
+ allowSemicolons, expectWarning := true, false
+ testQuerySemicolon(t, tt.query, tt.xWithSemicolons, allowSemicolons, expectWarning)
+ })
+ }
+}
+
+func testQuerySemicolon(t *testing.T, query string, wantX string, allowSemicolons, expectWarning bool) {
+ setParallel(t)
+
+ writeBackX := func(w ResponseWriter, r *Request) {
+ x := r.URL.Query().Get("x")
+ if expectWarning {
+ if err := r.ParseForm(); err == nil || !strings.Contains(err.Error(), "semicolon") {
+ t.Errorf("expected error mentioning semicolons from ParseForm, got %v", err)
+ }
+ } else {
+ if err := r.ParseForm(); err != nil {
+ t.Errorf("expected no error from ParseForm, got %v", err)
+ }
+ }
+ if got := r.FormValue("x"); x != got {
+ t.Errorf("got %q from FormValue, want %q", got, x)
+ }
+ fmt.Fprintf(w, "%s", x)
+ }
+
+ h := Handler(HandlerFunc(writeBackX))
+ if allowSemicolons {
+ h = AllowQuerySemicolons(h)
+ }
+
+ ts := httptest.NewUnstartedServer(h)
+ logBuf := &bytes.Buffer{}
+ ts.Config.ErrorLog = log.New(logBuf, "", 0)
+ ts.Start()
+ defer ts.Close()
+
+ req, _ := NewRequest("GET", ts.URL+query, nil)
+ res, err := ts.Client().Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ slurp, _ := io.ReadAll(res.Body)
+ res.Body.Close()
+ if got, want := res.StatusCode, 200; got != want {
+ t.Errorf("Status = %d; want = %d", got, want)
+ }
+ if got, want := string(slurp), wantX; got != want {
+ t.Errorf("Body = %q; want = %q", got, want)
+ }
+
+ if expectWarning {
+ if !strings.Contains(logBuf.String(), "semicolon") {
+ t.Errorf("got %q from ErrorLog, expected a mention of semicolons", logBuf.String())
+ }
+ } else {
+ if strings.Contains(logBuf.String(), "semicolon") {
+ t.Errorf("got %q from ErrorLog, expected no mention of semicolons", logBuf.String())
+ }
+ }
+}
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index 33aadd6..ce39933 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -333,7 +333,7 @@ func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
const bufferBeforeChunkingSize = 2048
// chunkWriter writes to a response's conn buffer, and is the writer
-// wrapped by the response.bufw buffered writer.
+// wrapped by the response.w buffered writer.
//
// chunkWriter also is responsible for finalizing the Header, including
// conditionally setting the Content-Type and setting a Content-Length
@@ -577,37 +577,17 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
return io.CopyBuffer(writerOnly{w}, src, buf)
}
- // sendfile path:
-
- // Do not start actually writing response until src is readable.
- // If body length is <= sniffLen, sendfile/splice path will do
- // little anyway. This small read also satisfies sniffing the
- // body in case Content-Type is missing.
- nr, er := src.Read(buf[:sniffLen])
- atEOF := errors.Is(er, io.EOF)
- n += int64(nr)
-
- if nr > 0 {
- // Write the small amount read normally.
- nw, ew := w.Write(buf[:nr])
- if ew != nil {
- err = ew
- } else if nr != nw {
- err = io.ErrShortWrite
+ // Copy the first sniffLen bytes before switching to ReadFrom.
+ // This ensures we don't start writing the response before the
+ // source is available (see golang.org/issue/5660) and provides
+ // enough bytes to perform Content-Type sniffing when required.
+ if !w.cw.wroteHeader {
+ n0, err := io.CopyBuffer(writerOnly{w}, io.LimitReader(src, sniffLen), buf)
+ n += n0
+ if err != nil || n0 < sniffLen {
+ return n, err
}
}
- if err == nil && er != nil && !atEOF {
- err = er
- }
-
- // Do not send StatusOK in the error case where nothing has been written.
- if err == nil && !w.wroteHeader {
- w.WriteHeader(StatusOK) // nr == 0, no error (or EOF)
- }
-
- if err != nil || atEOF {
- return n, err
- }
w.w.Flush() // get rid of any previous writes
w.cw.flush() // make sure Header is written; flush data to rwc
@@ -620,7 +600,7 @@ func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
return n, err
}
- n0, err := io.Copy(writerOnly{w}, src)
+ n0, err := io.CopyBuffer(writerOnly{w}, src, buf)
n += n0
return n, err
}
@@ -964,14 +944,14 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
hdrDeadline time.Time // or zero if none
)
t0 := time.Now()
- if d := c.server.readHeaderTimeout(); d != 0 {
+ if d := c.server.readHeaderTimeout(); d > 0 {
hdrDeadline = t0.Add(d)
}
- if d := c.server.ReadTimeout; d != 0 {
+ if d := c.server.ReadTimeout; d > 0 {
wholeReqDeadline = t0.Add(d)
}
c.rwc.SetReadDeadline(hdrDeadline)
- if d := c.server.WriteTimeout; d != 0 {
+ if d := c.server.WriteTimeout; d > 0 {
defer func() {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}()
@@ -983,7 +963,7 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
c.bufr.Discard(numLeadingCRorLF(peek))
}
- req, err := readRequest(c.bufr, keepHostHeader)
+ req, err := readRequest(c.bufr)
if err != nil {
if c.r.hitReadLimit() {
return nil, errTooLarge
@@ -1003,9 +983,6 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade && req.Method != "CONNECT" {
return nil, badRequestError("missing required Host header")
}
- if len(hosts) > 1 {
- return nil, badRequestError("too many Host headers")
- }
if len(hosts) == 1 && !httpguts.ValidHostHeader(hosts[0]) {
return nil, badRequestError("malformed Host header")
}
@@ -1557,12 +1534,12 @@ func (w *response) bodyAllowed() bool {
// The Writers are wired together like:
//
// 1. *response (the ResponseWriter) ->
-// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes
+// 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes ->
// 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type)
-// and which writes the chunk headers, if needed.
-// 4. conn.buf, a bufio.Writer of default (4kB) bytes, writing to ->
+// and which writes the chunk headers, if needed ->
+// 4. conn.bufw, a *bufio.Writer of default (4kB) bytes, writing to ->
// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write
-// and populates c.werr with it if so. but otherwise writes to:
+// and populates c.werr with it if so, but otherwise writes to ->
// 6. the rwc, the net.Conn.
//
// TODO(bradfitz): short-circuit some of the buffering when the
@@ -1836,13 +1813,13 @@ func (c *conn) serve(ctx context.Context) {
}()
if tlsConn, ok := c.rwc.(*tls.Conn); ok {
- if d := c.server.ReadTimeout; d != 0 {
+ if d := c.server.ReadTimeout; d > 0 {
c.rwc.SetReadDeadline(time.Now().Add(d))
}
- if d := c.server.WriteTimeout; d != 0 {
+ if d := c.server.WriteTimeout; d > 0 {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}
- if err := tlsConn.Handshake(); err != nil {
+ if err := tlsConn.HandshakeContext(ctx); err != nil {
// If the handshake failed due to the client not speaking
// TLS, assume they're speaking plaintext HTTP and write a
// 400 response on the TLS conn's underlying net.Conn.
@@ -2412,9 +2389,8 @@ func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
if path != r.URL.Path {
_, pattern = mux.handler(host, path)
- url := *r.URL
- url.Path = path
- return RedirectHandler(url.String(), StatusMovedPermanently), pattern
+ u := &url.URL{Path: path, RawQuery: r.URL.RawQuery}
+ return RedirectHandler(u.String(), StatusMovedPermanently), pattern
}
return mux.handler(host, r.URL.Path)
@@ -2572,7 +2548,8 @@ type Server struct {
TLSConfig *tls.Config
// ReadTimeout is the maximum duration for reading the entire
- // request, including the body.
+ // request, including the body. A zero or negative value means
+ // there will be no timeout.
//
// Because ReadTimeout does not let Handlers make per-request
// decisions on each request body's acceptable deadline or
@@ -2592,6 +2569,7 @@ type Server struct {
// writes of the response. It is reset whenever a new
// request's header is read. Like ReadTimeout, it does not
// let Handlers make decisions on a per-request basis.
+ // A zero or negative value means there will be no timeout.
WriteTimeout time.Duration
// IdleTimeout is the maximum amount of time to wait for the
@@ -2643,7 +2621,7 @@ type Server struct {
// value.
ConnContext func(ctx context.Context, c net.Conn) context.Context
- inShutdown atomicBool // true when when server is in shutdown
+ inShutdown atomicBool // true when server is in shutdown
disableKeepAlives int32 // accessed atomically.
nextProtoOnce sync.Once // guards setupHTTP2_* init
@@ -2889,9 +2867,51 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
if req.RequestURI == "*" && req.Method == "OPTIONS" {
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.
+//
+// This restores the pre-Go 1.17 behavior of splitting query parameters on both
+// semicolons and ampersands. (See golang.org/issue/25192). Note that this
+// behavior doesn't match that of many proxies, and the mismatch can lead to
+// security issues.
+//
+// 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
+ r2.URL = new(url.URL)
+ *r2.URL = *r.URL
+ r2.URL.RawQuery = strings.ReplaceAll(r.URL.RawQuery, ";", "&")
+ h.ServeHTTP(w, r2)
+ } else {
+ h.ServeHTTP(w, r)
+ }
+ })
+}
+
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go
index 8d53503..e913357 100644
--- a/libgo/go/net/http/sniff_test.go
+++ b/libgo/go/net/http/sniff_test.go
@@ -157,9 +157,25 @@ func testServerIssue5953(t *testing.T, h2 bool) {
resp.Body.Close()
}
-func TestContentTypeWithCopy_h1(t *testing.T) { testContentTypeWithCopy(t, h1Mode) }
-func TestContentTypeWithCopy_h2(t *testing.T) { testContentTypeWithCopy(t, h2Mode) }
-func testContentTypeWithCopy(t *testing.T, h2 bool) {
+type byteAtATimeReader struct {
+ buf []byte
+}
+
+func (b *byteAtATimeReader) Read(p []byte) (n int, err error) {
+ if len(p) < 1 {
+ return 0, nil
+ }
+ if len(b.buf) == 0 {
+ return 0, io.EOF
+ }
+ p[0] = b.buf[0]
+ b.buf = b.buf[1:]
+ return 1, nil
+}
+
+func TestContentTypeWithVariousSources_h1(t *testing.T) { testContentTypeWithVariousSources(t, h1Mode) }
+func TestContentTypeWithVariousSources_h2(t *testing.T) { testContentTypeWithVariousSources(t, h2Mode) }
+func testContentTypeWithVariousSources(t *testing.T, h2 bool) {
defer afterTest(t)
const (
@@ -167,30 +183,86 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) {
expected = "text/html; charset=utf-8"
)
- cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
- // Use io.Copy from a bytes.Buffer to trigger ReadFrom.
- buf := bytes.NewBuffer([]byte(input))
- n, err := io.Copy(w, buf)
- if int(n) != len(input) || err != nil {
- t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
- }
- }))
- defer cst.close()
+ for _, test := range []struct {
+ name string
+ handler func(ResponseWriter, *Request)
+ }{{
+ name: "write",
+ handler: func(w ResponseWriter, r *Request) {
+ // Write the whole input at once.
+ n, err := w.Write([]byte(input))
+ if int(n) != len(input) || err != nil {
+ t.Errorf("w.Write(%q) = %v, %v want %d, nil", input, n, err, len(input))
+ }
+ },
+ }, {
+ name: "write one byte at a time",
+ handler: func(w ResponseWriter, r *Request) {
+ // Write the input one byte at a time.
+ buf := []byte(input)
+ for i := range buf {
+ n, err := w.Write(buf[i : i+1])
+ if n != 1 || err != nil {
+ t.Errorf("w.Write(%q) = %v, %v want 1, nil", input, n, err)
+ }
+ }
+ },
+ }, {
+ name: "copy from Reader",
+ handler: func(w ResponseWriter, r *Request) {
+ // Use io.Copy from a plain Reader.
+ type readerOnly struct{ io.Reader }
+ buf := bytes.NewBuffer([]byte(input))
+ n, err := io.Copy(w, readerOnly{buf})
+ if int(n) != len(input) || err != nil {
+ t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
+ }
+ },
+ }, {
+ name: "copy from bytes.Buffer",
+ handler: func(w ResponseWriter, r *Request) {
+ // Use io.Copy from a bytes.Buffer to trigger ReadFrom.
+ buf := bytes.NewBuffer([]byte(input))
+ n, err := io.Copy(w, buf)
+ if int(n) != len(input) || err != nil {
+ t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
+ }
+ },
+ }, {
+ name: "copy one byte at a time",
+ handler: func(w ResponseWriter, r *Request) {
+ // Use io.Copy from a Reader that returns one byte at a time.
+ n, err := io.Copy(w, &byteAtATimeReader{[]byte(input)})
+ if int(n) != len(input) || err != nil {
+ t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
+ }
+ },
+ }} {
+ t.Run(test.name, func(t *testing.T) {
+ cst := newClientServerTest(t, h2, HandlerFunc(test.handler))
+ defer cst.close()
+
+ resp, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ if ct := resp.Header.Get("Content-Type"); ct != expected {
+ t.Errorf("Content-Type = %q, want %q", ct, expected)
+ }
+ if want, got := resp.Header.Get("Content-Length"), fmt.Sprint(len(input)); want != got {
+ t.Errorf("Content-Length = %q, want %q", want, got)
+ }
+ data, err := io.ReadAll(resp.Body)
+ if err != nil {
+ t.Errorf("reading body: %v", err)
+ } else if !bytes.Equal(data, []byte(input)) {
+ t.Errorf("data is %q, want %q", data, input)
+ }
+ resp.Body.Close()
+
+ })
- resp, err := cst.c.Get(cst.ts.URL)
- if err != nil {
- t.Fatalf("Get: %v", err)
- }
- if ct := resp.Header.Get("Content-Type"); ct != expected {
- t.Errorf("Content-Type = %q, want %q", ct, expected)
- }
- data, err := io.ReadAll(resp.Body)
- if err != nil {
- t.Errorf("reading body: %v", err)
- } else if !bytes.Equal(data, []byte(input)) {
- t.Errorf("data is %q, want %q", data, input)
}
- resp.Body.Close()
}
func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) }
diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go
index fbb0c39..85c2e5a 100644
--- a/libgo/go/net/http/transfer.go
+++ b/libgo/go/net/http/transfer.go
@@ -12,6 +12,7 @@ import (
"io"
"net/http/httptrace"
"net/http/internal"
+ "net/http/internal/ascii"
"net/textproto"
"reflect"
"sort"
@@ -638,7 +639,7 @@ func (t *transferReader) parseTransferEncoding() error {
if len(raw) != 1 {
return &unsupportedTEError{fmt.Sprintf("too many transfer encodings: %q", raw)}
}
- if strings.ToLower(textproto.TrimString(raw[0])) != "chunked" {
+ if !ascii.EqualFold(textproto.TrimString(raw[0]), "chunked") {
return &unsupportedTEError{fmt.Sprintf("unsupported transfer encoding: %q", raw[0])}
}
diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go
index 0aa4827..309194e 100644
--- a/libgo/go/net/http/transport.go
+++ b/libgo/go/net/http/transport.go
@@ -21,6 +21,7 @@ import (
"log"
"net"
"net/http/httptrace"
+ "net/http/internal/ascii"
"net/textproto"
"net/url"
"os"
@@ -426,6 +427,7 @@ func (t *Transport) onceSetNextProtoDefaults() {
//
// The environment values may be either a complete URL or a
// "host[:port]", in which case the "http" scheme is assumed.
+// The schemes "http", "https", and "socks5" are supported.
// An error is returned if the value is a different form.
//
// A nil URL and nil error are returned if no proxy is defined in the
@@ -786,10 +788,12 @@ func (t *Transport) CancelRequest(req *Request) {
// Cancel an in-flight request, recording the error value.
// Returns whether the request was canceled.
func (t *Transport) cancelRequest(key cancelKey, err error) bool {
+ // This function must not return until the cancel func has completed.
+ // See: https://golang.org/issue/34658
t.reqMu.Lock()
+ defer t.reqMu.Unlock()
cancel := t.reqCanceler[key]
delete(t.reqCanceler, key)
- t.reqMu.Unlock()
if cancel != nil {
cancel(err)
}
@@ -1185,7 +1189,7 @@ type wantConn struct {
// hooks for testing to know when dials are done
// beforeDial is called in the getConn goroutine when the dial is queued.
- // afterDial is called when the dial is completed or cancelled.
+ // afterDial is called when the dial is completed or canceled.
beforeDial func()
afterDial func()
@@ -1373,7 +1377,7 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi
trace.GotConn(httptrace.GotConnInfo{Conn: w.pc.conn, Reused: w.pc.isReused()})
}
if w.err != nil {
- // If the request has been cancelled, that's probably
+ // If the request has been canceled, that's probably
// what caused w.err; if so, prefer to return the
// cancellation error (see golang.org/issue/16049).
select {
@@ -1435,7 +1439,7 @@ func (t *Transport) queueForDial(w *wantConn) {
// dialConnFor dials on behalf of w and delivers the result to w.
// dialConnFor has received permission to dial w.cm and is counted in t.connCount[w.cm.key()].
-// If the dial is cancelled or unsuccessful, dialConnFor decrements t.connCount[w.cm.key()].
+// If the dial is canceled or unsuccessful, dialConnFor decrements t.connCount[w.cm.key()].
func (t *Transport) dialConnFor(w *wantConn) {
defer w.afterDial()
@@ -1505,7 +1509,7 @@ func (t *Transport) decConnsPerHost(key connectMethodKey) {
// Add TLS to a persistent connection, i.e. negotiate a TLS session. If pconn is already a TLS
// tunnel, this function establishes a nested TLS session inside the encrypted channel.
// The remote endpoint's name may be overridden by TLSClientConfig.ServerName.
-func (pconn *persistConn) addTLS(name string, trace *httptrace.ClientTrace) error {
+func (pconn *persistConn) addTLS(ctx context.Context, name string, trace *httptrace.ClientTrace) error {
// Initiate TLS and check remote host name against certificate.
cfg := cloneTLSConfig(pconn.t.TLSClientConfig)
if cfg.ServerName == "" {
@@ -1527,7 +1531,7 @@ func (pconn *persistConn) addTLS(name string, trace *httptrace.ClientTrace) erro
if trace != nil && trace.TLSHandshakeStart != nil {
trace.TLSHandshakeStart()
}
- err := tlsConn.Handshake()
+ err := tlsConn.HandshakeContext(ctx)
if timer != nil {
timer.Stop()
}
@@ -1583,7 +1587,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
if trace != nil && trace.TLSHandshakeStart != nil {
trace.TLSHandshakeStart()
}
- if err := tc.Handshake(); err != nil {
+ if err := tc.HandshakeContext(ctx); err != nil {
go pconn.conn.Close()
if trace != nil && trace.TLSHandshakeDone != nil {
trace.TLSHandshakeDone(tls.ConnectionState{}, err)
@@ -1607,7 +1611,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
if firstTLSHost, _, err = net.SplitHostPort(cm.addr()); err != nil {
return nil, wrapErr(err)
}
- if err = pconn.addTLS(firstTLSHost, trace); err != nil {
+ if err = pconn.addTLS(ctx, firstTLSHost, trace); err != nil {
return nil, wrapErr(err)
}
}
@@ -1721,7 +1725,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
}
if cm.proxyURL != nil && cm.targetScheme == "https" {
- if err := pconn.addTLS(cm.tlsHost(), trace); err != nil {
+ if err := pconn.addTLS(ctx, cm.tlsHost(), trace); err != nil {
return nil, err
}
}
@@ -2183,7 +2187,7 @@ func (pc *persistConn) readLoop() {
}
resp.Body = body
- if rc.addedGzip && strings.EqualFold(resp.Header.Get("Content-Encoding"), "gzip") {
+ if rc.addedGzip && ascii.EqualFold(resp.Header.Get("Content-Encoding"), "gzip") {
resp.Body = &gzipReader{body: body}
resp.Header.Del("Content-Encoding")
resp.Header.Del("Content-Length")
diff --git a/libgo/go/net/http/transport_internal_test.go b/libgo/go/net/http/transport_internal_test.go
index 1097ffd..1cce272 100644
--- a/libgo/go/net/http/transport_internal_test.go
+++ b/libgo/go/net/http/transport_internal_test.go
@@ -12,7 +12,7 @@ import (
"errors"
"io"
"net"
- "net/http/internal"
+ "net/http/internal/testcert"
"strings"
"testing"
)
@@ -191,7 +191,7 @@ func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) {
// Issue 25009
func TestTransportBodyAltRewind(t *testing.T) {
- cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+ cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
if err != nil {
t.Fatal(err)
}
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index d0202c0..cae5464 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -30,7 +30,7 @@ import (
"net/http/httptest"
"net/http/httptrace"
"net/http/httputil"
- "net/http/internal"
+ "net/http/internal/testcert"
"net/textproto"
"net/url"
"os"
@@ -626,12 +626,15 @@ func TestTransportMaxConnsPerHost(t *testing.T) {
t.Fatalf("ExportHttp2ConfigureTransport: %v", err)
}
- connCh := make(chan net.Conn, 1)
+ mu := sync.Mutex{}
+ var conns []net.Conn
var dialCnt, gotConnCnt, tlsHandshakeCnt int32
tr.Dial = func(network, addr string) (net.Conn, error) {
atomic.AddInt32(&dialCnt, 1)
c, err := net.Dial(network, addr)
- connCh <- c
+ mu.Lock()
+ defer mu.Unlock()
+ conns = append(conns, c)
return c, err
}
@@ -685,7 +688,12 @@ func TestTransportMaxConnsPerHost(t *testing.T) {
t.FailNow()
}
- (<-connCh).Close()
+ mu.Lock()
+ for _, c := range conns {
+ c.Close()
+ }
+ conns = nil
+ mu.Unlock()
tr.CloseIdleConnections()
doReq()
@@ -3738,7 +3746,7 @@ func TestTransportDialTLSContext(t *testing.T) {
if err != nil {
return nil, err
}
- return c, c.Handshake()
+ return c, c.HandshakeContext(ctx)
}
req, err := NewRequest("GET", ts.URL, nil)
@@ -4295,7 +4303,7 @@ func TestTransportReuseConnEmptyResponseBody(t *testing.T) {
// Issue 13839
func TestNoCrashReturningTransportAltConn(t *testing.T) {
- cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
+ cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
if err != nil {
t.Fatal(err)
}
diff --git a/libgo/go/net/http/triv.go b/libgo/go/net/http/triv.go
index 23e65d5..4dc6240 100644
--- a/libgo/go/net/http/triv.go
+++ b/libgo/go/net/http/triv.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build ignore
// +build ignore
package main
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
index 914aaa0..0e5d320 100644
--- a/libgo/go/net/interface.go
+++ b/libgo/go/net/interface.go
@@ -6,6 +6,7 @@ package net
import (
"errors"
+ "internal/itoa"
"sync"
"time"
)
@@ -230,7 +231,7 @@ func (zc *ipv6ZoneCache) name(index int) string {
zoneCache.RUnlock()
}
if !ok { // last resort
- name = uitoa(uint(index))
+ name = itoa.Uitoa(uint(index))
}
return name
}
diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go
index d791cb3..7578b1a 100644
--- a/libgo/go/net/interface_bsd.go
+++ b/libgo/go/net/interface_bsd.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package net
diff --git a/libgo/go/net/interface_bsd_test.go b/libgo/go/net/interface_bsd_test.go
index 947dde7..8d0d9c3 100644
--- a/libgo/go/net/interface_bsd_test.go
+++ b/libgo/go/net/interface_bsd_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package net
diff --git a/libgo/go/net/interface_bsdvar.go b/libgo/go/net/interface_bsdvar.go
index a809b5f..6230e0b 100644
--- a/libgo/go/net/interface_bsdvar.go
+++ b/libgo/go/net/interface_bsdvar.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build dragonfly || netbsd || openbsd
// +build dragonfly netbsd openbsd
package net
diff --git a/libgo/go/net/interface_freebsd.go b/libgo/go/net/interface_freebsd.go
index 45badd6..2b51fcb 100644
--- a/libgo/go/net/interface_freebsd.go
+++ b/libgo/go/net/interface_freebsd.go
@@ -16,9 +16,9 @@ func interfaceMessages(ifindex int) ([]route.Message, error) {
if err != nil {
typ = route.RIBType(syscall.NET_RT_IFLIST)
rib, err = route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex)
- }
- if err != nil {
- return nil, err
+ if err != nil {
+ return nil, err
+ }
}
return route.ParseRIB(typ, rib)
}
diff --git a/libgo/go/net/interface_plan9.go b/libgo/go/net/interface_plan9.go
index 31bbaca..957975c 100644
--- a/libgo/go/net/interface_plan9.go
+++ b/libgo/go/net/interface_plan9.go
@@ -6,6 +6,7 @@ package net
import (
"errors"
+ "internal/itoa"
"os"
)
@@ -38,8 +39,8 @@ func interfaceTable(ifindex int) ([]Interface, error) {
func readInterface(i int) (*Interface, error) {
ifc := &Interface{
- Index: i + 1, // Offset the index by one to suit the contract
- Name: netdir + "/ipifc/" + itoa(i), // Name is the full path to the interface path in plan9
+ Index: i + 1, // Offset the index by one to suit the contract
+ Name: netdir + "/ipifc/" + itoa.Itoa(i), // Name is the full path to the interface path in plan9
}
ifcstat := ifc.Name + "/status"
diff --git a/libgo/go/net/interface_stub.go b/libgo/go/net/interface_stub.go
index 437b9eb..1075e36 100644
--- a/libgo/go/net/interface_stub.go
+++ b/libgo/go/net/interface_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build hurd || (js && wasm)
// +build hurd js,wasm
package net
diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go
index b2ef21e..754db36 100644
--- a/libgo/go/net/interface_test.go
+++ b/libgo/go/net/interface_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/interface_unix_test.go b/libgo/go/net/interface_unix_test.go
index bf41a0fb..0d69fa5 100644
--- a/libgo/go/net/interface_unix_test.go
+++ b/libgo/go/net/interface_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
// +build darwin dragonfly freebsd linux netbsd openbsd
package net
diff --git a/libgo/go/net/internal/socktest/main_test.go b/libgo/go/net/internal/socktest/main_test.go
index 3b0a48a..8af85d3 100644
--- a/libgo/go/net/internal/socktest/main_test.go
+++ b/libgo/go/net/internal/socktest/main_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js && !plan9
// +build !js,!plan9
package socktest_test
diff --git a/libgo/go/net/internal/socktest/main_unix_test.go b/libgo/go/net/internal/socktest/main_unix_test.go
index 4d9d414..6aa8875 100644
--- a/libgo/go/net/internal/socktest/main_unix_test.go
+++ b/libgo/go/net/internal/socktest/main_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js && !plan9 && !windows
// +build !js,!plan9,!windows
package socktest_test
diff --git a/libgo/go/net/internal/socktest/switch_posix.go b/libgo/go/net/internal/socktest/switch_posix.go
index 863edef..cda74e8 100644
--- a/libgo/go/net/internal/socktest/switch_posix.go
+++ b/libgo/go/net/internal/socktest/switch_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !plan9
// +build !plan9
package socktest
diff --git a/libgo/go/net/internal/socktest/switch_stub.go b/libgo/go/net/internal/socktest/switch_stub.go
index 28ce72c..5aa2ece 100644
--- a/libgo/go/net/internal/socktest/switch_stub.go
+++ b/libgo/go/net/internal/socktest/switch_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build plan9
// +build plan9
package socktest
diff --git a/libgo/go/net/internal/socktest/switch_unix.go b/libgo/go/net/internal/socktest/switch_unix.go
index 4c037ba..be9ef6d 100644
--- a/libgo/go/net/internal/socktest/switch_unix.go
+++ b/libgo/go/net/internal/socktest/switch_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris
package socktest
diff --git a/libgo/go/net/internal/socktest/sys_cloexec.go b/libgo/go/net/internal/socktest/sys_cloexec.go
index b13ba57..5e95896 100644
--- a/libgo/go/net/internal/socktest/sys_cloexec.go
+++ b/libgo/go/net/internal/socktest/sys_cloexec.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd
// +build dragonfly freebsd hurd illumos linux netbsd openbsd
package socktest
diff --git a/libgo/go/net/internal/socktest/sys_unix.go b/libgo/go/net/internal/socktest/sys_unix.go
index fbbffc6..39f3dbc 100644
--- a/libgo/go/net/internal/socktest/sys_unix.go
+++ b/libgo/go/net/internal/socktest/sys_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris
package socktest
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
index c00fe8e..38e1aa2 100644
--- a/libgo/go/net/ip.go
+++ b/libgo/go/net/ip.go
@@ -12,7 +12,10 @@
package net
-import "internal/bytealg"
+import (
+ "internal/bytealg"
+ "internal/itoa"
+)
// IP address lengths (bytes).
const (
@@ -125,6 +128,25 @@ func (ip IP) IsLoopback() bool {
return ip.Equal(IPv6loopback)
}
+// IsPrivate reports whether ip is a private address, according to
+// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).
+func (ip IP) IsPrivate() bool {
+ if ip4 := ip.To4(); ip4 != nil {
+ // Following RFC 1918, Section 3. Private Address Space which says:
+ // The Internet Assigned Numbers Authority (IANA) has reserved the
+ // following three blocks of the IP address space for private internets:
+ // 10.0.0.0 - 10.255.255.255 (10/8 prefix)
+ // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
+ // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
+ return ip4[0] == 10 ||
+ (ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
+ (ip4[0] == 192 && ip4[1] == 168)
+ }
+ // Following RFC 4193, Section 8. IANA Considerations which says:
+ // The IANA has assigned the FC00::/7 prefix to "Unique Local Unicast".
+ return len(ip) == IPv6len && ip[0]&0xfe == 0xfc
+}
+
// IsMulticast reports whether ip is a multicast address.
func (ip IP) IsMulticast() bool {
if ip4 := ip.To4(); ip4 != nil {
@@ -531,7 +553,7 @@ func (n *IPNet) String() string {
if l == -1 {
return nn.String() + "/" + m.String()
}
- return nn.String() + "/" + uitoa(uint(l))
+ return nn.String() + "/" + itoa.Uitoa(uint(l))
}
// Parse IPv4 address (d.d.d.d).
@@ -552,6 +574,10 @@ func parseIPv4(s string) IP {
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)
}
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
index a5fc5e6..5bbda60 100644
--- a/libgo/go/net/ip_test.go
+++ b/libgo/go/net/ip_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
@@ -20,9 +21,7 @@ var parseIPTests = []struct {
}{
{"127.0.1.2", IPv4(127, 0, 1, 2)},
{"127.0.0.1", IPv4(127, 0, 0, 1)},
- {"127.001.002.003", IPv4(127, 1, 2, 3)},
{"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
- {"::ffff:127.001.002.003", IPv4(127, 1, 2, 3)},
{"::ffff:7f01:0203", IPv4(127, 1, 2, 3)},
{"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
{"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
@@ -42,6 +41,11 @@ var parseIPTests = []struct {
{"fe80::1%911", nil},
{"", nil},
{"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628
+ {"127.001.002.003", nil},
+ {"::ffff:127.001.002.003", nil},
+ {"123.000.000.000", nil},
+ {"1.2..4", nil},
+ {"0123.0.0.1", nil},
}
func TestParseIP(t *testing.T) {
@@ -357,6 +361,7 @@ var parseCIDRTests = []struct {
{"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}},
{"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}},
{"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}},
+ {"127.000.000.001/32", nil, nil, &ParseError{Type: "CIDR address", Text: "127.000.000.001/32"}},
{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
}
@@ -690,6 +695,28 @@ var ipAddrScopeTests = []struct {
{IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
{IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
{IP.IsGlobalUnicast, nil, false},
+ {IP.IsPrivate, nil, false},
+ {IP.IsPrivate, IPv4(1, 1, 1, 1), false},
+ {IP.IsPrivate, IPv4(9, 255, 255, 255), false},
+ {IP.IsPrivate, IPv4(10, 0, 0, 0), true},
+ {IP.IsPrivate, IPv4(10, 255, 255, 255), true},
+ {IP.IsPrivate, IPv4(11, 0, 0, 0), false},
+ {IP.IsPrivate, IPv4(172, 15, 255, 255), false},
+ {IP.IsPrivate, IPv4(172, 16, 0, 0), true},
+ {IP.IsPrivate, IPv4(172, 16, 255, 255), true},
+ {IP.IsPrivate, IPv4(172, 23, 18, 255), true},
+ {IP.IsPrivate, IPv4(172, 31, 255, 255), true},
+ {IP.IsPrivate, IPv4(172, 31, 0, 0), true},
+ {IP.IsPrivate, IPv4(172, 32, 0, 0), false},
+ {IP.IsPrivate, IPv4(192, 167, 255, 255), false},
+ {IP.IsPrivate, IPv4(192, 168, 0, 0), true},
+ {IP.IsPrivate, IPv4(192, 168, 255, 255), true},
+ {IP.IsPrivate, IPv4(192, 169, 0, 0), false},
+ {IP.IsPrivate, IP{0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, false},
+ {IP.IsPrivate, IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsPrivate, IP{0xfc, 0xff, 0x12, 0, 0, 0, 0, 0x44, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsPrivate, IP{0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true},
+ {IP.IsPrivate, IP{0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
}
func name(f interface{}) string {
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
index fdb3913..ffc437c 100644
--- a/libgo/go/net/iprawsock_posix.go
+++ b/libgo/go/net/iprawsock_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
package net
@@ -74,7 +75,7 @@ func stripIPv4Header(n int, b []byte) int {
func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &IPAddr{IP: sa.Addr[0:]}
diff --git a/libgo/go/net/iprawsock_test.go b/libgo/go/net/iprawsock_test.go
index 8e3543d..a96448e 100644
--- a/libgo/go/net/iprawsock_test.go
+++ b/libgo/go/net/iprawsock_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
index 7d0684d..0f5da25 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -7,6 +7,7 @@ package net
import (
"context"
"internal/bytealg"
+ "runtime"
"sync"
)
@@ -44,6 +45,13 @@ func supportsIPv6() bool {
// IPv4 address inside an IPv6 address at transport layer
// protocols. See RFC 4291, RFC 4038 and RFC 3493.
func supportsIPv4map() bool {
+ // Some operating systems provide no support for mapping IPv4
+ // addresses to IPv6, and a runtime check is unnecessary.
+ switch runtime.GOOS {
+ case "dragonfly", "openbsd":
+ return false
+ }
+
ipStackCaps.Once.Do(ipStackCaps.probe)
return ipStackCaps.ipv4MappedIPv6Enabled
}
diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go
index 7a4b7a6..4328743 100644
--- a/libgo/go/net/ipsock_plan9.go
+++ b/libgo/go/net/ipsock_plan9.go
@@ -7,12 +7,13 @@ package net
import (
"context"
"internal/bytealg"
+ "internal/itoa"
"io/fs"
"os"
"syscall"
)
-// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
+// probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
// capabilities.
//
// Plan 9 uses IPv6 natively, see ip(3).
@@ -336,9 +337,9 @@ func plan9LocalAddr(addr Addr) string {
if port == 0 {
return ""
}
- return itoa(port)
+ return itoa.Itoa(port)
}
- return ip.String() + "!" + itoa(port)
+ return ip.String() + "!" + itoa.Itoa(port)
}
func hangupCtlWrite(ctx context.Context, proto string, ctl *os.File, msg string) error {
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
index 84e72d5..cdd191a 100644
--- a/libgo/go/net/ipsock_posix.go
+++ b/libgo/go/net/ipsock_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
package net
@@ -13,13 +14,13 @@ import (
"syscall"
)
-// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
+// probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
// capabilities which are controlled by the IPV6_V6ONLY socket option
// and kernel configuration.
//
// Should we try to use the IPv4 socket interface if we're only
// dealing with IPv4 sockets? As long as the host system understands
-// IPv4-mapped IPv6, it's okay to pass IPv4-mapeed IPv6 addresses to
+// IPv4-mapped IPv6, it's okay to pass IPv4-mapped IPv6 addresses to
// the IPv6 interface. That simplifies our code and is most
// general. Unfortunately, we need to run on kernels built without
// IPv6 support too. So probe the kernel to figure it out.
diff --git a/libgo/go/net/listen_test.go b/libgo/go/net/listen_test.go
index d8c7209..b1dce29 100644
--- a/libgo/go/net/listen_test.go
+++ b/libgo/go/net/listen_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js && !plan9
// +build !js,!plan9
package net
diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go
index 0660268..d350ef7 100644
--- a/libgo/go/net/lookup.go
+++ b/libgo/go/net/lookup.go
@@ -166,6 +166,9 @@ func (r *Resolver) getLookupGroup() *singleflight.Group {
// LookupHost looks up the given host using the local resolver.
// It returns a slice of that host's addresses.
+//
+// LookupHost uses context.Background internally; to specify the context, use
+// Resolver.LookupHost.
func LookupHost(host string) (addrs []string, err error) {
return DefaultResolver.LookupHost(context.Background(), host)
}
@@ -353,6 +356,9 @@ func ipAddrsEface(addrs []IPAddr) []interface{} {
}
// LookupPort looks up the port for the given network and service.
+//
+// LookupPort uses context.Background internally; to specify the context, use
+// Resolver.LookupPort.
func LookupPort(network, service string) (port int, err error) {
return DefaultResolver.LookupPort(context.Background(), network, service)
}
@@ -392,6 +398,9 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por
//
// The returned canonical name is validated to be a properly
// formatted presentation-format domain name.
+//
+// LookupCNAME uses context.Background internally; to specify the context, use
+// Resolver.LookupCNAME.
func LookupCNAME(host string) (cname string, err error) {
return DefaultResolver.LookupCNAME(context.Background(), host)
}
@@ -415,7 +424,7 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error)
return "", err
}
if !isDomainName(cname) {
- return "", &DNSError{Err: "CNAME target is invalid", Name: host}
+ return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
}
return cname, nil
}
@@ -431,7 +440,9 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error)
// and proto are empty strings, LookupSRV looks up name directly.
//
// The returned service names are validated to be properly
-// formatted presentation-format domain names.
+// formatted presentation-format domain names. If the response contains
+// invalid names, those records are filtered out and an error
+// will be returned alongside the the remaining results, if any.
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
}
@@ -447,7 +458,9 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
// and proto are empty strings, LookupSRV looks up name directly.
//
// The returned service names are validated to be properly
-// formatted presentation-format domain names.
+// formatted presentation-format domain names. If the response contains
+// invalid names, those records are filtered out and an error
+// will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
if err != nil {
@@ -456,21 +469,31 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (
if cname != "" && !isDomainName(cname) {
return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
}
+ filteredAddrs := make([]*SRV, 0, len(addrs))
for _, addr := range addrs {
if addr == nil {
continue
}
if !isDomainName(addr.Target) {
- return "", nil, &DNSError{Err: "SRV target is invalid", Name: name}
+ continue
}
+ filteredAddrs = append(filteredAddrs, addr)
}
- return cname, addrs, nil
+ if len(addrs) != len(filteredAddrs) {
+ return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
+ }
+ return cname, filteredAddrs, nil
}
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
//
// The returned mail server names are validated to be properly
-// formatted presentation-format domain names.
+// formatted presentation-format domain names. If the response contains
+// invalid names, those records are filtered out and an error
+// will be returned alongside the the remaining results, if any.
+//
+// LookupMX uses context.Background internally; to specify the context, use
+// Resolver.LookupMX.
func LookupMX(name string) ([]*MX, error) {
return DefaultResolver.LookupMX(context.Background(), name)
}
@@ -478,27 +501,41 @@ func LookupMX(name string) ([]*MX, error) {
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
//
// The returned mail server names are validated to be properly
-// formatted presentation-format domain names.
+// formatted presentation-format domain names. If the response contains
+// invalid names, those records are filtered out and an error
+// will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
records, err := r.lookupMX(ctx, name)
if err != nil {
return nil, err
}
+ filteredMX := make([]*MX, 0, len(records))
for _, mx := range records {
if mx == nil {
continue
}
- if !isDomainName(mx.Host) {
- return nil, &DNSError{Err: "MX target is invalid", Name: name}
+ // Bypass the hostname validity check for targets which contain only a dot,
+ // as this is used to represent a 'Null' MX record.
+ if mx.Host != "." && !isDomainName(mx.Host) {
+ continue
}
+ filteredMX = append(filteredMX, mx)
+ }
+ if len(records) != len(filteredMX) {
+ return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
}
- return records, nil
+ return filteredMX, nil
}
// LookupNS returns the DNS NS records for the given domain name.
//
// The returned name server names are validated to be properly
-// formatted presentation-format domain names.
+// formatted presentation-format domain names. If the response contains
+// invalid names, those records are filtered out and an error
+// will be returned alongside the the remaining results, if any.
+//
+// LookupNS uses context.Background internally; to specify the context, use
+// Resolver.LookupNS.
func LookupNS(name string) ([]*NS, error) {
return DefaultResolver.LookupNS(context.Background(), name)
}
@@ -506,24 +543,34 @@ func LookupNS(name string) ([]*NS, error) {
// LookupNS returns the DNS NS records for the given domain name.
//
// The returned name server names are validated to be properly
-// formatted presentation-format domain names.
+// formatted presentation-format domain names. If the response contains
+// invalid names, those records are filtered out and an error
+// will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
records, err := r.lookupNS(ctx, name)
if err != nil {
return nil, err
}
+ filteredNS := make([]*NS, 0, len(records))
for _, ns := range records {
if ns == nil {
continue
}
if !isDomainName(ns.Host) {
- return nil, &DNSError{Err: "NS target is invalid", Name: name}
+ continue
}
+ filteredNS = append(filteredNS, ns)
}
- return records, nil
+ if len(records) != len(filteredNS) {
+ return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
+ }
+ return filteredNS, nil
}
// LookupTXT returns the DNS TXT records for the given domain name.
+//
+// LookupTXT uses context.Background internally; to specify the context, use
+// Resolver.LookupTXT.
func LookupTXT(name string) ([]string, error) {
return DefaultResolver.lookupTXT(context.Background(), name)
}
@@ -537,10 +584,14 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error)
// of names mapping to that address.
//
// The returned names are validated to be properly formatted presentation-format
-// domain names.
+// domain names. If the response contains invalid names, those records are filtered
+// out and an error will be returned alongside the the remaining results, if any.
//
// When using the host C library resolver, at most one result will be
// returned. To bypass the host resolver, use a custom Resolver.
+//
+// LookupAddr uses context.Background internally; to specify the context, use
+// Resolver.LookupAddr.
func LookupAddr(addr string) (names []string, err error) {
return DefaultResolver.LookupAddr(context.Background(), addr)
}
@@ -549,16 +600,26 @@ func LookupAddr(addr string) (names []string, err error) {
// of names mapping to that address.
//
// The returned names are validated to be properly formatted presentation-format
-// domain names.
+// domain names. If the response contains invalid names, those records are filtered
+// out and an error will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
names, err := r.lookupAddr(ctx, addr)
if err != nil {
return nil, err
}
+ filteredNames := make([]string, 0, len(names))
for _, name := range names {
- if !isDomainName(name) {
- return nil, &DNSError{Err: "PTR target is invalid", Name: addr}
+ if isDomainName(name) {
+ filteredNames = append(filteredNames, name)
}
}
- return names, nil
+ if len(names) != len(filteredNames) {
+ return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
+ }
+ return filteredNames, nil
}
+
+// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
+// method recieves DNS records which contain invalid DNS names. This may be returned alongside
+// results which have had the malformed records filtered out.
+var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
diff --git a/libgo/go/net/lookup_fake.go b/libgo/go/net/lookup_fake.go
index 3b3c39b..f4fcaed 100644
--- a/libgo/go/net/lookup_fake.go
+++ b/libgo/go/net/lookup_fake.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build js && wasm
// +build js,wasm
package net
diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go
index 6a2d48e..75c18b3 100644
--- a/libgo/go/net/lookup_plan9.go
+++ b/libgo/go/net/lookup_plan9.go
@@ -8,6 +8,7 @@ import (
"context"
"errors"
"internal/bytealg"
+ "internal/itoa"
"io"
"os"
)
@@ -84,7 +85,7 @@ func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest str
if len(ip) != 0 && !ip.IsUnspecified() {
ips = ip.String()
}
- lines, err := queryCS(ctx, net, ips, itoa(port))
+ lines, err := queryCS(ctx, net, ips, itoa.Itoa(port))
if err != nil {
return
}
@@ -308,7 +309,7 @@ func (*Resolver) lookupTXT(ctx context.Context, name string) (txt []string, err
}
for _, line := range lines {
if i := bytealg.IndexByteString(line, '\t'); i >= 0 {
- txt = append(txt, absDomainName([]byte(line[i+1:])))
+ txt = append(txt, line[i+1:])
}
}
return
diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go
index 32a0d37..3faaf00 100644
--- a/libgo/go/net/lookup_test.go
+++ b/libgo/go/net/lookup_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go
index c27b1a0..05f49b0 100644
--- a/libgo/go/net/lookup_unix.go
+++ b/libgo/go/net/lookup_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
@@ -89,7 +90,7 @@ func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string,
func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
if r.preferGo() {
- return r.goLookupIP(ctx, host)
+ return r.goLookupIP(ctx, network, host)
}
order := systemConf().hostLookupOrder(r, host)
if order == hostLookupCgo {
@@ -99,7 +100,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []
// cgo not available (or netgo); fall back to Go's DNS resolver
order = hostLookupFilesDNS
}
- ips, _, err := r.goLookupIPCNAMEOrder(ctx, host, order)
+ ips, _, err := r.goLookupIPCNAMEOrder(ctx, network, host, order)
return ips, err
}
diff --git a/libgo/go/net/lookup_windows_test.go b/libgo/go/net/lookup_windows_test.go
index 62b61ed..aa95501 100644
--- a/libgo/go/net/lookup_windows_test.go
+++ b/libgo/go/net/lookup_windows_test.go
@@ -299,7 +299,7 @@ func lookupPTR(name string) (ptr []string, err error) {
ptr = make([]string, 0, 10)
rx := regexp.MustCompile(`(?m)^Pinging\s+([a-zA-Z0-9.\-]+)\s+\[.*$`)
for _, ans := range rx.FindAllStringSubmatch(r, -1) {
- ptr = append(ptr, ans[1]+".")
+ ptr = append(ptr, absDomainName([]byte(ans[1])))
}
return
}
diff --git a/libgo/go/net/main_cloexec_test.go b/libgo/go/net/main_cloexec_test.go
index d436df1..03f7d63 100644
--- a/libgo/go/net/main_cloexec_test.go
+++ b/libgo/go/net/main_cloexec_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd
// +build dragonfly freebsd hurd illumos linux netbsd openbsd
package net
diff --git a/libgo/go/net/main_conf_test.go b/libgo/go/net/main_conf_test.go
index a92dff5..645b267 100644
--- a/libgo/go/net/main_conf_test.go
+++ b/libgo/go/net/main_conf_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js && !plan9 && !windows
// +build !js,!plan9,!windows
package net
diff --git a/libgo/go/net/main_noconf_test.go b/libgo/go/net/main_noconf_test.go
index bac84aa..bcea630 100644
--- a/libgo/go/net/main_noconf_test.go
+++ b/libgo/go/net/main_noconf_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build (js && wasm) || plan9 || windows
// +build js,wasm plan9 windows
package net
diff --git a/libgo/go/net/main_posix_test.go b/libgo/go/net/main_posix_test.go
index f2484f3..c9ab25a 100644
--- a/libgo/go/net/main_posix_test.go
+++ b/libgo/go/net/main_posix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js && !plan9
// +build !js,!plan9
package net
diff --git a/libgo/go/net/main_test.go b/libgo/go/net/main_test.go
index 2d5be2e..dc17d3f 100644
--- a/libgo/go/net/main_test.go
+++ b/libgo/go/net/main_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/main_unix_test.go b/libgo/go/net/main_unix_test.go
index ef7e915..367cefc 100644
--- a/libgo/go/net/main_unix_test.go
+++ b/libgo/go/net/main_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/mockserver_test.go b/libgo/go/net/mockserver_test.go
index 867e31e..b50a1e5 100644
--- a/libgo/go/net/mockserver_test.go
+++ b/libgo/go/net/mockserver_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index 4b4ed12..a7c65ff 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -539,6 +539,9 @@ type ParseError struct {
func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }
+func (e *ParseError) Timeout() bool { return false }
+func (e *ParseError) Temporary() bool { return false }
+
type AddrError struct {
Err string
Addr string
@@ -642,7 +645,7 @@ var errClosed = poll.ErrNetClosing
// another goroutine before the I/O is completed. This may be wrapped
// in another error, and should normally be tested using
// errors.Is(err, net.ErrClosed).
-var ErrClosed = errClosed
+var ErrClosed error = errClosed
type writerOnly struct {
io.Writer
@@ -733,6 +736,7 @@ func (v *Buffers) consume(n int64) {
return
}
n -= ln0
+ (*v)[0] = nil
*v = (*v)[1:]
}
}
diff --git a/libgo/go/net/net_fake.go b/libgo/go/net/net_fake.go
index 0c48dd5..74fc1da 100644
--- a/libgo/go/net/net_fake.go
+++ b/libgo/go/net/net_fake.go
@@ -4,6 +4,7 @@
// Fake networking for js/wasm. It is intended to allow tests of other package to pass.
+//go:build js && wasm
// +build js,wasm
package net
@@ -267,7 +268,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return 0, nil, syscall.ENOSYS
}
-func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
return 0, 0, 0, nil, syscall.ENOSYS
}
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index 409e140..6e7be4d 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
@@ -587,3 +588,23 @@ func TestNotTemporaryRead(t *testing.T) {
}
withTCPConnPair(t, client, server)
}
+
+// The various errors should implement the Error interface.
+func TestErrors(t *testing.T) {
+ var (
+ _ Error = &OpError{}
+ _ Error = &ParseError{}
+ _ Error = &AddrError{}
+ _ Error = UnknownNetworkError("")
+ _ Error = InvalidAddrError("")
+ _ Error = &timeoutError{}
+ _ Error = &DNSConfigError{}
+ _ Error = &DNSError{}
+ )
+
+ // ErrClosed was introduced as type error, so we can't check
+ // it using a declaration.
+ if _, ok := ErrClosed.(Error); !ok {
+ t.Fatal("ErrClosed does not implement Error")
+ }
+}
diff --git a/libgo/go/net/nss.go b/libgo/go/net/nss.go
index 98d740f..c12ee75 100644
--- a/libgo/go/net/nss.go
+++ b/libgo/go/net/nss.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/nss_test.go b/libgo/go/net/nss_test.go
index 53cbc4d..948b8d3 100644
--- a/libgo/go/net/nss_test.go
+++ b/libgo/go/net/nss_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/packetconn_test.go b/libgo/go/net/packetconn_test.go
index a377d33..aeb9845 100644
--- a/libgo/go/net/packetconn_test.go
+++ b/libgo/go/net/packetconn_test.go
@@ -5,6 +5,7 @@
// This file implements API tests across platforms and will never have a build
// tag.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go
index cdb35bb..6c230ab 100644
--- a/libgo/go/net/parse.go
+++ b/libgo/go/net/parse.go
@@ -172,32 +172,6 @@ func xtoi2(s string, e byte) (byte, bool) {
return byte(n), ok && ei == 2
}
-// Convert integer to decimal string.
-func itoa(val int) string {
- if val < 0 {
- return "-" + uitoa(uint(-val))
- }
- return uitoa(uint(val))
-}
-
-// Convert unsigned integer to decimal string.
-func uitoa(val uint) string {
- if val == 0 { // avoid string allocation
- return "0"
- }
- var buf [20]byte // big enough for 64bit value base 10
- i := len(buf) - 1
- for val >= 10 {
- q := val / 10
- buf[i] = byte('0' + val - q*10)
- i--
- val = q
- }
- // val < 10
- buf[i] = byte('0' + val)
- return string(buf[i:])
-}
-
// Convert i to a hexadecimal string. Leading zeros are not printed.
func appendHex(dst []byte, i uint32) []byte {
if i == 0 {
diff --git a/libgo/go/net/port_unix.go b/libgo/go/net/port_unix.go
index a3b402f..07b4cbb 100644
--- a/libgo/go/net/port_unix.go
+++ b/libgo/go/net/port_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris
// Read system port mappings from /etc/services
diff --git a/libgo/go/net/protoconn_test.go b/libgo/go/net/protoconn_test.go
index 6f83f52..fc9b386 100644
--- a/libgo/go/net/protoconn_test.go
+++ b/libgo/go/net/protoconn_test.go
@@ -5,6 +5,7 @@
// This file implements API tests across platforms and will never have a build
// tag.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/rawconn_stub_test.go b/libgo/go/net/rawconn_stub_test.go
index cec977f..975aa8d 100644
--- a/libgo/go/net/rawconn_stub_test.go
+++ b/libgo/go/net/rawconn_stub_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build (js && wasm) || plan9
// +build js,wasm plan9
package net
diff --git a/libgo/go/net/rawconn_test.go b/libgo/go/net/rawconn_test.go
index a08ff89..3ef7af3 100644
--- a/libgo/go/net/rawconn_test.go
+++ b/libgo/go/net/rawconn_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/rawconn_unix_test.go b/libgo/go/net/rawconn_unix_test.go
index 21527c4..77df4f8 100644
--- a/libgo/go/net/rawconn_unix_test.go
+++ b/libgo/go/net/rawconn_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go
index 9cb9282..074c5b9 100644
--- a/libgo/go/net/rpc/server.go
+++ b/libgo/go/net/rpc/server.go
@@ -283,7 +283,7 @@ func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {
mtype := method.Type
mname := method.Name
// Method must be exported.
- if method.PkgPath != "" {
+ if !method.IsExported() {
continue
}
// Method needs three ins: receiver, *args, *reply.
diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go
index 53bc53a..5753bc0 100644
--- a/libgo/go/net/sendfile_stub.go
+++ b/libgo/go/net/sendfile_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || (js && wasm) || netbsd || openbsd
// +build aix darwin js,wasm netbsd openbsd
package net
diff --git a/libgo/go/net/sendfile_test.go b/libgo/go/net/sendfile_test.go
index d6057fd..54e51fa 100644
--- a/libgo/go/net/sendfile_test.go
+++ b/libgo/go/net/sendfile_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
@@ -13,7 +14,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"os"
"runtime"
"sync"
@@ -366,7 +366,7 @@ func TestSendfileOnWriteTimeoutExceeded(t *testing.T) {
}
defer conn.Close()
- n, err := io.Copy(ioutil.Discard, conn)
+ n, err := io.Copy(io.Discard, conn)
if err != nil {
t.Fatalf("expected nil error, but got %v", err)
}
diff --git a/libgo/go/net/sendfile_unix_alt.go b/libgo/go/net/sendfile_unix_alt.go
index 8cededc..54667d6 100644
--- a/libgo/go/net/sendfile_unix_alt.go
+++ b/libgo/go/net/sendfile_unix_alt.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build dragonfly || freebsd || solaris
// +build dragonfly freebsd solaris
package net
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
index 4ac5443..7cbf152 100644
--- a/libgo/go/net/server_test.go
+++ b/libgo/go/net/server_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
@@ -104,13 +105,6 @@ func TestTCPServer(t *testing.T) {
if perr := parseDialError(err); perr != nil {
t.Error(perr)
}
- if tt.taddr == "::1" && os.Getenv("GO_BUILDER_NAME") == "darwin-amd64-10_12" && os.IsTimeout(err) {
- // A suspected kernel bug in macOS 10.12 occasionally results in
- // "i/o timeout" errors when dialing address ::1. The errors have not
- // been observed on newer versions of the OS, so we don't plan to work
- // around them. See https://golang.org/issue/32919.
- t.Skipf("skipping due to error on known-flaky macOS 10.12 builder: %v", err)
- }
t.Fatal(err)
}
defer c.Close()
diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go
index 73fb6be..4c883ad 100644
--- a/libgo/go/net/sock_bsd.go
+++ b/libgo/go/net/sock_bsd.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package net
diff --git a/libgo/go/net/sock_cloexec.go b/libgo/go/net/sock_cloexec.go
index 43be6ff..cb57bb4 100644
--- a/libgo/go/net/sock_cloexec.go
+++ b/libgo/go/net/sock_cloexec.go
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file implements sysSocket and accept for platforms that
-// provide a fast path for setting SetNonblock and CloseOnExec.
+// This file implements sysSocket for platforms that provide a fast path for
+// setting SetNonblock and CloseOnExec.
+//go:build dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd
// +build dragonfly freebsd hurd illumos linux netbsd openbsd
package net
diff --git a/libgo/go/net/sock_posix.go b/libgo/go/net/sock_posix.go
index 8fe9bc7..8c09b0b 100644
--- a/libgo/go/net/sock_posix.go
+++ b/libgo/go/net/sock_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/sock_stub.go b/libgo/go/net/sock_stub.go
index 6d44f43..1e5032e 100644
--- a/libgo/go/net/sock_stub.go
+++ b/libgo/go/net/sock_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || hurd || (js && wasm) || solaris
// +build aix hurd js,wasm solaris
package net
diff --git a/libgo/go/net/sockaddr_posix.go b/libgo/go/net/sockaddr_posix.go
index 470d044..618d85f 100644
--- a/libgo/go/net/sockaddr_posix.go
+++ b/libgo/go/net/sockaddr_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go
index 7b8b8d9..e52fa88 100644
--- a/libgo/go/net/sockopt_bsd.go
+++ b/libgo/go/net/sockopt_bsd.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || netbsd || openbsd
// +build darwin dragonfly freebsd netbsd openbsd
package net
@@ -25,7 +26,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
}
}
- if supportsIPv4map() && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
+ if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW && supportsIPv4map() {
// Allow both IP versions even if the OS default
// is otherwise. Note that some operating systems
// never admit this option.
diff --git a/libgo/go/net/sockopt_posix.go b/libgo/go/net/sockopt_posix.go
index d2cb30b..3478872 100644
--- a/libgo/go/net/sockopt_posix.go
+++ b/libgo/go/net/sockopt_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/sockopt_stub.go b/libgo/go/net/sockopt_stub.go
index 52624a3..99b5277 100644
--- a/libgo/go/net/sockopt_stub.go
+++ b/libgo/go/net/sockopt_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build js && wasm
// +build js,wasm
package net
diff --git a/libgo/go/net/sockoptip_bsdvar.go b/libgo/go/net/sockoptip_bsdvar.go
index c93f592..8b0b5d2 100644
--- a/libgo/go/net/sockoptip_bsdvar.go
+++ b/libgo/go/net/sockoptip_bsdvar.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd netbsd openbsd solaris
package net
diff --git a/libgo/go/net/sockoptip_posix.go b/libgo/go/net/sockoptip_posix.go
index 0ac50e3..a063e79 100644
--- a/libgo/go/net/sockoptip_posix.go
+++ b/libgo/go/net/sockoptip_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/sockoptip_stub.go b/libgo/go/net/sockoptip_stub.go
index 57cd289..4175922 100644
--- a/libgo/go/net/sockoptip_stub.go
+++ b/libgo/go/net/sockoptip_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build js && wasm
// +build js,wasm
package net
diff --git a/libgo/go/net/splice_stub.go b/libgo/go/net/splice_stub.go
index 9106cb2..ce2e904 100644
--- a/libgo/go/net/splice_stub.go
+++ b/libgo/go/net/splice_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !linux
// +build !linux
package net
diff --git a/libgo/go/net/splice_test.go b/libgo/go/net/splice_test.go
index cd4e01f..d5f6367 100644
--- a/libgo/go/net/splice_test.go
+++ b/libgo/go/net/splice_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build linux
// +build linux
package net
diff --git a/libgo/go/net/sys_cloexec.go b/libgo/go/net/sys_cloexec.go
index 967b8be..a32483e 100644
--- a/libgo/go/net/sys_cloexec.go
+++ b/libgo/go/net/sys_cloexec.go
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file implements sysSocket and accept for platforms that do not
-// provide a fast path for setting SetNonblock and CloseOnExec.
+// This file implements sysSocket for platforms that do not provide a fast path
+// for setting SetNonblock and CloseOnExec.
+//go:build aix || darwin || (solaris && !illumos)
// +build aix darwin solaris,!illumos
package net
diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go
index 9a9b03a..19a90143 100644
--- a/libgo/go/net/tcpsock.go
+++ b/libgo/go/net/tcpsock.go
@@ -6,6 +6,7 @@ package net
import (
"context"
+ "internal/itoa"
"io"
"os"
"syscall"
@@ -31,9 +32,9 @@ func (a *TCPAddr) String() string {
}
ip := ipEmptyString(a.IP)
if a.Zone != "" {
- return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port))
+ return JoinHostPort(ip+"%"+a.Zone, itoa.Itoa(a.Port))
}
- return JoinHostPort(ip, itoa(a.Port))
+ return JoinHostPort(ip, itoa.Itoa(a.Port))
}
func (a *TCPAddr) isWildcard() bool {
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
index 2c359da..9fd7822 100644
--- a/libgo/go/net/tcpsock_posix.go
+++ b/libgo/go/net/tcpsock_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/tcpsock_test.go b/libgo/go/net/tcpsock_test.go
index c220c0b..884c5cb 100644
--- a/libgo/go/net/tcpsock_test.go
+++ b/libgo/go/net/tcpsock_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/tcpsock_unix_test.go b/libgo/go/net/tcpsock_unix_test.go
index 2bd591b..41bd229 100644
--- a/libgo/go/net/tcpsock_unix_test.go
+++ b/libgo/go/net/tcpsock_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js && !plan9 && !windows
// +build !js,!plan9,!windows
package net
diff --git a/libgo/go/net/tcpsockopt_plan9.go b/libgo/go/net/tcpsockopt_plan9.go
index fb56871..264359d 100644
--- a/libgo/go/net/tcpsockopt_plan9.go
+++ b/libgo/go/net/tcpsockopt_plan9.go
@@ -7,6 +7,7 @@
package net
import (
+ "internal/itoa"
"syscall"
"time"
)
@@ -17,7 +18,7 @@ func setNoDelay(fd *netFD, noDelay bool) error {
// Set keep alive period.
func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
- cmd := "keepalive " + itoa(int(d/time.Millisecond))
+ cmd := "keepalive " + itoa.Itoa(int(d/time.Millisecond))
_, e := fd.ctl.WriteAt([]byte(cmd), 0)
return e
}
diff --git a/libgo/go/net/tcpsockopt_posix.go b/libgo/go/net/tcpsockopt_posix.go
index 01bc421..4c99ab8 100644
--- a/libgo/go/net/tcpsockopt_posix.go
+++ b/libgo/go/net/tcpsockopt_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/tcpsockopt_stub.go b/libgo/go/net/tcpsockopt_stub.go
index d043da1..028d5fd 100644
--- a/libgo/go/net/tcpsockopt_stub.go
+++ b/libgo/go/net/tcpsockopt_stub.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build js && wasm
// +build js,wasm
package net
diff --git a/libgo/go/net/tcpsockopt_unix.go b/libgo/go/net/tcpsockopt_unix.go
index e05cb73..cc0662a 100644
--- a/libgo/go/net/tcpsockopt_unix.go
+++ b/libgo/go/net/tcpsockopt_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || freebsd || hurd || linux || netbsd
// +build aix freebsd hurd linux netbsd
package net
diff --git a/libgo/go/net/testdata/ipv4-hosts b/libgo/go/net/testdata/ipv4-hosts
index 5208bb4..6b99675 100644
--- a/libgo/go/net/testdata/ipv4-hosts
+++ b/libgo/go/net/testdata/ipv4-hosts
@@ -1,12 +1,8 @@
# See https://tools.ietf.org/html/rfc1123.
-#
-# The literal IPv4 address parser in the net package is a relaxed
-# one. It may accept a literal IPv4 address in dotted-decimal notation
-# with leading zeros such as "001.2.003.4".
# internet address and host name
127.0.0.1 localhost # inline comment separated by tab
-127.000.000.002 localhost # inline comment separated by space
+127.0.0.2 localhost # inline comment separated by space
# internet address, host name and aliases
-127.000.000.003 localhost localhost.localdomain
+127.0.0.3 localhost localhost.localdomain
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
index 205aaa4..e1cf146 100644
--- a/libgo/go/net/timeout_test.go
+++ b/libgo/go/net/timeout_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
index 571e099..70f2ce2 100644
--- a/libgo/go/net/udpsock.go
+++ b/libgo/go/net/udpsock.go
@@ -6,6 +6,7 @@ package net
import (
"context"
+ "internal/itoa"
"syscall"
)
@@ -34,9 +35,9 @@ func (a *UDPAddr) String() string {
}
ip := ipEmptyString(a.IP)
if a.Zone != "" {
- return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port))
+ return JoinHostPort(ip+"%"+a.Zone, itoa.Itoa(a.Port))
}
- return JoinHostPort(ip, itoa(a.Port))
+ return JoinHostPort(ip, itoa.Itoa(a.Port))
}
func (a *UDPAddr) isWildcard() bool {
@@ -99,11 +100,20 @@ func (c *UDPConn) SyscallConn() (syscall.RawConn, error) {
}
// ReadFromUDP acts like ReadFrom but returns a UDPAddr.
-func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
+ // This function is designed to allow the caller to control the lifetime
+ // of the returned *UDPAddr and thereby prevent an allocation.
+ // See https://blog.filippo.io/efficient-go-apis-with-the-inliner/.
+ // The real work is done by readFromUDP, below.
+ return c.readFromUDP(b, &UDPAddr{})
+}
+
+// readFromUDP implements ReadFromUDP.
+func (c *UDPConn) readFromUDP(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
}
- n, addr, err := c.readFrom(b)
+ n, addr, err := c.readFrom(b, addr)
if err != nil {
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
@@ -112,14 +122,9 @@ func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
// ReadFrom implements the PacketConn ReadFrom method.
func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
- if !c.ok() {
- return 0, nil, syscall.EINVAL
- }
- n, addr, err := c.readFrom(b)
- if err != nil {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
- }
+ n, addr, err := c.readFromUDP(b, &UDPAddr{})
if addr == nil {
+ // Return Addr(nil), not Addr(*UDPConn(nil)).
return n, nil, err
}
return n, addr, err
diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go
index 79986ce..1df293d 100644
--- a/libgo/go/net/udpsock_plan9.go
+++ b/libgo/go/net/udpsock_plan9.go
@@ -11,7 +11,7 @@ import (
"syscall"
)
-func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
+func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
buf := make([]byte, udpHeaderSize+len(b))
m, err := c.fd.Read(buf)
if err != nil {
@@ -23,8 +23,9 @@ func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
buf = buf[:m]
h, buf := unmarshalUDPHeader(buf)
- n = copy(b, buf)
- return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil
+ n := copy(b, buf)
+ *addr = UDPAddr{IP: h.raddr, Port: int(h.rport)}
+ return n, addr, nil
}
func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
index 858a3ef..a4c6da2 100644
--- a/libgo/go/net/udpsock_posix.go
+++ b/libgo/go/net/udpsock_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
package net
@@ -42,21 +43,23 @@ func (a *UDPAddr) toLocal(net string) sockaddr {
return &UDPAddr{loopbackIP(net), a.Port, a.Zone}
}
-func (c *UDPConn) readFrom(b []byte) (int, *UDPAddr, error) {
- var addr *UDPAddr
+func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
n, sa, err := c.fd.readFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
- addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
+ *addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
case *syscall.SockaddrInet6:
- addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
+ *addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
+ default:
+ // No sockaddr, so don't return UDPAddr.
+ addr = nil
}
return n, addr, err
}
func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
diff --git a/libgo/go/net/udpsock_test.go b/libgo/go/net/udpsock_test.go
index 327eba6..0e8c351 100644
--- a/libgo/go/net/udpsock_test.go
+++ b/libgo/go/net/udpsock_test.go
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
import (
+ "errors"
"internal/testenv"
+ "os"
"reflect"
"runtime"
"testing"
@@ -444,3 +447,51 @@ func TestUDPReadSizeError(t *testing.T) {
}
}
}
+
+// TestUDPReadTimeout verifies that ReadFromUDP with timeout returns an error
+// without data or an address.
+func TestUDPReadTimeout(t *testing.T) {
+ la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ c, err := ListenUDP("udp4", la)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ c.SetDeadline(time.Now())
+ b := make([]byte, 1)
+ n, addr, err := c.ReadFromUDP(b)
+ if !errors.Is(err, os.ErrDeadlineExceeded) {
+ t.Errorf("ReadFromUDP got err %v want os.ErrDeadlineExceeded", err)
+ }
+ if n != 0 {
+ t.Errorf("ReadFromUDP got n %d want 0", n)
+ }
+ if addr != nil {
+ t.Errorf("ReadFromUDP got addr %+#v want nil", addr)
+ }
+}
+
+func BenchmarkWriteToReadFromUDP(b *testing.B) {
+ conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
+ if err != nil {
+ b.Fatal(err)
+ }
+ addr := conn.LocalAddr()
+ buf := make([]byte, 8)
+ b.ResetTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ _, err := conn.WriteTo(buf, addr)
+ if err != nil {
+ b.Fatal(err)
+ }
+ _, _, err = conn.ReadFromUDP(buf)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
index 3721485..af075af 100644
--- a/libgo/go/net/unixsock_posix.go
+++ b/libgo/go/net/unixsock_posix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris windows
package net
@@ -112,7 +113,11 @@ func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
var sa syscall.Sockaddr
- n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
+ n, oobn, flags, sa, err = c.fd.readMsg(b, oob, readMsgFlags)
+ if readMsgFlags == 0 && err == nil && oobn > 0 {
+ setReadMsgCloseOnExec(oob[:oobn])
+ }
+
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
diff --git a/libgo/go/net/unixsock_readmsg_cloexec.go b/libgo/go/net/unixsock_readmsg_cloexec.go
new file mode 100644
index 0000000..716484c
--- /dev/null
+++ b/libgo/go/net/unixsock_readmsg_cloexec.go
@@ -0,0 +1,31 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || darwin || freebsd || solaris
+// +build aix darwin freebsd solaris
+
+package net
+
+import "syscall"
+
+const readMsgFlags = 0
+
+func setReadMsgCloseOnExec(oob []byte) {
+ scms, err := syscall.ParseSocketControlMessage(oob)
+ if err != nil {
+ return
+ }
+
+ for _, scm := range scms {
+ if scm.Header.Level == syscall.SOL_SOCKET && scm.Header.Type == syscall.SCM_RIGHTS {
+ fds, err := syscall.ParseUnixRights(&scm)
+ if err != nil {
+ continue
+ }
+ for _, fd := range fds {
+ syscall.CloseOnExec(fd)
+ }
+ }
+ }
+}
diff --git a/libgo/go/net/unixsock_readmsg_cmsg_cloexec.go b/libgo/go/net/unixsock_readmsg_cmsg_cloexec.go
new file mode 100644
index 0000000..bb851b8
--- /dev/null
+++ b/libgo/go/net/unixsock_readmsg_cmsg_cloexec.go
@@ -0,0 +1,14 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build dragonfly || linux || netbsd || openbsd
+// +build dragonfly linux netbsd openbsd
+
+package net
+
+import "syscall"
+
+const readMsgFlags = syscall.MSG_CMSG_CLOEXEC
+
+func setReadMsgCloseOnExec(oob []byte) {}
diff --git a/libgo/go/net/unixsock_readmsg_other.go b/libgo/go/net/unixsock_readmsg_other.go
new file mode 100644
index 0000000..3290761
--- /dev/null
+++ b/libgo/go/net/unixsock_readmsg_other.go
@@ -0,0 +1,12 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (js && wasm) || windows
+// +build js,wasm windows
+
+package net
+
+const readMsgFlags = 0
+
+func setReadMsgCloseOnExec(oob []byte) {}
diff --git a/libgo/go/net/unixsock_readmsg_test.go b/libgo/go/net/unixsock_readmsg_test.go
new file mode 100644
index 0000000..a4d2fca
--- /dev/null
+++ b/libgo/go/net/unixsock_readmsg_test.go
@@ -0,0 +1,105 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "testing"
+ "time"
+)
+
+func TestUnixConnReadMsgUnixSCMRightsCloseOnExec(t *testing.T) {
+ if !testableNetwork("unix") {
+ t.Skip("not unix system")
+ }
+
+ scmFile, err := os.Open(os.DevNull)
+ if err != nil {
+ t.Fatalf("file open: %v", err)
+ }
+ defer scmFile.Close()
+
+ rights := syscall.UnixRights(int(scmFile.Fd()))
+ fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
+ if err != nil {
+ t.Fatalf("Socketpair: %v", err)
+ }
+
+ writeFile := os.NewFile(uintptr(fds[0]), "write-socket")
+ defer writeFile.Close()
+ readFile := os.NewFile(uintptr(fds[1]), "read-socket")
+ defer readFile.Close()
+
+ cw, err := FileConn(writeFile)
+ if err != nil {
+ t.Fatalf("FileConn: %v", err)
+ }
+ defer cw.Close()
+ cr, err := FileConn(readFile)
+ if err != nil {
+ t.Fatalf("FileConn: %v", err)
+ }
+ defer cr.Close()
+
+ ucw, ok := cw.(*UnixConn)
+ if !ok {
+ t.Fatalf("got %T; want UnixConn", cw)
+ }
+ ucr, ok := cr.(*UnixConn)
+ if !ok {
+ t.Fatalf("got %T; want UnixConn", cr)
+ }
+
+ oob := make([]byte, syscall.CmsgSpace(4))
+ err = ucw.SetWriteDeadline(time.Now().Add(5 * time.Second))
+ if err != nil {
+ t.Fatalf("Can't set unix connection timeout: %v", err)
+ }
+ _, _, err = ucw.WriteMsgUnix(nil, rights, nil)
+ if err != nil {
+ t.Fatalf("UnixConn readMsg: %v", err)
+ }
+ err = ucr.SetReadDeadline(time.Now().Add(5 * time.Second))
+ if err != nil {
+ t.Fatalf("Can't set unix connection timeout: %v", err)
+ }
+ _, oobn, _, _, err := ucr.ReadMsgUnix(nil, oob)
+ if err != nil {
+ t.Fatalf("UnixConn readMsg: %v", err)
+ }
+
+ scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
+ if err != nil {
+ t.Fatalf("ParseSocketControlMessage: %v", err)
+ }
+ if len(scms) != 1 {
+ t.Fatalf("got scms = %#v; expected 1 SocketControlMessage", scms)
+ }
+ scm := scms[0]
+ gotFDs, err := syscall.ParseUnixRights(&scm)
+ if err != nil {
+ t.Fatalf("syscall.ParseUnixRights: %v", err)
+ }
+ if len(gotFDs) != 1 {
+ t.Fatalf("got FDs %#v: wanted only 1 fd", gotFDs)
+ }
+ defer func() {
+ if err := syscall.Close(gotFDs[0]); err != nil {
+ t.Fatalf("fail to close gotFDs: %v", err)
+ }
+ }()
+
+ flags, err := fcntl(gotFDs[0], syscall.F_GETFD, 0)
+ if err != nil {
+ t.Fatalf("Can't get flags of fd:%#v, with err:%v", gotFDs[0], err)
+ }
+ if flags&syscall.FD_CLOEXEC == 0 {
+ t.Fatalf("got flags %#x, want %#x (FD_CLOEXEC) set", flags, syscall.FD_CLOEXEC)
+ }
+}
diff --git a/libgo/go/net/unixsock_test.go b/libgo/go/net/unixsock_test.go
index 0b13bf6..71092e8 100644
--- a/libgo/go/net/unixsock_test.go
+++ b/libgo/go/net/unixsock_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js && !plan9 && !windows
// +build !js,!plan9,!windows
package net
diff --git a/libgo/go/net/unixsock_windows_test.go b/libgo/go/net/unixsock_windows_test.go
index 5dccc14..29244f6 100644
--- a/libgo/go/net/unixsock_windows_test.go
+++ b/libgo/go/net/unixsock_windows_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build windows
// +build windows
package net
diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go
index d90f5f0..20de0f6 100644
--- a/libgo/go/net/url/url.go
+++ b/libgo/go/net/url/url.go
@@ -425,31 +425,31 @@ func (u *Userinfo) String() string {
return s
}
-// Maybe rawurl is of the form scheme:path.
+// Maybe rawURL is of the form scheme:path.
// (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
-// If so, return scheme, path; else return "", rawurl.
-func getscheme(rawurl string) (scheme, path string, err error) {
- for i := 0; i < len(rawurl); i++ {
- c := rawurl[i]
+// If so, return scheme, path; else return "", rawURL.
+func getScheme(rawURL string) (scheme, path string, err error) {
+ for i := 0; i < len(rawURL); i++ {
+ c := rawURL[i]
switch {
case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
// do nothing
case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
if i == 0 {
- return "", rawurl, nil
+ return "", rawURL, nil
}
case c == ':':
if i == 0 {
return "", "", errors.New("missing protocol scheme")
}
- return rawurl[:i], rawurl[i+1:], nil
+ return rawURL[:i], rawURL[i+1:], nil
default:
// we have encountered an invalid character,
// so there is no valid scheme
- return "", rawurl, nil
+ return "", rawURL, nil
}
}
- return "", rawurl, nil
+ return "", rawURL, nil
}
// split slices s into two substrings separated by the first occurrence of
@@ -466,15 +466,15 @@ func split(s string, sep byte, cutc bool) (string, string) {
return s[:i], s[i:]
}
-// Parse parses rawurl into a URL structure.
+// Parse parses a raw url into a URL structure.
//
-// The rawurl may be relative (a path, without a host) or absolute
+// The url may be relative (a path, without a host) or absolute
// (starting with a scheme). Trying to parse a hostname and path
// without a scheme is invalid but may not necessarily return an
// error, due to parsing ambiguities.
-func Parse(rawurl string) (*URL, error) {
+func Parse(rawURL string) (*URL, error) {
// Cut off #frag
- u, frag := split(rawurl, '#', true)
+ u, frag := split(rawURL, '#', true)
url, err := parse(u, false)
if err != nil {
return nil, &Error{"parse", u, err}
@@ -483,20 +483,20 @@ func Parse(rawurl string) (*URL, error) {
return url, nil
}
if err = url.setFragment(frag); err != nil {
- return nil, &Error{"parse", rawurl, err}
+ return nil, &Error{"parse", rawURL, err}
}
return url, nil
}
-// ParseRequestURI parses rawurl into a URL structure. It assumes that
-// rawurl was received in an HTTP request, so the rawurl is interpreted
+// ParseRequestURI parses a raw url into a URL structure. It assumes that
+// url was received in an HTTP request, so the url is interpreted
// only as an absolute URI or an absolute path.
-// The string rawurl is assumed not to have a #fragment suffix.
+// The string url is assumed not to have a #fragment suffix.
// (Web browsers strip #fragment before sending the URL to a web server.)
-func ParseRequestURI(rawurl string) (*URL, error) {
- url, err := parse(rawurl, true)
+func ParseRequestURI(rawURL string) (*URL, error) {
+ url, err := parse(rawURL, true)
if err != nil {
- return nil, &Error{"parse", rawurl, err}
+ return nil, &Error{"parse", rawURL, err}
}
return url, nil
}
@@ -505,27 +505,27 @@ func ParseRequestURI(rawurl string) (*URL, error) {
// viaRequest is true, the URL is assumed to have arrived via an HTTP request,
// in which case only absolute URLs or path-absolute relative URLs are allowed.
// If viaRequest is false, all forms of relative URLs are allowed.
-func parse(rawurl string, viaRequest bool) (*URL, error) {
+func parse(rawURL string, viaRequest bool) (*URL, error) {
var rest string
var err error
- if stringContainsCTLByte(rawurl) {
+ if stringContainsCTLByte(rawURL) {
return nil, errors.New("net/url: invalid control character in URL")
}
- if rawurl == "" && viaRequest {
+ if rawURL == "" && viaRequest {
return nil, errors.New("empty url")
}
url := new(URL)
- if rawurl == "*" {
+ if rawURL == "*" {
url.Path = "*"
return url, nil
}
// Split off possible leading "http:", "mailto:", etc.
// Cannot contain escaped characters.
- if url.Scheme, rest, err = getscheme(rawurl); err != nil {
+ if url.Scheme, rest, err = getScheme(rawURL); err != nil {
return nil, err
}
url.Scheme = strings.ToLower(url.Scheme)
@@ -909,15 +909,22 @@ func (v Values) Del(key string) {
delete(v, key)
}
+// Has checks whether a given key is set.
+func (v Values) Has(key string) bool {
+ _, ok := v[key]
+ return ok
+}
+
// ParseQuery parses the URL-encoded query string and returns
// a map listing the values specified for each key.
// ParseQuery always returns a non-nil map containing all the
// valid query parameters found; err describes the first decoding error
// encountered, if any.
//
-// Query is expected to be a list of key=value settings separated by
-// ampersands or semicolons. A setting without an equals sign is
-// interpreted as a key set to an empty value.
+// Query is expected to be a list of key=value settings separated by ampersands.
+// A setting without an equals sign is interpreted as a key set to an empty
+// value.
+// Settings containing a non-URL-encoded semicolon are considered invalid.
func ParseQuery(query string) (Values, error) {
m := make(Values)
err := parseQuery(m, query)
@@ -927,11 +934,15 @@ func ParseQuery(query string) (Values, error) {
func parseQuery(m Values, query string) (err error) {
for query != "" {
key := query
- if i := strings.IndexAny(key, "&;"); i >= 0 {
+ if i := strings.IndexAny(key, "&"); i >= 0 {
key, query = key[:i], key[i+1:]
} else {
query = ""
}
+ if strings.Contains(key, ";") {
+ err = fmt.Errorf("invalid semicolon separator in query")
+ continue
+ }
if key == "" {
continue
}
@@ -1009,6 +1020,8 @@ func resolvePath(base, ref string) string {
)
first := true
remaining := full
+ // We want to return a leading '/', so write it now.
+ dst.WriteByte('/')
for i >= 0 {
i = strings.IndexByte(remaining, '/')
if i < 0 {
@@ -1023,10 +1036,12 @@ func resolvePath(base, ref string) string {
}
if elem == ".." {
- str := dst.String()
+ // Ignore the leading '/' we already wrote.
+ str := dst.String()[1:]
index := strings.LastIndexByte(str, '/')
dst.Reset()
+ dst.WriteByte('/')
if index == -1 {
first = true
} else {
@@ -1045,7 +1060,12 @@ func resolvePath(base, ref string) string {
dst.WriteByte('/')
}
- return "/" + strings.TrimPrefix(dst.String(), "/")
+ // We wrote an initial '/', but we don't want two.
+ r := dst.String()
+ if len(r) > 1 && r[1] == '/' {
+ r = r[1:]
+ }
+ return r
}
// IsAbs reports whether the URL is absolute.
@@ -1058,11 +1078,11 @@ func (u *URL) IsAbs() bool {
// may be relative or absolute. Parse returns nil, err on parse
// failure, otherwise its return value is the same as ResolveReference.
func (u *URL) Parse(ref string) (*URL, error) {
- refurl, err := Parse(ref)
+ refURL, err := Parse(ref)
if err != nil {
return nil, err
}
- return u.ResolveReference(refurl), nil
+ return u.ResolveReference(refURL), nil
}
// ResolveReference resolves a URI reference to an absolute URI from
@@ -1151,8 +1171,8 @@ func (u *URL) Port() string {
// splitHostPort separates host and port. If the port is not valid, it returns
// the entire input as host, and it doesn't check the validity of the host.
// Unlike net.SplitHostPort, but per RFC 3986, it requires ports to be numeric.
-func splitHostPort(hostport string) (host, port string) {
- host = hostport
+func splitHostPort(hostPort string) (host, port string) {
+ host = hostPort
colon := strings.LastIndexByte(host, ':')
if colon != -1 && validOptionalPort(host[colon:]) {
diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go
index f02e4650..63c8e69 100644
--- a/libgo/go/net/url/url_test.go
+++ b/libgo/go/net/url/url_test.go
@@ -1295,10 +1295,10 @@ func TestResolveReference(t *testing.T) {
}
func TestQueryValues(t *testing.T) {
- u, _ := Parse("http://x.com?foo=bar&bar=1&bar=2")
+ u, _ := Parse("http://x.com?foo=bar&bar=1&bar=2&baz")
v := u.Query()
- if len(v) != 2 {
- t.Errorf("got %d keys in Query values, want 2", len(v))
+ if len(v) != 3 {
+ t.Errorf("got %d keys in Query values, want 3", len(v))
}
if g, e := v.Get("foo"), "bar"; g != e {
t.Errorf("Get(foo) = %q, want %q", g, e)
@@ -1313,6 +1313,18 @@ func TestQueryValues(t *testing.T) {
if g, e := v.Get("baz"), ""; g != e {
t.Errorf("Get(baz) = %q, want %q", g, e)
}
+ if h, e := v.Has("foo"), true; h != e {
+ t.Errorf("Has(foo) = %t, want %t", h, e)
+ }
+ if h, e := v.Has("bar"), true; h != e {
+ t.Errorf("Has(bar) = %t, want %t", h, e)
+ }
+ if h, e := v.Has("baz"), true; h != e {
+ t.Errorf("Has(baz) = %t, want %t", h, e)
+ }
+ if h, e := v.Has("noexist"), false; h != e {
+ t.Errorf("Has(noexist) = %t, want %t", h, e)
+ }
v.Del("bar")
if g, e := v.Get("bar"), ""; g != e {
t.Errorf("second Get(bar) = %q, want %q", g, e)
@@ -1322,57 +1334,125 @@ func TestQueryValues(t *testing.T) {
type parseTest struct {
query string
out Values
+ ok bool
}
var parseTests = []parseTest{
{
+ query: "a=1",
+ out: Values{"a": []string{"1"}},
+ ok: true,
+ },
+ {
query: "a=1&b=2",
out: Values{"a": []string{"1"}, "b": []string{"2"}},
+ ok: true,
},
{
query: "a=1&a=2&a=banana",
out: Values{"a": []string{"1", "2", "banana"}},
+ ok: true,
},
{
query: "ascii=%3Ckey%3A+0x90%3E",
out: Values{"ascii": []string{"<key: 0x90>"}},
+ ok: true,
+ }, {
+ query: "a=1;b=2",
+ out: Values{},
+ ok: false,
+ }, {
+ query: "a;b=1",
+ out: Values{},
+ ok: false,
+ }, {
+ query: "a=%3B", // hex encoding for semicolon
+ out: Values{"a": []string{";"}},
+ ok: true,
},
{
- query: "a=1;b=2",
- out: Values{"a": []string{"1"}, "b": []string{"2"}},
+ query: "a%3Bb=1",
+ out: Values{"a;b": []string{"1"}},
+ ok: true,
},
{
query: "a=1&a=2;a=banana",
- out: Values{"a": []string{"1", "2", "banana"}},
+ out: Values{"a": []string{"1"}},
+ ok: false,
+ },
+ {
+ query: "a;b&c=1",
+ out: Values{"c": []string{"1"}},
+ ok: false,
+ },
+ {
+ query: "a=1&b=2;a=3&c=4",
+ out: Values{"a": []string{"1"}, "c": []string{"4"}},
+ ok: false,
+ },
+ {
+ query: "a=1&b=2;c=3",
+ out: Values{"a": []string{"1"}},
+ ok: false,
+ },
+ {
+ query: ";",
+ out: Values{},
+ ok: false,
+ },
+ {
+ query: "a=1;",
+ out: Values{},
+ ok: false,
+ },
+ {
+ query: "a=1&;",
+ out: Values{"a": []string{"1"}},
+ ok: false,
+ },
+ {
+ query: ";a=1&b=2",
+ out: Values{"b": []string{"2"}},
+ ok: false,
+ },
+ {
+ query: "a=1&b=2;",
+ out: Values{"a": []string{"1"}},
+ ok: false,
},
}
func TestParseQuery(t *testing.T) {
- for i, test := range parseTests {
- form, err := ParseQuery(test.query)
- if err != nil {
- t.Errorf("test %d: Unexpected error: %v", i, err)
- continue
- }
- if len(form) != len(test.out) {
- t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
- }
- for k, evs := range test.out {
- vs, ok := form[k]
- if !ok {
- t.Errorf("test %d: Missing key %q", i, k)
- continue
+ for _, test := range parseTests {
+ t.Run(test.query, func(t *testing.T) {
+ form, err := ParseQuery(test.query)
+ if test.ok != (err == nil) {
+ want := "<error>"
+ if test.ok {
+ want = "<nil>"
+ }
+ t.Errorf("Unexpected error: %v, want %v", err, want)
}
- if len(vs) != len(evs) {
- t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
- continue
+ if len(form) != len(test.out) {
+ t.Errorf("len(form) = %d, want %d", len(form), len(test.out))
}
- for j, ev := range evs {
- if v := vs[j]; v != ev {
- t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
+ for k, evs := range test.out {
+ vs, ok := form[k]
+ if !ok {
+ t.Errorf("Missing key %q", k)
+ continue
+ }
+ if len(vs) != len(evs) {
+ t.Errorf("len(form[%q]) = %d, want %d", k, len(vs), len(evs))
+ continue
+ }
+ for j, ev := range evs {
+ if v := vs[j]; v != ev {
+ t.Errorf("form[%q][%d] = %q, want %q", k, j, v, ev)
+ }
}
}
- }
+ })
}
}
diff --git a/libgo/go/net/write_unix_test.go b/libgo/go/net/write_unix_test.go
index 6d8cb6a..f79f2d0 100644
--- a/libgo/go/net/write_unix_test.go
+++ b/libgo/go/net/write_unix_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package net
diff --git a/libgo/go/net/writev_test.go b/libgo/go/net/writev_test.go
index d603b7f..bf40ca2 100644
--- a/libgo/go/net/writev_test.go
+++ b/libgo/go/net/writev_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build !js
// +build !js
package net
diff --git a/libgo/go/net/writev_unix.go b/libgo/go/net/writev_unix.go
index 8b20f42..a0fedc2 100644
--- a/libgo/go/net/writev_unix.go
+++ b/libgo/go/net/writev_unix.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd
// +build darwin dragonfly freebsd illumos linux netbsd openbsd
package net