chi icon indicating copy to clipboard operation
chi copied to clipboard

CleanPath middleware does not work correctly with http CONNECT requests

Open samiponkanenssh opened this issue 2 years ago • 2 comments

If the same router handles REST API requests and http CONNECT requests, then it is not possible to use middleware.CleanPath. CleanPath will mess up ctx.RoutePath for typical http CONNECT URIs, which are of the format host:port. This causes go-chi to respond to CONNECT requests with 404 Not Found.

I need to use to a workaround like below to get it working. Fixing middleware.CleanPath to not do anything for CONNECT requests would be the correct fix.

package main

import (
        "log"
        "net/http"
        "net/http/httputil"

        "github.com/go-chi/chi/v5"
        "github.com/go-chi/chi/v5/middleware"
)

func main() {
        mux := chi.NewRouter()
        mux.Use(middleware.CleanPath)
        mux.Use(httpConnectMiddleWare)
        mux.Method("GET", "/", http.HandlerFunc(ServeDefault))
        mux.Method("CONNECT", "/*", http.HandlerFunc(ServeConnect))

        http.ListenAndServe("127.0.0.1:8080", mux)
}

func httpConnectMiddleWare(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                ctx := chi.RouteContext(r.Context())
                if r.Method == http.MethodConnect {
                        ctx.RoutePath = "/"
                }
                next.ServeHTTP(w, r)
        })
}

func ServeDefault(w http.ResponseWriter, r *http.Request) {
        dump, _ := httputil.DumpRequest(r, false)
        log.Printf("%s", string(dump))
}

func ServeConnect(w http.ResponseWriter, r *http.Request) {
        dump, _ := httputil.DumpRequest(r, false)
        log.Printf("%s", string(dump))
}

samiponkanenssh avatar Mar 27 '23 09:03 samiponkanenssh

@samiponkanenssh Hi, I ran your script and test with provided format host:port, but seems it returns the expected response, not 404. will you share the request for reproducing 404?

❯ curl localhost:8080/t/e///s/t/// -X CONNECT -I
HTTP/1.1 200 OK
Date: Sat, 20 May 2023 05:38:23 GMT
Content-Length: 0


❯ curl localhost:8080/t/e///s/t/// -X GET -I
HTTP/1.1 405 Method Not Allowed
Date: Sat, 20 May 2023 05:38:28 GMT
Content-Length: 0


❯ curl localhost:8080/ -X GET -I
HTTP/1.1 200 OK
Date: Sat, 20 May 2023 05:38:32 GMT
Content-Length: 0

kubosuke avatar May 20 '23 05:05 kubosuke

@kubosuke

Hi,

Sorry for the late response.

Your curl command will not produce a valid HTTP CONNECT request:

 curl -v localhost:8080/t/e///s/t/// -X CONNECT -I
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> CONNECT /t/e///s/t/// HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Tue, 06 Jun 2023 13:53:04 GMT
Date: Tue, 06 Jun 2023 13:53:04 GMT
< Content-Length: 0
Content-Length: 0

< 
* Connection #0 to host localhost left intact

However if you use netcat, you will see this error without the workaround:

$ nc -v -X connect -x localhost:8080 google.com 443
nc: Proxy error: "HTTP/1.0 404 Not Found"

With the workaround you will see this:

$ nc -v -X connect -x localhost:8080 google.com 443
Connection to google.com 443 port [tcp/https] succeeded!
^C

Br, Sami

samiponkanenssh avatar Jun 06 '23 13:06 samiponkanenssh