You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: ocsp.go
    path of file: ./repos/plumber/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp
    
    the code of the file until where you have to start completion: // Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

package ocsp

import (
	"bytes"
	"context"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"errors"
	"fmt"
	"io/ioutil"
	"math/big"
	"net/http"
	"net/url"
	"time"

	"golang.org/x/crypto/ocsp"
	"golang.org/x/sync/errgroup"
)

var (
	tlsFeatureExtensionOID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24}
	mustStapleFeatureValue = big.NewInt(5)

	defaultRequestTimeout = 5 * time.Second
	errGotOCSPResponse    = errors.New("done")
)

// Error represents an OCSP verification error
type Error struct {
	wrapped error
}

// Error implements the error interface
func (e *Error) Error() string {
	return fmt.Sprintf("OCSP verification failed: %v", e.wrapped)
}

// Unwrap returns the underlying error.
func (e *Error) Unwrap() error {
	return e.wrapped
}

func newOCSPError(wrapped error) error {
	return &Error{wrapped: wrapped}
}

// ResponseDetails contains a subset of the details needed from an OCSP response after the original response has been
// validated.
type ResponseDetails struct {
	Status     int
	NextUpdate time.Time
}

func extractResponseDetails(res *ocsp.Response) *ResponseDetails {
	return &ResponseDetails{
		Status:     res.Status,
		NextUpdate: res.NextUpdate,
	}
}

// Verify performs OCSP verification for the provided ConnectionState instance.
func Verify(ctx context.Context, connState tls.ConnectionState, opts *VerifyOptions) error {
	if opts.Cache == nil {
		// There should always be an OCSP cache. Even if the user has specified the URI option to disable communication
		// with OCSP responders, the driver will cache any stapled responses. Requiring that the cache is non-nil
		// allows us to confirm that the cache is correctly being passed down from a higher level.
		return newOCSPError(errors.New("no OCSP cache provided"))
	}
	if len(connState.VerifiedChains) == 0 {
		return newOCSPError(errors.New("no verified certificate chains reported after TLS handshake"))
	}

	certChain := connState.VerifiedChains[0]
	if numCerts := len(certChain); numCerts == 0 {
		return newOCSPError(errors.New("verified chain contained no certificates"))
	}

	ocspCfg, err := newConfig(certChain, opts)
	if err != nil {
		return newOCSPError(err)
	}

	res, err := getParsedResponse(ctx, ocspCfg, connState)
	if err != nil {
		return err
	}
	if res == nil {
		// If no response was parsed from the staple and responders, the status of the certificate is unknown, so don't
		// error.
		return nil
	}

	if res.Status == ocsp.Revoked {
		return newOCSPError(errors.New("certificate is revoked"))
	}
	return nil
}

// getParsedResponse attempts to parse a response from the stapled OCSP data or by contacting OCSP responders if no
// staple is present.
func getParsedResponse(ctx context.Context, cfg config, connState tls.ConnectionState) (*ResponseDetails, error) {
	stapledResponse, err := processStaple(cfg, connState.OCSPResponse)
	if err != nil {
		return nil, err
	}

	if stapledResponse != nil {
		// If there is a staple, attempt to cache it. The cache.Update call will resolve conflicts with an existing
		// cache enry if necessary.
		return cfg.cache.Update(cfg.ocspRequest, stapledResponse), nil
	}
	if cachedResponse := cfg.cache.Get(cfg.ocspRequest); cachedResponse != nil {
		return cachedResponse, nil
	}

	// If there is no stapled or cached response, fall back to querying the responders if that functionality has not
	// been disabled.
	if cfg.disableEndpointChecking {
		return nil, nil
	}
	e
    
func contactResponders(ctx context.Context, cfg config) (*ResponseDetails, error) {
	if len(cfg.serverCert.OCSPServer) == 0 {
		return nil, nil
	}

	requestCtx := ctx // Either ctx or a new context derived from ctx with a five second timeout.
	userContextUsed := true
	var cancelFn context.CancelFunc

	// Use a context with defaultRequestTimeout if ctx does not have a deadline set or the current deadline is further
	// out than defaultRequestTimeout. If the current deadline is less than less than defaultRequestTimeout out, respect
	// it. Calling context.WithTimeout would do this for us, but we need to know which context we're using.
	wantDeadline := time.Now().Add(defaultRequestTimeout)
	if deadline, ok := ctx.Deadline(); !ok || deadline.After(wantDeadline) {
		userContextUsed = false
		requestCtx, cancelFn = context.WithDeadline(ctx, wantDeadline)
	}
	defer func() {
		if cancelFn != nil {
			cancelFn()
		}
	}()

	group, groupCtx := errgroup.WithContext(requestCtx)
	ocspResponses := make(chan *ocsp.Response, len(cfg.serverCert.OCSPServer))
	defer close(ocspResponses)

	for _, endpoint := range cfg.serverCert.OCSPServer {
		// Re-assign endpoint so it gets re-scoped rather than using the iteration variable in the goroutine. See
		// https://golang.org/doc/faq#closures_and_goroutines.
		endpoint := endpoint
		group.Go(func() error {
			// Use bytes.NewReader instead of bytes.NewBuffer because a bytes.Buffer is an owning representation and the
			// docs recommend not using the underlying []byte after creating the buffer, so a new copy of the request
			// bytes would be needed for each request.
			request, err := http.NewRequest("POST", endpoint, bytes.NewReader(cfg.ocspRequestBytes))
			if err != nil {
				return nil
			}
			request = request.WithContext(groupCtx)

			// Execute the request and handle errors as follows:
			//
			// 1. If the original context expired or was cancelled, propagate the error up so the caller will abort the
			// verification and return control to the user.
			//
			// 2. If any other errors occurred, including the defaultRequestTimeout expiring, or the response has a
			// non-200 status code, suppress the error because we want to ignore this responder and wait for a different
			// one to responsd.
			httpResponse, err := http.DefaultClient.Do(request)
			if err != nil {
				urlErr, ok := err.(*url.Error)
				if !ok {
					return nil
				}

				timeout := urlErr.Timeout()
				cancelled := urlErr.Err == context.Canceled // Timeout() does not return true for context.Cancelled.
				if cancelled || (userContextUsed && timeout) {
					// Handle the original context expiring or being cancelled. The url.Error type supports Unwrap, so
					// users can use errors.Is to check for context errors.
					return err
				}
				return nil // Ignore all other errors.
			}
			defer func() {
				_ = httpResponse.Body.Close()
			}()
			if httpResponse.StatusCode != 200 {
				return nil
			}

			httpBytes, err := ioutil.ReadAll(httpResponse.Body)
			if err != nil {
				return nil
			}

			ocspResponse, err := ocsp.ParseResponseForCert(httpBytes, cfg.serverCert, cfg.issuer)
			if err != nil || verifyResponse(cfg, ocspResponse) != nil || ocspResponse.Status == ocsp.Unknown {
				// If there was an error parsing/validating the response or the response was inconclusive, suppress
				// the error because we want to ignore this responder.
				return nil
			}

			// Store the response and return a sentinel error so the error group will exit and any in-flight requests
			// will be cancelled.
			ocspResponses <- ocspResponse
			return errGotOCSPResponse
		})
	}

	if err := group.Wait(); err != nil && err != errGotOCSPResponse {
		return nil, err
	}
	if len(ocspResponses) == 0 {
		// None of the responders gave a conclusive response.
		return nil, nil
	}
	return extractResponseDetails(<-ocspResponses), nil
}