Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ type Dialer struct {
// If KeepAliveConfig.Enable is false and KeepAlive is negative,
// keep-alive probes are disabled.
KeepAliveConfig KeepAliveConfig

// Resolver optionally specifies an alternate resolver to use.
//
// TINYGO: present for API compatibility; DialContext resolves via the
// netdev-backed ResolveTCPAddr/ResolveUDPAddr and does not consult this
// field.
Resolver *Resolver
}

// Dial connects to the address on the named network.
Expand Down Expand Up @@ -281,3 +288,22 @@ func Listen(network, address string) (Listener, error) {

return listenTCP(laddr)
}

// ListenPacket announces on the local network address.
//
// TINYGO: only UDP networks are supported, backed by ListenUDP; the
// returned PacketConn is a *UDPConn.
func ListenPacket(network, address string) (PacketConn, error) {
switch network {
case "udp", "udp4":
default:
return nil, fmt.Errorf("Network %s not supported", network)
}

laddr, err := ResolveUDPAddr(network, address)
if err != nil {
return nil, err
}

return ListenUDP(network, laddr)
}
47 changes: 47 additions & 0 deletions dnserror.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// TINYGO: The following is copied and modified from Go 1.26.2 official implementation.

// Copyright 2018 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 net

// DNSError represents a DNS lookup error.
type DNSError struct {
UnwrapErr error // error returned by the [DNSError.Unwrap] method, might be nil
Err string // description of the error
Name string // name looked for
Server string // server used
IsTimeout bool // if true, timed out; not all timeouts set this
IsTemporary bool // if true, error is temporary; not all errors set this

// IsNotFound is set to true when the requested name does not
// contain any records of the requested type (data not found),
// or the name itself was not found (NXDOMAIN).
IsNotFound bool
}

// Unwrap returns e.UnwrapErr.
func (e *DNSError) Unwrap() error { return e.UnwrapErr }

func (e *DNSError) Error() string {
if e == nil {
return "<nil>"
}
s := "lookup " + e.Name
if e.Server != "" {
s += " on " + e.Server
}
s += ": " + e.Err
return s
}

// Timeout reports whether the DNS lookup is known to have timed out.
// This is not always known; a DNS lookup may fail due to a timeout
// and return a [DNSError] for which Timeout returns false.
func (e *DNSError) Timeout() bool { return e.IsTimeout }

// Temporary reports whether the DNS error is known to be temporary.
// This is not always known; a DNS lookup may fail due to a temporary
// error and return a [DNSError] for which Temporary returns false.
func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary }
6 changes: 6 additions & 0 deletions http/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ package http
import (
"bufio"
"bytes"
"crypto/tls"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -117,6 +118,11 @@ type Response struct {
// Request's Body is nil (having already been consumed).
// This is only populated for Client requests.
Request *Request

// TLS contains information about the TLS connection on which the response
// was received. It is nil for unencrypted responses. TINYGO: populated only
// if a caller sets it; the wasm fetch path leaves it nil.
TLS *tls.ConnectionState
}

// Cookies parses and returns the cookies set in the Set-Cookie headers.
Expand Down
152 changes: 152 additions & 0 deletions http/responsecontroller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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)
}
17 changes: 17 additions & 0 deletions http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2779,6 +2779,23 @@ type Server struct {
// value.
ConnContext func(ctx context.Context, c net.Conn) context.Context

// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
// If TLSNextProto is not nil, HTTP/2 support is not enabled
// automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)

// HTTP2 configures HTTP/2 connections.
//
// This field does not yet have any effect.
// See https://go.dev/issue/67813.
HTTP2 *HTTP2Config

inShutdown atomicBool // true when server is in shutdown

disableKeepAlives int32 // accessed atomically.
Expand Down
Loading