Просмотр исходного кода

Send cache headers with the proxied images

Lucas Stadler лет назад: 9
Родитель
Сommit
81488c239e
1 измененных файлов с 22 добавлено и 6 удалено
  1. 22 6
      go/favicon/favicon.go

+ 22 - 6
go/favicon/favicon.go

1
package main
1
package main
2
2
3
import (
3
import (
4
	"crypto/md5"
4
	"errors"
5
	"errors"
5
	"flag"
6
	"flag"
6
	"fmt"
7
	"fmt"
23
var lock sync.RWMutex
24
var lock sync.RWMutex
24
25
25
var imageCache *lru.Cache
26
var imageCache *lru.Cache
27
var imageHashes *lru.Cache
26
var imageLock sync.RWMutex
28
var imageLock sync.RWMutex
27
29
28
func main() {
30
func main() {
30
32
31
	faviconCache = lru.New(*cacheSize)
33
	faviconCache = lru.New(*cacheSize)
32
	imageCache = lru.New(*cacheSize)
34
	imageCache = lru.New(*cacheSize)
35
	imageHashes = lru.New(*cacheSize)
33
36
34
	http.HandleFunc("/favicon", HandleGetFavicon)
37
	http.HandleFunc("/favicon", HandleGetFavicon)
35
	http.HandleFunc("/favicon_proxy", HandleProxy)
38
	http.HandleFunc("/favicon_proxy", HandleProxy)
47
}
50
}
48
51
49
func HandleProxy(w http.ResponseWriter, r *http.Request) {
52
func HandleProxy(w http.ResponseWriter, r *http.Request) {
53
	w.Header().Set("Cache-Control", "max-age=2419200")
54
50
	url := r.URL.Query()["url"][0]
55
	url := r.URL.Query()["url"][0]
51
	favicon, err := GetFaviconCached(url)
56
	favicon, err := GetFaviconCached(url)
52
	if err != nil {
57
	if err != nil {
56
		return
61
		return
57
	}
62
	}
58
63
59
	image, err := GetImageCached(favicon)
64
	image, hash, err := GetImageCached(favicon)
60
	if err != nil {
65
	if err != nil {
61
		fmt.Printf("Error: '%s': %s\n", url, err)
66
		fmt.Printf("Error: '%s': %s\n", url, err)
62
		w.WriteHeader(http.StatusNotFound)
67
		w.WriteHeader(http.StatusNotFound)
63
		w.Write([]byte(fmt.Sprint(err)))
68
		w.Write([]byte(fmt.Sprint(err)))
64
		return
69
		return
65
	}
70
	}
71
	w.Header().Set("ETag", hash)
72
73
	ifNoneMatch := r.Header.Get("If-None-Match")
74
	if ifNoneMatch != "" && hash == ifNoneMatch {
75
		w.WriteHeader(http.StatusNotModified)
76
		return
77
	}
66
78
79
	w.Header().Set("Content-Length", fmt.Sprintf("%d", len(image)))
67
	w.Write(image)
80
	w.Write(image)
68
}
81
}
69
82
70
func GetImageCached(u string) ([]byte, error) {
83
func GetImageCached(u string) ([]byte, string, error) {
71
	imageLock.RLock()
84
	imageLock.RLock()
72
	image, cached := imageCache.Get(u)
85
	image, cached := imageCache.Get(u)
86
	hash, _ := imageHashes.Get(u)
73
	imageLock.RUnlock()
87
	imageLock.RUnlock()
74
88
75
	if cached {
89
	if cached {
76
		return image.([]byte), nil
90
		return image.([]byte), hash.(string), nil
77
	}
91
	}
78
92
79
	resp, err := http.Get(u)
93
	resp, err := http.Get(u)
80
	if err != nil {
94
	if err != nil {
81
		return nil, err
95
		return nil, "", err
82
	}
96
	}
83
	defer resp.Body.Close()
97
	defer resp.Body.Close()
84
98
85
	imageData, err := ioutil.ReadAll(resp.Body)
99
	imageData, err := ioutil.ReadAll(resp.Body)
86
	if err != nil {
100
	if err != nil {
87
		return nil, err
101
		return nil, "", err
88
	}
102
	}
103
	imageHash := fmt.Sprintf("%x", md5.Sum(imageData))
89
104
90
	imageLock.Lock()
105
	imageLock.Lock()
91
	imageCache.Add(u, imageData)
106
	imageCache.Add(u, imageData)
107
	imageHashes.Add(u, imageHash)
92
	imageLock.Unlock()
108
	imageLock.Unlock()
93
	return imageData, nil
109
	return imageData, imageHash, nil
94
110
95
}
111
}
96
112