mirror of
https://github.com/tinygo-org/net.git
synced 2026-07-26 08:18:39 +00:00
d5da3ddeef
* net: add UDP listen, resolver, DNSError, and TCP listener APIs for wasm TinyGo's net package was missing several symbols that upstream Go's js/wasm net declares, blocking builds that pull pion/transport, pion/dtls, and similar (via netbird's WASM client). Add them, backed by the existing netdev abstraction so they compile for all targets and no-op cleanly under nopNetdev (matching Go's js runtime behavior): - DNSError type (dnserror.go), copied from Go 1.26.2. - Resolver + DefaultResolver with LookupHost/LookupIP/LookupIPAddr/ LookupNetIP/LookupPort; LookupHost/LookupIP package funcs; Dialer.Resolver field for API compatibility. - UDPConn: ListenUDP, ReadFromUDP(AddrPort), WriteToUDP(AddrPort), SetReadBuffer, SetWriteBuffer. - TCPConn: CloseRead, SetNoDelay, SetReadBuffer, SetWriteBuffer, ReadFrom(io.Reader). - TCPListener: ListenTCP, AcceptTCP, SetDeadline; ListenPacket package func. - Interface: Addrs, MulticastAddrs stubs. * more complete PR for adding more net support (#64) * format unixsock
153 lines
4.5 KiB
Go
153 lines
4.5 KiB
Go
// TINYGO: Copied verbatim from the Go 1.26.2 official implementation to provide
|
|
// the ResponseController API used by net/http/httputil (reverse proxy). The
|
|
// underlying methods degrade to ErrNotSupported when the ResponseWriter does
|
|
// not implement them, which is the standard behavior.
|
|
|
|
// Copyright 2022 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 http
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// A ResponseController is used by an HTTP handler to control the response.
|
|
//
|
|
// A ResponseController may not be used after the [Handler.ServeHTTP] method has returned.
|
|
type ResponseController struct {
|
|
rw ResponseWriter
|
|
}
|
|
|
|
// NewResponseController creates a [ResponseController] for a request.
|
|
//
|
|
// The ResponseWriter should be the original value passed to the [Handler.ServeHTTP] method,
|
|
// or have an Unwrap method returning the original ResponseWriter.
|
|
//
|
|
// If the ResponseWriter implements any of the following methods, the ResponseController
|
|
// will call them as appropriate:
|
|
//
|
|
// Flush()
|
|
// FlushError() error // alternative Flush returning an error
|
|
// Hijack() (net.Conn, *bufio.ReadWriter, error)
|
|
// SetReadDeadline(deadline time.Time) error
|
|
// SetWriteDeadline(deadline time.Time) error
|
|
// EnableFullDuplex() error
|
|
//
|
|
// If the ResponseWriter does not support a method, ResponseController returns
|
|
// an error matching [ErrNotSupported].
|
|
func NewResponseController(rw ResponseWriter) *ResponseController {
|
|
return &ResponseController{rw}
|
|
}
|
|
|
|
type rwUnwrapper interface {
|
|
Unwrap() ResponseWriter
|
|
}
|
|
|
|
// Flush flushes buffered data to the client.
|
|
func (c *ResponseController) Flush() error {
|
|
rw := c.rw
|
|
for {
|
|
switch t := rw.(type) {
|
|
case interface{ FlushError() error }:
|
|
return t.FlushError()
|
|
case Flusher:
|
|
t.Flush()
|
|
return nil
|
|
case rwUnwrapper:
|
|
rw = t.Unwrap()
|
|
default:
|
|
return errNotSupported()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hijack lets the caller take over the connection.
|
|
// See the [Hijacker] interface for details.
|
|
func (c *ResponseController) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
rw := c.rw
|
|
for {
|
|
switch t := rw.(type) {
|
|
case Hijacker:
|
|
return t.Hijack()
|
|
case rwUnwrapper:
|
|
rw = t.Unwrap()
|
|
default:
|
|
return nil, nil, errNotSupported()
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetReadDeadline sets the deadline for reading the entire request, including the body.
|
|
// Reads from the request body after the deadline has been exceeded will return an error.
|
|
// A zero value means no deadline.
|
|
//
|
|
// Setting the read deadline after it has been exceeded will not extend it.
|
|
func (c *ResponseController) SetReadDeadline(deadline time.Time) error {
|
|
rw := c.rw
|
|
for {
|
|
switch t := rw.(type) {
|
|
case interface{ SetReadDeadline(time.Time) error }:
|
|
return t.SetReadDeadline(deadline)
|
|
case rwUnwrapper:
|
|
rw = t.Unwrap()
|
|
default:
|
|
return errNotSupported()
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetWriteDeadline sets the deadline for writing the response.
|
|
// Writes to the response body after the deadline has been exceeded will not block,
|
|
// but may succeed if the data has been buffered.
|
|
// A zero value means no deadline.
|
|
//
|
|
// Setting the write deadline after it has been exceeded will not extend it.
|
|
func (c *ResponseController) SetWriteDeadline(deadline time.Time) error {
|
|
rw := c.rw
|
|
for {
|
|
switch t := rw.(type) {
|
|
case interface{ SetWriteDeadline(time.Time) error }:
|
|
return t.SetWriteDeadline(deadline)
|
|
case rwUnwrapper:
|
|
rw = t.Unwrap()
|
|
default:
|
|
return errNotSupported()
|
|
}
|
|
}
|
|
}
|
|
|
|
// EnableFullDuplex indicates that the request handler will interleave reads from [Request.Body]
|
|
// with writes to the [ResponseWriter].
|
|
//
|
|
// For HTTP/1 requests, the Go HTTP server by default consumes any unread portion of
|
|
// the request body before beginning to write the response, preventing handlers from
|
|
// concurrently reading from the request and writing the response.
|
|
// Calling EnableFullDuplex disables this behavior and permits handlers to continue to read
|
|
// from the request while concurrently writing the response.
|
|
//
|
|
// For HTTP/2 requests, the Go HTTP server always permits concurrent reads and responses.
|
|
func (c *ResponseController) EnableFullDuplex() error {
|
|
rw := c.rw
|
|
for {
|
|
switch t := rw.(type) {
|
|
case interface{ EnableFullDuplex() error }:
|
|
return t.EnableFullDuplex()
|
|
case rwUnwrapper:
|
|
rw = t.Unwrap()
|
|
default:
|
|
return errNotSupported()
|
|
}
|
|
}
|
|
}
|
|
|
|
// errNotSupported returns an error that Is ErrNotSupported,
|
|
// but is not == to it.
|
|
func errNotSupported() error {
|
|
return fmt.Errorf("%w", ErrNotSupported)
|
|
}
|