go http server doesn't send 100 continue

112 Views Asked by At

I have a service that collects and processes data (more precisely road traffic data in Datex2) from different governmental organizations. I want to send a 100-continue with a Go http server to a client that sends a request with this header:

Content-Length: "4914"]
Content-Type: "application/xml"
Expect: "100-continue"

The client doesn't send authorization credentials with this request. It waits for the 100 to send a second request, which will contain the auth credentials.

I don't want to read the body of the first request, which would let to sending 100, because I first want to get the authorization credentials.

Here is one example of the codes i tried to use:

if c.Request.Header.Get("Expect") != "" {
    c.Writer.WriteHeader(http.StatusContinue)
    c.Writer.WriteHeaderNow()
    time.Sleep(30 * time.Second)
    return
}

In my understanding this should send the 100 immediately. But I sends a response (200) when return is reached. With reference to this answer, I send requests with different informations in the header, but nothing worked out..

Edit: Here are sample client:

func main() {

    client := http.Client{}
    reqBody := []byte(`{"somekey":"somevalue"}`)

    req, err := http.NewRequest(http.MethodPost, "http://localhost:8080/somepath", bytes.NewBuffer(reqBody))
    if err != nil {
        panic(err)
    }

    req.Header.Set("Expect", "100-continue")

    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }

    if resp.StatusCode != http.StatusContinue {
        panic("invalid status code")
    } else {
        println("ok")
    }
}

and server:

func main() {
    server := http.Server{
        Addr:    "localhost:8080",
        Handler: http.HandlerFunc(Handle),
    }

    server.ListenAndServe()
}

func Handle(w http.ResponseWriter, r *http.Request) {
    if r.Header.Get("Expect") == "100-continue" {
        w.WriteHeader(http.StatusContinue)
        return
    }
}

I get response code 200.

2

There are 2 best solutions below

1
NotX On

If I understand "But I sends a response (200) when return is reached" correctly, you're receiving a 200 code instead of a 100 at the client side.

I don't know what c.Writer is in your example, but you're probably invoking ResponseWriter#Write at some point. See the documentation:

If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) before writing the data.

From my testing, the response code will also set to be 200 if you call ResponseWriter#Write after invoking ResponseWriter.WriteHeader(StatusContinue).

So long story short: don't invoke ResponseWriter#Write. Since c.Writer seems to be some wrapper around the ResponseWriter (since that one doesn't have a WriteHeaderNow method), make also sure your wrapping library doesn't write anything to the response body either.

1
Melinda Jacobson On

If the client set the Expect: 100-continue header, then the net/http server sends the HTTP/1.1 100 Continue response on first read of the request body.

Here's how to handle 100-continue in the handler:

 func example(w http.ResponseWriter, r *http.Request) {
     // Check request headers.  The handler must not read the
     // the request body while doing this.
     u, ok := auth(r)
     if !ok {
          // Auth failed, write header and exit.
          http.Error(w, "auth required", http.StatusForbidden)
          return
     }
     // Read the request body.
     // The net/http server sends 100-continue on the first
     // call to Read on the request body.
     err := r.ParseMultipartForm(10000)
     ...
}