[release] version 0.5.0-unstable20
This commit is contained in:
parent
0f46cff353
commit
550917bf6e
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.5.0-unstable20",
|
"version": "0.5.0-unstable21",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
217
src/icons.go
217
src/icons.go
|
@ -7,9 +7,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"os"
|
"os"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
|
||||||
"path"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"go.deanishe.net/favicon"
|
||||||
|
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
)
|
)
|
||||||
|
@ -22,70 +24,6 @@ type CachedImage struct {
|
||||||
|
|
||||||
var cache = make(map[string]CachedImage)
|
var cache = make(map[string]CachedImage)
|
||||||
|
|
||||||
func ExtractFaviconMetaTag(filename string) string {
|
|
||||||
// Read the contents of the file
|
|
||||||
htmlBytes, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return "/favicon.ico"
|
|
||||||
}
|
|
||||||
html := string(htmlBytes)
|
|
||||||
|
|
||||||
// Regular expression pattern to match the favicon metatag
|
|
||||||
pattern := `<link[^>]*rel="icon"[^>]*(?:sizes="([^"]+)")?[^>]*href="([^"]+)"[^>]*>|<meta[^>]*name="msapplication-TileImage"[^>]*content="([^"]+)"[^>]*>`
|
|
||||||
|
|
||||||
// Compile the regular expression pattern
|
|
||||||
regex := regexp.MustCompile(pattern)
|
|
||||||
|
|
||||||
// Find all matches in the HTML string
|
|
||||||
matches := regex.FindAllStringSubmatch(html, -1)
|
|
||||||
|
|
||||||
var faviconURL string
|
|
||||||
|
|
||||||
// Iterate over the matches to find the appropriate favicon
|
|
||||||
for _, match := range matches {
|
|
||||||
sizes := match[1]
|
|
||||||
href := match[2]
|
|
||||||
msAppTileImage := match[3]
|
|
||||||
|
|
||||||
// Check if the meta tag specifies msapplication-TileImage
|
|
||||||
if msAppTileImage != "" {
|
|
||||||
faviconURL = msAppTileImage
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the sizes attribute contains 96x96
|
|
||||||
if strings.Contains(sizes, "96x96") {
|
|
||||||
faviconURL = href
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the sizes attribute contains 64x64
|
|
||||||
if strings.Contains(sizes, "64x64") {
|
|
||||||
faviconURL = href
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the sizes attribute contains 32x32
|
|
||||||
if strings.Contains(sizes, "32x32") {
|
|
||||||
faviconURL = href
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no sizes specified, set faviconURL to the first match without sizes
|
|
||||||
if faviconURL == "" && sizes == "" {
|
|
||||||
faviconURL = href
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a favicon URL is found, return it
|
|
||||||
if faviconURL != "" {
|
|
||||||
return faviconURL
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return an error if no favicon URL is found
|
|
||||||
return "/favicon.ico"
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendImage(w http.ResponseWriter, image CachedImage) {
|
func sendImage(w http.ResponseWriter, image CachedImage) {
|
||||||
// Copy the response to the output
|
// Copy the response to the output
|
||||||
w.Header().Set("Content-Type", image.ContentType)
|
w.Header().Set("Content-Type", image.ContentType)
|
||||||
|
@ -111,6 +49,7 @@ func sendFallback(w http.ResponseWriter) {
|
||||||
w.Write(fallback)
|
w.Write(fallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var IconCacheLock = make(chan bool, 1)
|
||||||
|
|
||||||
func GetFavicon(w http.ResponseWriter, req *http.Request) {
|
func GetFavicon(w http.ResponseWriter, req *http.Request) {
|
||||||
if utils.LoggedInOnly(w, req) != nil {
|
if utils.LoggedInOnly(w, req) != nil {
|
||||||
|
@ -120,6 +59,9 @@ func GetFavicon(w http.ResponseWriter, req *http.Request) {
|
||||||
// get url from query string
|
// get url from query string
|
||||||
escsiteurl := req.URL.Query().Get("q")
|
escsiteurl := req.URL.Query().Get("q")
|
||||||
|
|
||||||
|
IconCacheLock <- true
|
||||||
|
defer func() { <-IconCacheLock }()
|
||||||
|
|
||||||
// URL decode
|
// URL decode
|
||||||
siteurl, err := url.QueryUnescape(escsiteurl)
|
siteurl, err := url.QueryUnescape(escsiteurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -147,70 +89,105 @@ func GetFavicon(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
urlBody, err := ioutil.ReadAll(respNew.Body)
|
newsiteurl := respNew.Request.URL.String()
|
||||||
|
|
||||||
|
icons, err := favicon.Find(newsiteurl)
|
||||||
|
|
||||||
|
utils.Debug("Found Favicon: " + strconv.Itoa(len(icons)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error("FaviconFetch", err)
|
utils.Error("FaviconFetch", err)
|
||||||
sendFallback(w)
|
sendFallback(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(icons) == 0 {
|
||||||
|
utils.Error("FaviconFetch", err)
|
||||||
|
sendFallback(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if !strings.Contains(icons[iconIndex].URL, "favicon.ico") {
|
||||||
|
// icons = append(icons, favicon.Icon{URL: "favicon.ico", Width: 0})
|
||||||
|
// }
|
||||||
|
|
||||||
// get favicon meta tag from the response
|
// if !strings.Contains(icons[iconIndex].URL, "/favicon.ico") {
|
||||||
faviconURL := ExtractFaviconMetaTag((string)(urlBody))
|
// icons = append(icons, favicon.Icon{URL: "/favicon.ico", Width: 0})
|
||||||
|
// }
|
||||||
|
|
||||||
// if faviconURL is relative get hostname of the URL and append icon
|
for _, icon := range icons {
|
||||||
if !strings.HasPrefix(faviconURL, "http") {
|
utils.Debug("Favicon Width: " + icon.URL + " " + strconv.Itoa(icon.Width))
|
||||||
u, err := url.Parse(siteurl)
|
if icon.Width <= 256 {
|
||||||
if err != nil {
|
|
||||||
utils.Error("FaviconFetch", err)
|
iconURL := icon.URL
|
||||||
|
u, err := url.Parse(siteurl)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("FaviconFetch failed to parse ", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(iconURL, "http") {
|
||||||
|
if strings.HasPrefix(iconURL, ".") {
|
||||||
|
// Relative URL starting with "."
|
||||||
|
// Resolve the relative URL based on the base URL
|
||||||
|
baseURL := u.Scheme + "://" + u.Host
|
||||||
|
iconURL = baseURL + iconURL[1:]
|
||||||
|
} else if strings.HasPrefix(iconURL, "/") {
|
||||||
|
// Relative URL starting with "/"
|
||||||
|
// Append the relative URL to the base URL
|
||||||
|
iconURL = u.Scheme + "://" + u.Host + iconURL
|
||||||
|
} else {
|
||||||
|
// Relative URL without starting dot or slash
|
||||||
|
// Construct the absolute URL based on the current page's URL path
|
||||||
|
baseURL := u.Scheme + "://" + u.Host
|
||||||
|
baseURLPath := path.Dir(u.Path)
|
||||||
|
iconURL = baseURL + baseURLPath + "/" + iconURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.Log("Favicon Trying to fetch " + iconURL)
|
||||||
|
// Fetch the favicon
|
||||||
|
resp, err := http.Get(iconURL)
|
||||||
|
if err != nil {
|
||||||
|
utils.Error("FaviconFetch", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if 200 and if image
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
utils.Error("FaviconFetch - " + iconURL + " - not 200 ", nil)
|
||||||
|
continue
|
||||||
|
} else if !strings.Contains(resp.Header.Get("Content-Type"), "image") {
|
||||||
|
utils.Error("FaviconFetch - " + iconURL + " - not image ", nil)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
utils.Log("Favicon found " + iconURL)
|
||||||
|
|
||||||
|
// 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])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.Log("Favicon final fallback ")
|
||||||
sendFallback(w)
|
sendFallback(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if strings.HasPrefix(faviconURL, ".") {
|
|
||||||
// Relative URL starting with "."
|
|
||||||
// Resolve the relative URL based on the base URL
|
|
||||||
baseURL := u.Scheme + "://" + u.Host
|
|
||||||
faviconURL = baseURL + faviconURL[1:]
|
|
||||||
} else if strings.HasPrefix(faviconURL, "/") {
|
|
||||||
// Relative URL starting with "/"
|
|
||||||
// Append the relative URL to the base URL
|
|
||||||
faviconURL = u.Scheme + "://" + u.Host + faviconURL
|
|
||||||
} else {
|
|
||||||
// Relative URL without starting dot or slash
|
|
||||||
// Construct the absolute URL based on the current page's URL path
|
|
||||||
baseURL := u.Scheme + "://" + u.Host
|
|
||||||
baseURLPath := path.Dir(u.Path)
|
|
||||||
faviconURL = baseURL + baseURLPath + "/" + faviconURL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
utils.Log("Favicon: " + faviconURL)
|
|
||||||
|
|
||||||
// Fetch the favicon
|
|
||||||
resp, err := http.Get(faviconURL)
|
|
||||||
if err != nil {
|
|
||||||
utils.Error("FaviconFetch", err)
|
|
||||||
sendFallback(w)
|
|
||||||
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 {
|
} else {
|
||||||
utils.Error("Favicon: Method not allowed" + req.Method, nil)
|
utils.Error("Favicon: Method not allowed" + req.Method, nil)
|
||||||
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
|
||||||
|
|
Loading…
Reference in a new issue