1 // Download files via HTTP with support for If-Modified-Since
3 // Copyright (C) 2019 Simon Ruderich
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Affero General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Affero General Public License for more details.
15 // You should have received a copy of the GNU Affero General Public License
16 // along with this program. If not, see <https://www.gnu.org/licenses/>.
28 "github.com/pkg/errors"
31 // Global variable to permit reuse of connections (keep-alive)
32 var clients map[string]*http.Client
35 clients = make(map[string]*http.Client)
36 clients[""] = &http.Client{}
39 func fetchIfModified(url, ca string, lastModified *time.Time) (int, []byte, error) {
40 req, err := http.NewRequest("GET", url, nil)
44 if !lastModified.IsZero() {
45 req.Header.Add("If-Modified-Since",
46 lastModified.Format(http.TimeFormat))
49 client, ok := clients[ca]
51 pem, err := ioutil.ReadFile(ca)
53 return 0, nil, errors.Wrapf(err, "file.ca %q", ca)
55 pool := x509.NewCertPool()
56 ok := pool.AppendCertsFromPEM(pem)
58 return 0, nil, fmt.Errorf(
59 "file.ca %q: no PEM cert found", ca)
62 client = &http.Client{
63 Transport: &http.Transport{
64 TLSClientConfig: &tls.Config{
72 resp, err := client.Do(req)
76 defer resp.Body.Close()
78 body, err := ioutil.ReadAll(resp.Body)
83 modified, err := http.ParseTime(resp.Header.Get("Last-Modified"))
85 *lastModified = modified
88 return resp.StatusCode, body, nil