1 // Download files via HTTP with support for If-Modified-Since
3 // Copyright (C) 2019-2020 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, user, pass, ca string, lastModified *time.Time) (int, []byte, error) {
40 req, err := http.NewRequest("GET", url, nil)
44 if user != "" || pass != "" {
45 req.SetBasicAuth(user, pass)
47 if !lastModified.IsZero() {
48 req.Header.Add("If-Modified-Since",
49 lastModified.UTC().Format(http.TimeFormat))
52 client, ok := clients[ca]
54 pem, err := ioutil.ReadFile(ca)
56 return 0, nil, errors.Wrapf(err, "file.ca %q", ca)
58 pool := x509.NewCertPool()
59 ok := pool.AppendCertsFromPEM(pem)
61 return 0, nil, fmt.Errorf(
62 "file.ca %q: no PEM cert found", ca)
65 client = &http.Client{
66 Transport: &http.Transport{
67 TLSClientConfig: &tls.Config{
75 resp, err := client.Do(req)
79 defer resp.Body.Close()
81 body, err := ioutil.ReadAll(resp.Body)
86 modified, err := http.ParseTime(resp.Header.Get("Last-Modified"))
88 *lastModified = modified
91 return resp.StatusCode, body, nil