in Go, Tips

Run offical Go language tutorial (A Tour of Go) on a server

Recently I am learning Go language for the distributed system course. Basically, golang is a programming language developed by Google – it has a C-like code style and an enhanced support for concurrency, which means writing a server with golang is a good idea.

Golang has an online version tutorial here. It has a server-based compiler and allow you to run some script. Since it is on a public server, its speed is somewhat slow. In this case, I planned to run the gotour on my own VPS.

I downloaded and started gotour on my VPS. However, when I saw an message told me to open a browser and type http://127.0.0.1:3999, I realized that things could not be that easy. As expected, directly visit 3999 port will receive an instant HTTP error.

Leaving in China behind firewall for years, I instantly remind the SSH tunnel. By using SSH tunnel, you don’t need any extra software and you can access 3999 port as if you were localhost. By experiment, it did work but it was quite slow, which reminded me the days in China. After all, SSH is not designed for proxy.

I searched on Google but it seems that no one cares about that, and I had to figure out myself. By searching the source code, I find two places was related to localhost. Both in client.go, like:

var (
	httpListen  = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	openBrowser = flag.Bool("openbrowser", true, "open browser automatically")
)

(The other one is to display an warning message. I didn’t attempt to modified it)

Ah-hah! httpListen, a really easy-understanding name, right? Now change it to 0.0.0.0:3999. Don’t forget to type go install to compile. Now, I got an warning message:

WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

Really look like an important notice, right? Okay, I admit that allowing others to run program on my server is not a good idea.

I opened my local web browser, successfully received the tutorial page. However, to my suppress, I couldn’t run any code, and got an error message like:

2016/01/** **:**:** bad websocket origin: http://****.***:3999

It seems that the program also check the websocket origin. I searched Google for that, only to get some irrelevant results.

However, since both gotour and golang is open-source, I can look into the source code. Just check on GitHub. Search on the top of the website. Nothing relevant in tour itself, but something relevant in tools:

// NewHandler returns a websocket server which checks the origin of requests.
func NewHandler(origin *url.URL) websocket.Server {
	return websocket.Server{
		Config:    websocket.Config{Origin: origin},
		Handshake: handshake,
		Handler:   websocket.Handler(socketHandler),
	}
}

// handshake checks the origin of a request during the websocket handshake.
func handshake(c *websocket.Config, req *http.Request) error {
	o, err := websocket.Origin(c, req)
	if err != nil {
		log.Println("bad websocket origin:", err)
		return websocket.ErrBadWebSocketOrigin
	}
	_, port, err := net.SplitHostPort(c.Origin.Host)
	if err != nil {
		log.Println("bad websocket origin:", err)
		return websocket.ErrBadWebSocketOrigin
	}
	ok := c.Origin.Scheme == o.Scheme && (c.Origin.Host == o.Host || c.Origin.Host == net.JoinHostPort(o.Host, port))
	if !ok {
		log.Println("bad websocket origin:", o)
		return websocket.ErrBadWebSocketOrigin
	}
	log.Println("accepting connection from:", req.RemoteAddr)
	return nil
}

It seems that when you call NewHandler, it will check the origin  in handshake(). If not passed, it will print an error message like that.

So, where is NewHandler() called in gotour? Well, there:

origin := &url.URL{Scheme: "http", Host: host + ":" + port}
http.Handle(socketPath, socket.NewHandler(origin))

Ah-hah! We find it! I changed host to 0.0.0.0 to bind the listener to all possible address, but obviously we can’t access it by 0.0.0.0. Just change host to hostname or IP address which you will type in the address bar, and it works! Of course you can specify the listened host at the very beginning, which is probably better.

Once again, I admit that allowing others to run program on my server is not a good idea. Perhaps the public server runs gotour in a chroot jail or things like that to reduce safety risk. When you are on your own, you have to take care about everything on your own as well. Perhaps it is something like “growing pains”, well…

Write a Comment

Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.