Search code examples
gowebsocketsocket.iocors

Go & Socket.io HTTP + WSS on one port with CORS?


Brand new to Go.. Still obviously learning the syntax and the basics.. But I do have a specific goal in mind..

I'm trying to just get a simple server up on :8080 that can respond to both HTTP and socket.io (via /socket.io/ url), specificaly with CORS.

My code:

package main

import (
     "log"         
     "net/http"
     "github.com/rs/cors"
     "github.com/googollee/go-socket.io"
 )

 func SayHelloWorld(w http.ResponseWriter, r *http.Request) {
     w.Write([]byte("Hello, World!"))
 }

 func main() {

   c := cors.New(cors.Options{
         AllowedOrigins: []string{"*"},
         AllowCredentials: true,
   })

   server, err := socketio.NewServer(nil)
     if err != nil {
         log.Fatal(err)
     }


   server.On("connection", func(so socketio.Socket) {
      log.Println("on connection")
      so.Join("chat")
      so.On("chat message", func(msg string) {
          log.Println("emit:", so.Emit("chat message", msg))
          so.BroadcastTo("chat", "chat message", msg)
      })
      so.On("disconnection", func() {
          log.Println("on disconnect")
      })
   })

   server.On("error", func(so socketio.Socket, err error) {
      log.Println("error:", err)
   })    


   http.Handle("/socket.io/", c.Handler(server))
   http.HandleFunc("/", SayHelloWorld)
   log.Println("Serving at localhost:8080...")
   log.Fatal(http.ListenAndServe(":8080", nil))
}

On the client side I'm still seeing:

WebSocket connection to 'wss://api.domain.com/socket.io/?EIO=3&transport=websocket&sid=xNWd9aZvwDnZOrXkOBaC' failed: WebSocket is closed before the connection is established.

(index):1 XMLHttpRequest cannot load https://api.domain.com/socket.io/?EIO=3&transport=polling&t=1420662449235-3932&sid=xNWd9aZvwDnZOrXkOBaC. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fiddle.jshell.net' is therefore not allowed access.

EDIT #1:

So I've been banging my head away trying to understand why I can't connect.. Came across an even more confusing piece of the puzzle?

https://gist.github.com/acoyfellow/167b055da85248c94fc4

The above gist is the code of my golang server + the browser code used to connect.. This code will send 30 HTTP GET requests per second to the backend, without connecting, upgrading, or giving any errors (client or server side).. it essentially DDOS's my own backend?

Someone, please someone tell me I'm doing something stupid.. This is quite the pickle :P

EDIT #2:

I can stop the "DDOS" by simply adjusting the trailing / on the URL of the socket.io endpoint in Go.. So: mux.Handle("/socket.io", server) to mux.Handle("/socket.io/", server) will now produce error messages and connection attempts with error responses of:

WebSocket connection to 'wss://api.domain.com/socket.io/?EIO=3&transport=websocket&sid=0TzmTM_QtF1TaS4exiwF' failed: Error during WebSocket handshake: Unexpected response code: 400 socket.io-1.2.1.js:2

GET https://api.domain.com/socket.io/?EIO=3&transport=polling&t=1420743204485-62&sid=0TzmTM_QtF1TaS4exiwF 400 (Bad Request)


Solution

  • So I gave up using googoolee's Socket.io implementation and went with gorilla's.

    I checked out their examples: https://github.com/gorilla/websocket/tree/master/examples/chat

    Checked out their docs: http://www.gorillatoolkit.org/pkg/websocket -- Under Origin Considerations I found:

    An application can allow connections from any origin by specifying a function that always returns true:

    var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, }

    I added this CheckOrigin function to the conn.go file in their example, and was able to get a CORS socket server talking to a browser.

    As a first adventure into Golang, this was frustrating and fun.. +1 to anyone else learning