in go/cmd/ct-fetch/ct-fetch.go [783:853]
func (lw *LogWorker) downloadCTRangeToChannel(ctx context.Context, verifier *CtLogSubtreeVerifier, entryChan chan<- CtLogEntry) (uint64, uint64, error) {
var minTimestamp uint64
var maxTimestamp uint64
b := &backoff.Backoff{
Jitter: true,
Min: 5 * time.Second,
Max: 10 * time.Minute,
}
index := verifier.Subtree.First
last := verifier.Subtree.Last
for index <= last {
// TODO(jms) Add an option to get entries from disk.
resp, err := lw.Client.GetRawEntries(ctx, int64(index), int64(last))
if err != nil {
if strings.Contains(err.Error(), "HTTP Status") &&
(strings.Contains(err.Error(), "429") || strings.Contains(err.Error(), "Too Many Requests")) {
d := b.Duration()
glog.Infof("[%s] received status code 429 at index=%d, retrying in %s: %v", lw.Name(), index, d, err)
time.Sleep(d)
continue
}
glog.Warningf("Failed to get entries: %v", err)
return minTimestamp, maxTimestamp, err
}
b.Reset()
for _, entry := range resp.Entries {
logEntry, err := ct.LogEntryFromLeaf(int64(index), &entry)
if _, ok := err.(x509.NonFatalErrors); !ok && err != nil {
glog.Warningf("Erroneous certificate: log=%s index=%d err=%v",
lw.Name(), index, err)
// This is a serious error that prevents us from ingesting a log, so
// we ping the `ct-fetch.parse.error` metric to generate an alert and
// also the `ct-fetch.<log key>.parse.error` metric to identify the log.
metrics.IncrCounter([]string{"parse", "error"}, 1)
metrics.IncrCounter([]string{lw.MetricKey, "parse", "error"}, 1)
index++
continue
}
// We might block while waiting for space in entryChan.
// If we catch a signal here the verification will fail and the subtree
// will not get merged.
select {
case <-ctx.Done():
glog.Infof("[%s] Cancelled", lw.Name())
return minTimestamp, maxTimestamp, nil
case entryChan <- CtLogEntry{logEntry, lw.LogMeta}:
}
// Update the metadata that we will pass to mergeSubtree.
entryTimestamp := logEntry.Leaf.TimestampedEntry.Timestamp
if minTimestamp == 0 || entryTimestamp < minTimestamp {
minTimestamp = entryTimestamp
}
if maxTimestamp == 0 || maxTimestamp < entryTimestamp {
maxTimestamp = entryTimestamp
}
verifier.Consume(entry.LeafInput)
index++
}
}
return minTimestamp, maxTimestamp, nil
}