deislabs / wagi

Write HTTP handlers in WebAssembly with a minimal amount of work
Apache License 2.0
884 stars 45 forks source link

Cannot parse response from Go's `net/http/cgi` package #171

Closed radu-matei closed 2 years ago

radu-matei commented 2 years ago

I am trying to get the following Go program to run in Wagi:

package main

import (
    "fmt"
    "net/http"
    "net/http/cgi"
)

func main() {
    if err := cgi.Serve(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        header := w.Header()
        header.Set("Content-Type", "text/plain; charset=utf-8")

        fmt.Fprintln(w, "Hello, world!")

    })); err != nil {
        fmt.Println(err)
    }
}

Building it with TinyGo:

$ tinygo build -wasm-abi=generic -target=wasi -o main.wasm main.go

Then running it in Wagi (which prints the raw response):

FULL RESPONSE: 
Status: 200 OK
Content-Type: text/plain; charset=utf-8

Hello, world!

ERROR wagi::http_util: HTTP 500 error error=Exactly one of 'location' or 'content-type' must be specified

Not exactly why this is not parsing the response properly.

cc @bketelsen @technosophos

radu-matei commented 2 years ago

Ah, more context:

DEBUG wagi::handlers: composing response
FULL RESPONSE: 
Status: 200 OK
Content-Type: text/plain; charset=utf-8

Hello, world!

WARN wagi::http_util: corrupt header header=""
DEBUG wagi::handlers: Body(Full(b"Status: 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nHello, world!\n"))
ERROR wagi::http_util: HTTP 500 error error=Exactly one of 'location' or 'content-type' must be specified

So it is interpreting the headers as part of the body.

radu-matei commented 2 years ago

Manually adding a newline between headers and the body works:

package main

import (
    "fmt"
    "net/http"
    "net/http/cgi"
)

func main() {
    if err := cgi.Serve(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        header := w.Header()
        header.Set("Content-Type", "text/plain; charset=utf-8")
        fmt.Fprintf(w, "\n")

        fmt.Fprintln(w, "Hello, world!")

    })); err != nil {
        fmt.Println(err)
    }
}
radu-matei commented 2 years ago

In the scenario where this is failing (without manually adding the newline), this is how Wagi interprets the response:

b"Status: 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nHello, world!\n"

According to the spec:

The response comprises a message-header and a message-body, separated by a blank line. (https://datatracker.ietf.org/doc/html/rfc3875#section-6.2)

Should this be valid in Wagi?

Relevant implementation in Wagi — https://github.com/deislabs/wagi/blob/113749eee9dc88eb3fb9b46c331061fa78423d76/src/handlers.rs#L144-L164