package webserver import ( "fmt" "log" "regexp" "strconv" "strings" "time" "compress/gzip" "net/http" "istheinternetonfire.app/assets" "istheinternetonfire.app/internal/config" ) const ( TYPE_APPLICATION_PEM string = "application/x-pem-file" TYPE_APPLICATION_JSON string = "application/json" TYPE_AUDIO_MPEG string = "audio/mpeg" TYPE_FONT_WOFF string = "font/woff" TYPE_FONT_WOFF2 string = "font/woff2" TYPE_IMAGE_JPG string = "image/jpg" TYPE_IMAGE_PNG string = "image/png" TYPE_TEXT_CSS string = "text/css" TYPE_TEXT_HTML string = "text/html" TYPE_TEXT_JS string = "text/javascript" TYPE_TEXT_PLAIN string = "text/plain" TYPE_TEXT_RAW string = "text/raw" ) var validFiles map[string]string = map[string]string{ "/robots.txt": TYPE_TEXT_PLAIN, "/apple-touch-icon.png": TYPE_IMAGE_PNG, "/favicon.ico": TYPE_IMAGE_PNG, "/favicon-16x16.png": TYPE_IMAGE_PNG, "/favicon-32x32.png": TYPE_IMAGE_PNG, "/js/bootstrap.bundle.min.js": TYPE_TEXT_JS, "/js/bootstrap.bundle.min.js.map": TYPE_APPLICATION_JSON, "/js/jquery.min.js": TYPE_TEXT_JS, } func isValidReq(file string) (string, error) { for f, t := range validFiles { if file == f { return t, nil } } return "", fmt.Errorf("Invalid file requested: %s", file) } func httpAccessLog(req *http.Request) { config.Cfg.Log.Debug("http request", "method", req.Method, "remote-address", req.RemoteAddr, "request-uri", req.RequestURI) } func crossSiteOrigin(w http.ResponseWriter) { w.Header().Add("Access-Control-Allow-Origin", "*") w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS") } func Start() { path := http.NewServeMux() connection := &http.Server{ Addr: config.Cfg.WebServerIP + ":" + strconv.FormatInt(int64(config.Cfg.WebServerPort), 10), Handler: path, ReadTimeout: time.Duration(config.Cfg.WebServerReadTimeout) * time.Second, WriteTimeout: time.Duration(config.Cfg.WebServerWriteTimeout) * time.Second, IdleTimeout: time.Duration(config.Cfg.WebServerIdleTimeout) * time.Second, } path.HandleFunc("/", webRoot) if err := connection.ListenAndServe(); err != nil { config.Cfg.Log.Error("unable to start webserver", "error", err) } } func webRoot(w http.ResponseWriter, r *http.Request) { httpAccessLog(r) crossSiteOrigin(w) if strings.ToLower(r.Method) != "get" { config.Cfg.Log.Debug("http invalid method", "url", r.URL.Path, "expected", "GET", "received", r.Method) tmpltError(w, http.StatusBadRequest, "Invalid http method.") return } if r.URL.Path == "/" { tmpltWebRoot(w, r) } else { cType, err := isValidReq(r.URL.Path) if err != nil { config.Cfg.Log.Debug("request not found", "url", r.URL.Path) tmpltStatusNotFound(w, r.URL.Path) return } w.Header().Add("Content-Type", cType) o, err := assets.EmbedHTML.ReadFile("html" + r.URL.Path) if err != nil { log.Printf("[ERROR] Unable to read local embedded file data: %v\n", err) tmpltError(w, http.StatusInternalServerError, "Server unable to retrieve file data.") return } if regexp.MustCompile(`gzip`).Match([]byte(r.Header.Get("Accept-Encoding"))) { w.Header().Add("Content-Encoding", "gzip") gw := gzip.NewWriter(w) defer gw.Close() gw.Write(o) } else { w.Write(o) } } }