// ServeHTTP implements the HTTP Handler interface of the http package. func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Get the URL path. path := r.URL.Path // Call this in an inline function to handle errors. statusCode, err := func() (int, error) { // Check the origin. if !s.checkOriginFunc(r) { return http.StatusForbidden, fmt.Errorf("origin not allowed") } // Set the required HTTP headers for cross origin requests if enabled. if s.enableCORS { // Parse the origin url. origin := r.Header["Origin"] if len(origin) == 0 || len(origin[0]) == 0 { return 400, fmt.Errorf("failed to set header: Access-Control-Allow-Origin: HTTP request origin header is empty") } w.Header().Set("Access-Control-Allow-Origin", origin[0]) // Set allowed origin. w.Header().Set("Access-Control-Allow-Methods", "POST,GET") // Only allow POST and GET requests. } // Strip the base URL. if len(path) < s.httpURLStripLength { return http.StatusBadRequest, fmt.Errorf("invalid request") } path = path[s.httpURLStripLength:] // Route the HTTP request in a very simple way by comparing the strings. if path == httpURLWebSocketSuffix { // Handle the websocket request. s.webSocketServer.HandleRequest(w, r) } else if path == httpURLAjaxSocketSuffix { // Handle the ajax request. s.ajaxSocketServer.HandleRequest(w, r) } else { return http.StatusBadRequest, fmt.Errorf("invalid request") } return http.StatusAccepted, nil }() // Handle the error. if err != nil { // Set the HTTP status code. w.WriteHeader(statusCode) // Get the remote address and user agent. remoteAddr, _ := utils.RemoteAddress(r) userAgent := r.Header.Get("User-Agent") // Log the invalid request. log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, "url": r.URL.Path, }).Warningf("handle HTTP request: %v", err) } }
func handleWebSocket(rw http.ResponseWriter, req *http.Request) { // Get the remote address and user agent. remoteAddr, requestRemoteAddrMethodUsed := utils.RemoteAddress(req) userAgent := req.Header.Get("User-Agent") // This has to be a GET request. if req.Method != "GET" { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, "method": req.Method, }).Warning("client accessed websocket handler with an invalid request method") http.Error(rw, "Method not allowed", 405) return } // Upgrade to a websocket. ws, err := upgrader.Upgrade(rw, req, nil) if err != nil { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, }).Warningf("failed to upgrade to websocket layer: %v", err) http.Error(rw, "Bad Request", 400) return } // Create a new websocket value. w := newWebSocket(ws) // Set the user agent. w.userAgent = userAgent // Set the remote address get function. if requestRemoteAddrMethodUsed { // Obtain the remote address from the websocket directly. w.remoteAddrFunc = func() string { return utils.RemovePortFromRemoteAddr(w.ws.RemoteAddr().String()) } } else { // Obtain the remote address from the current string. // It was obtained using the request Headers. So don't use the // websocket RemoteAddr() method, because it does not return // the clients IP address. w.remoteAddrFunc = func() string { return remoteAddr } } // Start the handlers in new goroutines. go w.writeLoop() go w.readLoop() // Trigger the event that a new socket connection was made. triggerOnNewSocketConnection(w) }
// ServeHTTP implements the HTTP Handler interface of the http package. func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Get the URL path. path := r.URL.Path // Call this in an inline function to handle errors. err := func() error { // Strip the base URL. if len(path) < s.httpURLStripLength { return fmt.Errorf("invalid request") } path = path[s.httpURLStripLength:] // Route the HTTP request in a very simple way by comparing the strings. if path == httpURLWebSocketSuffix { // Handle the websocket request. s.webSocketServer.HandleRequest(w, r) } else if path == httpURLAjaxSocketSuffix { // Handle the ajax request. s.ajaxSocketServer.HandleRequest(w, r) } else { return fmt.Errorf("invalid request") } return nil }() // Handle the error. if err != nil { // Get the remote address and user agent. remoteAddr, _ := utils.RemoteAddress(r) userAgent := r.Header.Get("User-Agent") // Log the invalid request. log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, "url": r.URL.Path, }).Warningf("handle HTTP request: %v", err) http.Error(w, "Bad Request", 400) } }
func (s *Server) HandleRequest(w http.ResponseWriter, req *http.Request) { // Get the remote address and user agent. remoteAddr, _ := utils.RemoteAddress(req) userAgent := req.Header.Get("User-Agent") // Get the request body data. body, err := ioutil.ReadAll(req.Body) if err != nil { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, }).Warningf("failed to read ajax request body: %v", err) http.Error(w, "Internal Server Error", 500) return } // Check for bad requests. if req.Method != "POST" { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, }).Warningf("client accessed the ajax interface with an invalid http method: %s", req.Method) http.Error(w, "Bad Request", 400) return } // Get the request body as string. data := string(body) // Get the head of the body data delimited by an delimiter. var head string i := strings.Index(data, ajaxSocketDataDelimiter) if i < 0 { // There is no delimiter. The complete data is the head. head = data data = "" } else { // Extract the head. head = data[:i] data = data[i+1:] } // Validate the head length. if len(head) < ajaxSocketDataKeyLength { log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, }).Warningf("ajax: head data is too short: '%s'", head) http.Error(w, "Bad Request", 400) return } // The head is split into key and value. key := head[:ajaxSocketDataKeyLength] value := head[ajaxSocketDataKeyLength:] // Handle the specific request. switch key { case ajaxSocketDataKeyInit: s.initAjaxRequest(remoteAddr, userAgent, w) case ajaxSocketDataKeyPoll: s.pollAjaxRequest(value, remoteAddr, userAgent, data, w) case ajaxSocketDataKeyPush: s.pushAjaxRequest(value, remoteAddr, userAgent, data, w) default: log.L.WithFields(logrus.Fields{ "remoteAddress": remoteAddr, "userAgent": userAgent, "key": key, "value": value, }).Warningf("ajax: invalid request.") http.Error(w, "Bad Request", 400) return } }