package main import ( "net/http" "net/url" // "fmt" "os" "io/ioutil" "encoding/json" "strconv" "github.com/azukaar/cosmos-server/src/utils" "go.deanishe.net/favicon" ) type CachedImage struct { ContentType string ETag string Body []byte } var cache = make(map[string]CachedImage) func sendImage(w http.ResponseWriter, image CachedImage) { // Copy the response to the output w.Header().Set("Content-Type", image.ContentType) w.Header().Set("ETag", image.ETag) w.Header().Set("Cache-Control", "max-age=86400") w.WriteHeader(http.StatusOK) w.Write(image.Body) } func sendFallback(w http.ResponseWriter) { // Send the fallback image pwd,_ := os.Getwd() imgsrc := "cosmos_gray.png" fallback, err := ioutil.ReadFile(pwd + "/" + imgsrc) if err != nil { utils.Error("Favicon: fallback", err) utils.HTTPError(w, "Favicon", http.StatusInternalServerError, "FA003") return } w.Header().Set("Content-Type", "image/png") w.Header().Set("Cache-Control", "max-age=5") w.WriteHeader(http.StatusOK) w.Write(fallback) } func GetFavicon(w http.ResponseWriter, req *http.Request) { if utils.LoggedInOnly(w, req) != nil { return } // get url from query string escsiteurl := req.URL.Query().Get("q") // URL decode siteurl, err := url.QueryUnescape(escsiteurl) if err != nil { utils.Error("Favicon: URL decode", err) utils.HTTPError(w, "URL decode", http.StatusInternalServerError, "FA002") return } if(req.Method == "GET") { utils.Log("Fetch favicon for " + siteurl) // Check if we have the favicon in cache if _, ok := cache[siteurl]; ok { utils.Debug("Favicon in cache") resp := cache[siteurl] sendImage(w, resp) return } icons, err := favicon.Find(siteurl) utils.Debug("Found Favicon: " + strconv.Itoa(len(icons))) if err != nil { utils.Error("FaviconFetch", err) sendFallback(w) return } if len(icons) == 0 { utils.Error("FaviconFetch", err) sendFallback(w) return } iconIndex := len(icons)-1 iconChanged := false for i, icon := range icons { utils.Debug("Favicon Width: " + icon.URL + " " + strconv.Itoa(icon.Width)) if icon.Width <= 256 { iconIndex = i iconChanged = true break } } if !iconChanged { iconIndex = 0 } icon := icons[iconIndex] utils.Log("Favicon: " + icon.URL) // Fetch the favicon resp, err := http.Get(icon.URL) if err != nil { utils.Error("FaviconFetch", err) sendFallback(w) return } // save the body to a file // out, err := os.Create("favicon.ico") // if err != nil { // utils.Error("FaviconFetch", err) // utils.HTTPError(w, "Favicon Fetch", http.StatusInternalServerError, "FA001") // return // } // defer out.Close() // _, err = io.Copy(out, resp.Body) // if err != nil { // utils.Error("FaviconFetch", err) // utils.HTTPError(w, "Favicon Fetch", http.StatusInternalServerError, "FA001") // return // } // Cache the response body, err := ioutil.ReadAll(resp.Body) if err != nil { utils.Error("FaviconFetch", err) sendFallback(w) return } finalImage := CachedImage{ ContentType: resp.Header.Get("Content-Type"), ETag: resp.Header.Get("ETag"), Body: body, } cache[siteurl] = finalImage sendImage(w, cache[siteurl]) } else { utils.Error("Favicon: Method not allowed" + req.Method, nil) utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") return } } func PingURL(w http.ResponseWriter, req *http.Request) { if utils.LoggedInOnly(w, req) != nil { return } // get url from query string escsiteurl := req.URL.Query().Get("q") // URL decode siteurl, err := url.QueryUnescape(escsiteurl) if err != nil { utils.Error("Ping: URL decode", err) utils.HTTPError(w, "Ping URL decode", http.StatusInternalServerError, "FA002") return } if(req.Method == "GET") { utils.Log("Ping for " + siteurl) resp, err := http.Get(siteurl) if err != nil { utils.Error("Ping", err) utils.HTTPError(w, "URL decode", http.StatusInternalServerError, "PI0001") return } if resp.StatusCode >= 500 { utils.Error("Ping", err) utils.HTTPError(w, "URL decode", http.StatusInternalServerError, "PI0002") return } json.NewEncoder(w).Encode(map[string]interface{}{ "status": "OK", "data": map[string]interface{}{ }, }) } else { utils.Error("Favicon: Method not allowed" + req.Method, nil) utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") return } }