net icon indicating copy to clipboard operation
net copied to clipboard

Lookup failed for simple http.Get("https://httpbin.org/anything")

Open giper45 opened this issue 2 months ago • 1 comments

Hi, thank you for the project! I am wondering if I am wrong something with this simple PoC:

package main

import (
	"fmt"
	"net/http"

	_ "github.com/stealthrocket/net/http"
)


func main() {

	// Use hostname in URL so TLS certificate validation succeeds.
	resp, err := http.Get("https://httpbin.org/anything")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	fmt.Println("Response Status:", resp.Status)
	fmt.Println("Response Headers:", resp.Header)
}

 $ GOOS=wasip1 GOARCH=wasm go build -o main.wasm main.go
 $ wasmedge main.wasm 
panic: Get "https://httpbin.org/anything": dial httpbin.org:443 httpbin.org:443: lookup httpbin.org on [::1]:53: Connection refused

goroutine 1 [running]:
main.main()
	...golang-wasm/http/main.go:16 +0x20

Also tried with macOS and Linux, with wasirun and nothing, it seems that lookup fails.

giper45 avatar Oct 20 '25 07:10 giper45

I have found this "tricky" approach:

package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	_ "embed"
	"fmt"
	"io"
	"net"
	"net/http"

	_ "github.com/stealthrocket/net/http"
	"github.com/stealthrocket/net/wasip1"
)

//go:embed cacert.pem
var caCertsPEM []byte

func main() {
	// Load CA certificates from embedded file
	certPool := x509.NewCertPool()
	if !certPool.AppendCertsFromPEM(caCertsPEM) {
		panic("Failed to parse CA certificates")
	}

	// Override the default resolver to use 1.1.1.1:53 explicitly
	net.DefaultResolver = &net.Resolver{
		PreferGo: true,
		Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
			// Force use of 1.1.1.1:53 instead of [::1]:53
			return wasip1.DialContext(ctx, network, "1.1.1.1:53")
		},
	}

	// Create HTTP client with custom TLS config and dialer
	client := &http.Client{
		Transport: &http.Transport{
			DialContext: wasip1.DialContext,
			TLSClientConfig: &tls.Config{
				RootCAs: certPool,
			},
		},
	}

	fmt.Println("Fetching https://httpbin.org/anything ...")

	resp, err := client.Get("https://httpbin.org/anything")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	fmt.Println("Response Status:", resp.Status)
	fmt.Println("Response Headers:", resp.Header)

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	fmt.Printf("\nBody (first 500 chars):\n%s\n", string(body[:min(len(body), 500)]))
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

this solves the certificate problem (curl -o cacert.pem https://curl.se/ca/cacert.pem)

And defines the DNS resolver.

I would like to find a way that this become transparent when compiling existing projects in wasm.

Do you know if is there some approach to hide this conversion when a user call http.Get?

giper45 avatar Oct 20 '25 07:10 giper45