func download()

in go/downloader/downloader.go [90:174]


func download(ctx context.Context, crlUrl url.URL, path string, timeout time.Duration) error {
	client := &http.Client{Timeout: timeout}

	action, offset, size := determineAction(client, crlUrl, path)

	if action == UpToDate {
		return nil
	}

	req, err := http.NewRequestWithContext(ctx, "GET", crlUrl.String(), nil)
	if err != nil {
		return err
	}

	req.Header.Add("X-Automated-Tool", "https://github.com/mozilla/crlite")
	if action == Resume {
		req.Header.Add("Content-Range", fmt.Sprintf("bytes: %d-%d/%d", offset, size, offset-size))
	}

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var outFileParams int
	switch resp.StatusCode {
	case http.StatusPartialContent:
		// Depending on what the server responds with, we may have to go back to Create
		outFileParams = os.O_APPEND | os.O_WRONLY
		action = Resume
		glog.V(1).Infof("[%s] Successfully resumed download at offset %d", crlUrl.String(), offset)
	case http.StatusOK:
		outFileParams = os.O_TRUNC | os.O_CREATE | os.O_WRONLY
		action = Create
	default:
		return fmt.Errorf("Non-OK status: %s", resp.Status)
	}

	outFile, err := os.OpenFile(path, outFileParams, 0644)
	if err != nil {
		return err
	}
	defer outFile.Close()

	if ctx.Err() != nil {
		return ctx.Err()
	}

	defer resp.Body.Close()

	// and copy from reader, propagating errors
	totalBytes, err := io.Copy(outFile, resp.Body)
	if err != nil {
		return err
	}

	if action == Create && size != 0 && totalBytes != size {
		glog.Warningf("[%s] Didn't seem to download the right number of bytes, expected=%d got %d",
			crlUrl.String(), size, totalBytes)
	}

	if action == Resume && size != 0 && totalBytes+offset != size {
		glog.Warningf("[%s] Didn't seem to download the right number of bytes, expected=%d got %d with %d already local",
			crlUrl.String(), size, totalBytes, offset)
	}

	lastModStr := resp.Header.Get("Last-Modified")
	// http.TimeFormat is 29 characters
	if len(lastModStr) < 16 {
		glog.Infof("[%s] No compliant reported last-modified time, file may expire early: [%s]", crlUrl.String(), lastModStr)
		return nil
	}

	lastMod, err := http.ParseTime(resp.Header.Get("Last-Modified"))
	if err != nil {
		glog.Warningf("[%s] Couldn't parse modified time: %s [%s]", crlUrl.String(), err, lastModStr)
		return nil
	}

	if err := os.Chtimes(path, lastMod, lastMod); err != nil {
		glog.Warningf("Couldn't set modified time: %s", err)
	}
	return nil
}