Example #1
0
// 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)
	}
}
Example #2
0
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)
}
Example #3
0
// 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)
	}
}
Example #4
0
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
	}
}