valyala / fasthttp

Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http
MIT License
21.94k stars 1.76k forks source link

[Bug/Question] Hostclient sends content-type header on DELETE request even if it is not set #873

Open shkreios opened 4 years ago

shkreios commented 4 years ago

Hey, I just started to learn golang as well as fashttp. I tried to build a fasthttp reverse proxy using this libary and later using the code from this issue.

All requests work without any problems, only on delete requests the hostclient adds the header content-typewith the value application/x-www-form-urlencoded.

The server to which the request is proxyed responds with 406, is there a way to disable this behavior?

Thank you in advance for any help.

Code example: In the code example I don't use a proxy just the fashttp.Client to make a request with the request method set to DELETE. I have tested the behavior with a fashttp and express server, the code is shown below.

sender.go

package main

import (
    "fmt"

    "github.com/valyala/fasthttp"
)

func main() {
    req := fasthttp.AcquireRequest()

    resp := fasthttp.AcquireResponse()
    req.SetRequestURI("http://localhost:3000/")

    req.Header.SetMethod("DELETE")

    req.Header.Del("content-type")

    client := &fasthttp.Client{}
    fmt.Printf("Content-Type: %s\n", string(req.Header.ContentType()))
    client.Do(req, resp)
    fmt.Printf("Content-Type: %s\n", string(req.Header.ContentType()))

    fmt.Println(resp.StatusCode(), string(resp.Body()))
    fmt.Println(string(resp.Body()))

}

Output:

Content-Type: 
Content-Type: 
200 OK
OK

receiver.go

package main

import (
    "fmt"

    "github.com/valyala/fasthttp"
)

func fastHTTPHandler(ctx *fasthttp.RequestCtx) {

    fmt.Println(string(ctx.Request.Header.Header()))

    fmt.Fprintf(ctx, "Hi there! RequestURI is %q", ctx.RequestURI())

}

func main() {
    fmt.Println("server started...")

    server := &fasthttp.Server{
        Handler: fastHTTPHandler,
    }

    err := server.ListenAndServe(":3000")
    if err != nil {
        panic(err)
    }

}

Output:

DELETE / HTTP/1.1
User-Agent: fasthttp
Host: localhost:3000
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

Express JS Server example server.js

const express = require('express');
const app = express();
const port = 3000;

app.use((req, res, next) => {
  console.log(req.headers);
  res.sendStatus(200);
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

Output:

{
  'user-agent': 'fasthttp',
  host: 'localhost:3000',
  'content-type': 'application/x-www-form-urlencoded',
  'content-length': '0'
}
erikdubbelboer commented 4 years ago

This is because fasthttp always wants to set a Content-Type header for non GET/HEAD requests: https://github.com/valyala/fasthttp/blob/aa3f96c883322033099b4466c151893a3f9c2172/header.go#L1593-L1595

It is currently not possible to disable this.

Maybe it would work for you to set the Content-Type to text/plain?

shkreios commented 4 years ago

@erikdubbelboer Thank you for your answer. text/plain does not work but the app strangely accepts application/json even if the body is empty. Do you think it will be possible to disable this in the future? Because I want to use fashttp as reverse proxy and it is not possible for me to create a "failover" for all potentially wrong set Content-Type headers. Thanks again for your time.

erikdubbelboer commented 4 years ago

For ResponseHeader we have ResponseHeader.SetNoDefaultContentType(). I think we should add something similar for RequestHeader.