Skip to content

Commit dc158c3

Browse files
authored
Delete LogInfo object (#101)
* s/iOpts/hOpts * delete loginfo * remove references to loginfo * update comments
1 parent d7e4e68 commit dc158c3

File tree

2 files changed

+65
-81
lines changed

2 files changed

+65
-81
lines changed

handlers.go

Lines changed: 63 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ var entrypoints = []entrypointName{addChainName, addPreChainName, getRootsName}
8484
// pathHandlers maps from a path to the relevant AppHandler instance.
8585
type pathHandlers map[string]appHandler
8686

87-
// appHandler holds a logInfo and a handler function that uses it, and is
88-
// an implementation of the http.Handler interface.
87+
// appHandler connects an HTTP static-ct-api endpoint with log storage.
88+
// It is an implementation of the http.Handler interface.
8989
type appHandler struct {
90-
info *logInfo
91-
handler func(context.Context, *logInfo, http.ResponseWriter, *http.Request) (int, error)
90+
log *log
91+
opts *HandlerOptions
92+
handler func(context.Context, *HandlerOptions, *log, http.ResponseWriter, *http.Request) (int, error)
9293
name entrypointName
9394
method string // http.MethodGet or http.MethodPost
9495
}
@@ -97,64 +98,58 @@ type appHandler struct {
9798
// does additional common error and stats processing.
9899
func (a appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
99100
var statusCode int
100-
label0 := a.info.log.origin
101+
label0 := a.log.origin
101102
label1 := string(a.name)
102103
reqsCounter.Inc(label0, label1)
103-
startTime := a.info.iOpts.TimeSource.Now()
104-
logCtx := a.info.iOpts.RequestLog.start(r.Context())
105-
a.info.iOpts.RequestLog.origin(logCtx, a.info.log.origin)
104+
startTime := a.opts.TimeSource.Now()
105+
logCtx := a.opts.RequestLog.start(r.Context())
106+
a.opts.RequestLog.origin(logCtx, a.log.origin)
106107
defer func() {
107-
latency := a.info.iOpts.TimeSource.Now().Sub(startTime).Seconds()
108+
latency := a.opts.TimeSource.Now().Sub(startTime).Seconds()
108109
rspLatency.Observe(latency, label0, label1, strconv.Itoa(statusCode))
109110
}()
110-
klog.V(2).Infof("%s: request %v %q => %s", a.info.log.origin, r.Method, r.URL, a.name)
111+
klog.V(2).Infof("%s: request %v %q => %s", a.log.origin, r.Method, r.URL, a.name)
111112
// TODO(phboneff): add a.Method directly on the handler path and remove this test.
112113
if r.Method != a.method {
113-
klog.Warningf("%s: %s wrong HTTP method: %v", a.info.log.origin, a.name, r.Method)
114-
a.info.sendHTTPError(w, http.StatusMethodNotAllowed, fmt.Errorf("method not allowed: %s", r.Method))
115-
a.info.iOpts.RequestLog.status(logCtx, http.StatusMethodNotAllowed)
114+
klog.Warningf("%s: %s wrong HTTP method: %v", a.log.origin, a.name, r.Method)
115+
a.opts.sendHTTPError(w, http.StatusMethodNotAllowed, fmt.Errorf("method not allowed: %s", r.Method))
116+
a.opts.RequestLog.status(logCtx, http.StatusMethodNotAllowed)
116117
return
117118
}
118119

119120
// For GET requests all params come as form encoded so we might as well parse them now.
120121
// POSTs will decode the raw request body as JSON later.
121122
if r.Method == http.MethodGet {
122123
if err := r.ParseForm(); err != nil {
123-
a.info.sendHTTPError(w, http.StatusBadRequest, fmt.Errorf("failed to parse form data: %s", err))
124-
a.info.iOpts.RequestLog.status(logCtx, http.StatusBadRequest)
124+
a.opts.sendHTTPError(w, http.StatusBadRequest, fmt.Errorf("failed to parse form data: %s", err))
125+
a.opts.RequestLog.status(logCtx, http.StatusBadRequest)
125126
return
126127
}
127128
}
128129

129130
// impose a deadline on this onward request.
130-
ctx, cancel := context.WithDeadline(logCtx, deadlineTime(a.info))
131+
ctx, cancel := context.WithDeadline(logCtx, deadlineTime(a.opts))
131132
defer cancel()
132133

133134
var err error
134-
statusCode, err = a.handler(ctx, a.info, w, r)
135-
a.info.iOpts.RequestLog.status(ctx, statusCode)
136-
klog.V(2).Infof("%s: %s <= st=%d", a.info.log.origin, a.name, statusCode)
135+
statusCode, err = a.handler(ctx, a.opts, a.log, w, r)
136+
a.opts.RequestLog.status(ctx, statusCode)
137+
klog.V(2).Infof("%s: %s <= st=%d", a.log.origin, a.name, statusCode)
137138
rspsCounter.Inc(label0, label1, strconv.Itoa(statusCode))
138139
if err != nil {
139-
klog.Warningf("%s: %s handler error: %v", a.info.log.origin, a.name, err)
140-
a.info.sendHTTPError(w, statusCode, err)
140+
klog.Warningf("%s: %s handler error: %v", a.log.origin, a.name, err)
141+
a.opts.sendHTTPError(w, statusCode, err)
141142
return
142143
}
143144

144145
// Additional check, for consistency the handler must return an error for non-200 st
145146
if statusCode != http.StatusOK {
146-
klog.Warningf("%s: %s handler non 200 without error: %d %v", a.info.log.origin, a.name, statusCode, err)
147-
a.info.sendHTTPError(w, http.StatusInternalServerError, fmt.Errorf("http handler misbehaved, st: %d", statusCode))
147+
klog.Warningf("%s: %s handler non 200 without error: %d %v", a.log.origin, a.name, statusCode, err)
148+
a.opts.sendHTTPError(w, http.StatusInternalServerError, fmt.Errorf("http handler misbehaved, st: %d", statusCode))
148149
return
149150
}
150151
}
151152

152-
// logInfo holds information for a specific log instance.
153-
type logInfo struct {
154-
log *log
155-
iOpts *HandlerOptions
156-
}
157-
158153
// HandlerOptions describes log handlers options.
159154
type HandlerOptions struct {
160155
// Deadline is a timeout for HTTP requests.
@@ -171,36 +166,25 @@ type HandlerOptions struct {
171166
}
172167

173168
func NewPathHandlers(opts *HandlerOptions, log *log) pathHandlers {
174-
li := &logInfo{
175-
log: log,
176-
iOpts: opts,
177-
}
178-
179169
once.Do(func() { setupMetrics(opts.MetricFactory) })
180170
knownLogs.Set(1.0, log.origin)
181171

182-
return li.handlers(log.origin)
183-
}
184-
185-
// handlers returns a map from URL paths (with the given prefix) and AppHandler instances
186-
// to handle those entrypoints.
187-
func (li *logInfo) handlers(prefix string) pathHandlers {
188-
prefix = strings.TrimRight(prefix, "/")
172+
prefix := strings.TrimRight(log.origin, "/")
189173

190-
// Bind the logInfo instance to give an AppHandler instance for each endpoint.
174+
// Bind each endpoint to an appHandler instance.
191175
ph := pathHandlers{
192-
prefix + ct.AddChainPath: appHandler{info: li, handler: addChain, name: addChainName, method: http.MethodPost},
193-
prefix + ct.AddPreChainPath: appHandler{info: li, handler: addPreChain, name: addPreChainName, method: http.MethodPost},
194-
prefix + ct.GetRootsPath: appHandler{info: li, handler: getRoots, name: getRootsName, method: http.MethodGet},
176+
prefix + ct.AddChainPath: appHandler{opts: opts, log: log, handler: addChain, name: addChainName, method: http.MethodPost},
177+
prefix + ct.AddPreChainPath: appHandler{opts: opts, log: log, handler: addPreChain, name: addPreChainName, method: http.MethodPost},
178+
prefix + ct.GetRootsPath: appHandler{opts: opts, log: log, handler: getRoots, name: getRootsName, method: http.MethodGet},
195179
}
196180

197181
return ph
198182
}
199183

200184
// sendHTTPError generates a custom error page to give more information on why something didn't work
201-
func (li *logInfo) sendHTTPError(w http.ResponseWriter, statusCode int, err error) {
185+
func (opts *HandlerOptions) sendHTTPError(w http.ResponseWriter, statusCode int, err error) {
202186
errorBody := http.StatusText(statusCode)
203-
if !li.iOpts.MaskInternalErrors || statusCode != http.StatusInternalServerError {
187+
if !opts.MaskInternalErrors || statusCode != http.StatusInternalServerError {
204188
errorBody += fmt.Sprintf("\n%v", err)
205189
}
206190
http.Error(w, errorBody, statusCode)
@@ -231,7 +215,7 @@ func parseBodyAsJSONChain(r *http.Request) (ct.AddChainRequest, error) {
231215

232216
// addChainInternal is called by add-chain and add-pre-chain as the logic involved in
233217
// processing these requests is almost identical
234-
func addChainInternal(ctx context.Context, li *logInfo, w http.ResponseWriter, r *http.Request, isPrecert bool) (int, error) {
218+
func addChainInternal(ctx context.Context, opts *HandlerOptions, log *log, w http.ResponseWriter, r *http.Request, isPrecert bool) (int, error) {
235219
var method entrypointName
236220
if isPrecert {
237221
method = addPreChainName
@@ -242,45 +226,45 @@ func addChainInternal(ctx context.Context, li *logInfo, w http.ResponseWriter, r
242226
// Check the contents of the request and convert to slice of certificates.
243227
addChainReq, err := parseBodyAsJSONChain(r)
244228
if err != nil {
245-
return http.StatusBadRequest, fmt.Errorf("%s: failed to parse add-chain body: %s", li.log.origin, err)
229+
return http.StatusBadRequest, fmt.Errorf("%s: failed to parse add-chain body: %s", log.origin, err)
246230
}
247231
// Log the DERs now because they might not parse as valid X.509.
248232
for _, der := range addChainReq.Chain {
249-
li.iOpts.RequestLog.addDERToChain(ctx, der)
233+
opts.RequestLog.addDERToChain(ctx, der)
250234
}
251-
chain, err := verifyAddChain(li, addChainReq, isPrecert)
235+
chain, err := verifyAddChain(log, addChainReq, isPrecert)
252236
if err != nil {
253237
return http.StatusBadRequest, fmt.Errorf("failed to verify add-chain contents: %s", err)
254238
}
255239
for _, cert := range chain {
256-
li.iOpts.RequestLog.addCertToChain(ctx, cert)
240+
opts.RequestLog.addCertToChain(ctx, cert)
257241
}
258242
// Get the current time in the form used throughout RFC6962, namely milliseconds since Unix
259243
// epoch, and use this throughout.
260-
timeMillis := uint64(li.iOpts.TimeSource.Now().UnixNano() / nanosPerMilli)
244+
timeMillis := uint64(opts.TimeSource.Now().UnixNano() / nanosPerMilli)
261245

262246
entry, err := entryFromChain(chain, isPrecert, timeMillis)
263247
if err != nil {
264248
return http.StatusBadRequest, fmt.Errorf("failed to build MerkleTreeLeaf: %s", err)
265249
}
266250

267-
klog.V(2).Infof("%s: %s => storage.GetCertIndex", li.log.origin, method)
268-
sctDedupInfo, isDup, err := li.log.storage.GetCertDedupInfo(ctx, chain[0])
251+
klog.V(2).Infof("%s: %s => storage.GetCertIndex", log.origin, method)
252+
sctDedupInfo, isDup, err := log.storage.GetCertDedupInfo(ctx, chain[0])
269253
idx := sctDedupInfo.Idx
270254
if err != nil {
271255
return http.StatusInternalServerError, fmt.Errorf("couldn't deduplicate the request: %s", err)
272256
}
273257

274258
if isDup {
275-
klog.V(3).Infof("%s: %s - found duplicate entry at index %d", li.log.origin, method, idx)
259+
klog.V(3).Infof("%s: %s - found duplicate entry at index %d", log.origin, method, idx)
276260
entry.Timestamp = sctDedupInfo.Timestamp
277261
} else {
278-
if err := li.log.storage.AddIssuerChain(ctx, chain[1:]); err != nil {
262+
if err := log.storage.AddIssuerChain(ctx, chain[1:]); err != nil {
279263
return http.StatusInternalServerError, fmt.Errorf("failed to store issuer chain: %s", err)
280264
}
281265

282-
klog.V(2).Infof("%s: %s => storage.Add", li.log.origin, method)
283-
idx, err = li.log.storage.Add(ctx, entry)()
266+
klog.V(2).Infof("%s: %s => storage.Add", log.origin, method)
267+
idx, err = log.storage.Add(ctx, entry)()
284268
if err != nil {
285269
if errors.Is(err, tessera.ErrPushback) {
286270
w.Header().Add("Retry-After", "1")
@@ -291,8 +275,8 @@ func addChainInternal(ctx context.Context, li *logInfo, w http.ResponseWriter, r
291275
// We store the index for this certificate in the deduplication storage immediately.
292276
// It might be stored again later, if a local deduplication storage is synced, potentially
293277
// with a smaller value.
294-
klog.V(2).Infof("%s: %s => storage.AddCertIndex", li.log.origin, method)
295-
err = li.log.storage.AddCertDedupInfo(ctx, chain[0], dedup.SCTDedupInfo{Idx: idx, Timestamp: entry.Timestamp})
278+
klog.V(2).Infof("%s: %s => storage.AddCertIndex", log.origin, method)
279+
err = log.storage.AddCertDedupInfo(ctx, chain[0], dedup.SCTDedupInfo{Idx: idx, Timestamp: entry.Timestamp})
296280
// TODO: block log writes if deduplication breaks
297281
if err != nil {
298282
klog.Warningf("AddCertIndex(): failed to store certificate index: %v", err)
@@ -311,7 +295,7 @@ func addChainInternal(ctx context.Context, li *logInfo, w http.ResponseWriter, r
311295
// As the Log server has definitely got the Merkle tree leaf, we can
312296
// generate an SCT and respond with it.
313297
// TODO(phboneff): this should work, but double check
314-
sct, err := li.log.signSCT(&loggedLeaf)
298+
sct, err := log.signSCT(&loggedLeaf)
315299
if err != nil {
316300
return http.StatusInternalServerError, fmt.Errorf("failed to generate SCT: %s", err)
317301
}
@@ -320,32 +304,32 @@ func addChainInternal(ctx context.Context, li *logInfo, w http.ResponseWriter, r
320304
return http.StatusInternalServerError, fmt.Errorf("failed to marshall SCT: %s", err)
321305
}
322306
// We could possibly fail to issue the SCT after this but it's v. unlikely.
323-
li.iOpts.RequestLog.issueSCT(ctx, sctBytes)
307+
opts.RequestLog.issueSCT(ctx, sctBytes)
324308
err = marshalAndWriteAddChainResponse(sct, w)
325309
if err != nil {
326310
// reason is logged and http status is already set
327311
return http.StatusInternalServerError, fmt.Errorf("failed to write response: %s", err)
328312
}
329-
klog.V(3).Infof("%s: %s <= SCT", li.log.origin, method)
313+
klog.V(3).Infof("%s: %s <= SCT", log.origin, method)
330314
if sct.Timestamp == timeMillis {
331-
lastSCTTimestamp.Set(float64(sct.Timestamp), li.log.origin)
315+
lastSCTTimestamp.Set(float64(sct.Timestamp), log.origin)
332316
}
333317

334318
return http.StatusOK, nil
335319
}
336320

337-
func addChain(ctx context.Context, li *logInfo, w http.ResponseWriter, r *http.Request) (int, error) {
338-
return addChainInternal(ctx, li, w, r, false)
321+
func addChain(ctx context.Context, opts *HandlerOptions, log *log, w http.ResponseWriter, r *http.Request) (int, error) {
322+
return addChainInternal(ctx, opts, log, w, r, false)
339323
}
340324

341-
func addPreChain(ctx context.Context, li *logInfo, w http.ResponseWriter, r *http.Request) (int, error) {
342-
return addChainInternal(ctx, li, w, r, true)
325+
func addPreChain(ctx context.Context, opts *HandlerOptions, log *log, w http.ResponseWriter, r *http.Request) (int, error) {
326+
return addChainInternal(ctx, opts, log, w, r, true)
343327
}
344328

345-
func getRoots(_ context.Context, li *logInfo, w http.ResponseWriter, _ *http.Request) (int, error) {
329+
func getRoots(_ context.Context, opts *HandlerOptions, log *log, w http.ResponseWriter, _ *http.Request) (int, error) {
346330
// Pull out the raw certificates from the parsed versions
347-
rawCerts := make([][]byte, 0, len(li.log.chainValidationOpts.trustedRoots.RawCertificates()))
348-
for _, cert := range li.log.chainValidationOpts.trustedRoots.RawCertificates() {
331+
rawCerts := make([][]byte, 0, len(log.chainValidationOpts.trustedRoots.RawCertificates()))
332+
for _, cert := range log.chainValidationOpts.trustedRoots.RawCertificates() {
349333
rawCerts = append(rawCerts, cert.Raw)
350334
}
351335

@@ -354,23 +338,23 @@ func getRoots(_ context.Context, li *logInfo, w http.ResponseWriter, _ *http.Req
354338
enc := json.NewEncoder(w)
355339
err := enc.Encode(jsonMap)
356340
if err != nil {
357-
klog.Warningf("%s: get_roots failed: %v", li.log.origin, err)
341+
klog.Warningf("%s: get_roots failed: %v", log.origin, err)
358342
return http.StatusInternalServerError, fmt.Errorf("get-roots failed with: %s", err)
359343
}
360344

361345
return http.StatusOK, nil
362346
}
363347

364348
// deadlineTime calculates the future time a request should expire based on our config.
365-
func deadlineTime(li *logInfo) time.Time {
366-
return li.iOpts.TimeSource.Now().Add(li.iOpts.Deadline)
349+
func deadlineTime(opts *HandlerOptions) time.Time {
350+
return opts.TimeSource.Now().Add(opts.Deadline)
367351
}
368352

369353
// verifyAddChain is used by add-chain and add-pre-chain. It does the checks that the supplied
370354
// cert is of the correct type and chains to a trusted root.
371-
func verifyAddChain(li *logInfo, req ct.AddChainRequest, expectingPrecert bool) ([]*x509.Certificate, error) {
355+
func verifyAddChain(log *log, req ct.AddChainRequest, expectingPrecert bool) ([]*x509.Certificate, error) {
372356
// We already checked that the chain is not empty so can move on to verification
373-
validPath, err := validateChain(req.Chain, li.log.chainValidationOpts)
357+
validPath, err := validateChain(req.Chain, log.chainValidationOpts)
374358
if err != nil {
375359
// We rejected it because the cert failed checks or we could not find a path to a root etc.
376360
// Lots of possible causes for errors
@@ -385,9 +369,9 @@ func verifyAddChain(li *logInfo, req ct.AddChainRequest, expectingPrecert bool)
385369
// The type of the leaf must match the one the handler expects
386370
if isPrecert != expectingPrecert {
387371
if expectingPrecert {
388-
klog.Warningf("%s: Cert (or precert with invalid CT ext) submitted as precert chain: %q", li.log.origin, req.Chain)
372+
klog.Warningf("%s: Cert (or precert with invalid CT ext) submitted as precert chain: %q", log.origin, req.Chain)
389373
} else {
390-
klog.Warningf("%s: Precert (or cert with invalid CT ext) submitted as cert chain: %q", li.log.origin, req.Chain)
374+
klog.Warningf("%s: Precert (or cert with invalid CT ext) submitted as cert chain: %q", log.origin, req.Chain)
391375
}
392376
return nil, fmt.Errorf("cert / precert mismatch: %T", expectingPrecert)
393377
}

handlers_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func setupTest(t *testing.T, pemRoots []string, signer crypto.Signer) handlerTes
8181
rejectExpired: false,
8282
}
8383

84-
iOpts := HandlerOptions{
84+
hOpts := HandlerOptions{
8585
Deadline: time.Millisecond * 500,
8686
MetricFactory: monitoring.InertMetricFactory{},
8787
RequestLog: new(DefaultRequestLog),
@@ -96,7 +96,7 @@ func setupTest(t *testing.T, pemRoots []string, signer crypto.Signer) handlerTes
9696
origin: origin,
9797
chainValidationOpts: vOpts,
9898
}
99-
info.handlers = NewPathHandlers(&iOpts, &log)
99+
info.handlers = NewPathHandlers(&hOpts, &log)
100100

101101
for _, pemRoot := range pemRoots {
102102
if !info.roots.AppendCertsFromPEM([]byte(pemRoot)) {

0 commit comments

Comments
 (0)