gorilla/websocket

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

  1. Use Gorilla WebSocket in a scenario where the Host header contains a space at the end.
  2. 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

image

When I don't use space it detects by censorship and I get 403 error code:
image

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
}