WebSocket connection failure with Host header containing a space
Platon929 opened this issue · 1 comments
Is there an existing issue for this?
- I have searched the existing issues
Current Behavior
I'm experiencing an issue with the Gorilla WebSocket library used in V2Ray. The problem arises when attempting to establish a connection using a Host header with a space at the end. Surprisingly, when I use Postman with a space in the last URL, the connection works perfectly. However, with Gorilla WebSocket, I encounter a bad request error.
Expected Behavior
I expect Gorilla WebSocket to handle connections with a Host header containing a space similarly to how it works in Postman.
Steps To Reproduce
- Use Gorilla WebSocket in a scenario where the Host header contains a space at the end.
- Observe the bad request error.
Anything else?
This issue is crucial for bypassing censorship in certain environments, and any assistance in resolving or understanding this behavior would be greatly appreciated.
I believe the host header property is being altered in the request because, when I change encoded spaces to %20
, I encounter the same error in Postman.
Debug Data
Sample Code
socketHost := "www.speedtest.net"
socketURL := "ws://" + socketHost
hostHeaderValue := "cdn.MYHOSTNAME.space "
dialer := websocket.Dialer{}
header := http.Header{}
header.Add("Host", hostHeaderValue)
Request
{"GET" "http://www.speedtest.net" "HTTP/1.1" '\x01' '\x01' map["Connection":["Upgrade"] "Sec-WebSocket-Key":["H3ljhyX3xaAgV83eAM02Ow=="] "Sec-WebSocket-Version":["13"] "Upgrade":["websocket"]] <nil> %!q(func() (io.ReadCloser, error)=<nil>) '\x00' [] %!q(bool=false) "cdn.MYHOSTNAME.space " map[] map[] %!q(*multipart.Form=<nil>) map[] "" "" %!q(*tls.ConnectionState=<nil>) %!q(<-chan struct {}=<nil>) %!q(*http.Response=<nil>) {{}}}
response
{"400 Bad Request" 'Ɛ' "HTTP/1.1" '\x01' '\x01' map["Cf-Ray":["-"] "Content-Length":["155"] "Content-Type":["text/html"] "Date":["Tue, 23 Jan 2024 18:13:50 GMT"] "Server":["cloudflare"]] %!q(*http.body=&{0xc000012168 <nil> <nil> true false {0 0} false false false <nil>}) '\u009b' [] %!q(bool=true) %!q(bool=false) map[] %!q(*http.Request=&{GET 0xc000138000 HTTP/1.1 1 1 map[Connection:[Upgrade] Sec-WebSocket-Key:[H3ljhyX3xaAgV83eAM02Ow==] Sec-WebSocket-Version:[13] Upgrade:[websocket]] <nil> <nil> 0 [] false cdn.MYHOSTNAME.space map[] map[] <nil> map[] <nil> <nil> <nil> {{}}}) %!q(*tls.ConnectionState=<nil>)}
PostMan
When I don't use space it detects by censorship and I get 403 error code:
Another example using CURL works fine(with space):
curl -v -X GET "http://www.speedtest.net/" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: puNMlmuJTEbtspljcos8LQ==" -H "Sec-WebSocket-Version: 13" -H "Upgrade: websocket" -H "Host: cdn.MYHOSTNAME.space "
it's related to golang and httplex.go
func ValidHostHeader(h string) bool {
// The latest spec is actually this:
//
// http://tools.ietf.org/html/rfc7230#section-5.4
// Host = uri-host [ ":" port ]
//
// Where uri-host is:
// http://tools.ietf.org/html/rfc3986#section-3.2.2
//
// But we're going to be much more lenient for now and just
// search for any byte that's not a valid byte in any of those
// expressions.
for i := 0; i < len(h); i++ {
if !validHostByte[h[i]] {
return false
}
}
return true
}