...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package submission
16
17 import (
18 "bytes"
19 "fmt"
20 "net/http"
21 "sync"
22 "time"
23
24 "github.com/google/certificate-transparency-go/loglist3"
25 "github.com/google/certificate-transparency-go/x509util"
26 )
27
28 const (
29
30 httpClientTimeout = 10 * time.Second
31 )
32
33
34
35 type LogListData struct {
36 JSON []byte
37 List *loglist3.LogList
38 DownloadTime time.Time
39 }
40
41
42 type LogListRefresher interface {
43 Refresh() (*LogListData, error)
44 LastJSON() []byte
45 Source() string
46 }
47
48
49
50 type logListRefresherImpl struct {
51
52 updateMu sync.RWMutex
53 lastJSON []byte
54 path string
55 client *http.Client
56 }
57
58
59 func NewCustomLogListRefresher(client *http.Client, llPath string) LogListRefresher {
60 return &logListRefresherImpl{
61 path: llPath,
62 client: client,
63 }
64 }
65
66
67
68 func NewLogListRefresher(llPath string) LogListRefresher {
69 return NewCustomLogListRefresher(&http.Client{Timeout: httpClientTimeout}, llPath)
70 }
71
72
73
74 func (llr *logListRefresherImpl) Refresh() (*LogListData, error) {
75 llr.updateMu.Lock()
76 defer llr.updateMu.Unlock()
77
78 t := time.Now()
79 json, err := x509util.ReadFileOrURL(llr.path, llr.client)
80 if err != nil {
81 return nil, fmt.Errorf("failed to read %q: %v", llr.path, err)
82 }
83
84 if bytes.Equal(json, llr.lastJSON) {
85 return nil, nil
86 }
87
88 ll, err := loglist3.NewFromJSON(json)
89 if err != nil {
90 return nil, fmt.Errorf("failed to parse %q: %v", llr.path, err)
91 }
92 llr.lastJSON = json
93 return &LogListData{JSON: json, List: ll, DownloadTime: t}, nil
94 }
95
96
97 func (llr *logListRefresherImpl) LastJSON() []byte {
98 llr.updateMu.Lock()
99 defer llr.updateMu.Unlock()
100 if llr.lastJSON == nil {
101 return []byte{}
102 }
103 return llr.lastJSON
104 }
105
106
107 func (llr *logListRefresherImpl) Source() string {
108 return llr.path
109 }
110
View as plain text