...
1 package main
2
3 import (
4 "context"
5 "crypto/x509"
6 "flag"
7 "fmt"
8 "io"
9 "net/http"
10 "sync"
11 "time"
12
13 "github.com/letsencrypt/boulder/cmd"
14 "github.com/letsencrypt/boulder/core"
15 "github.com/letsencrypt/boulder/revocation"
16 )
17
18 type s3TestSrv struct {
19 sync.RWMutex
20 allSerials map[string]revocation.Reason
21 allShards map[string][]byte
22 }
23
24 func (srv *s3TestSrv) handleS3(w http.ResponseWriter, r *http.Request) {
25 if r.Method == "PUT" {
26 srv.handleUpload(w, r)
27 } else if r.Method == "GET" {
28 srv.handleDownload(w, r)
29 } else {
30 w.WriteHeader(405)
31 }
32 }
33
34 func (srv *s3TestSrv) handleUpload(w http.ResponseWriter, r *http.Request) {
35 body, err := io.ReadAll(r.Body)
36 if err != nil {
37 w.WriteHeader(500)
38 w.Write([]byte("failed to read request body"))
39 return
40 }
41
42 crl, err := x509.ParseRevocationList(body)
43 if err != nil {
44 w.WriteHeader(500)
45 w.Write([]byte(fmt.Sprintf("failed to parse body: %s", err)))
46 return
47 }
48
49 srv.Lock()
50 defer srv.Unlock()
51 srv.allShards[r.URL.Path] = body
52 for _, rc := range crl.RevokedCertificateEntries {
53 srv.allSerials[core.SerialToString(rc.SerialNumber)] = revocation.Reason(rc.ReasonCode)
54 }
55
56 w.WriteHeader(200)
57 w.Write([]byte("{}"))
58 }
59
60 func (srv *s3TestSrv) handleDownload(w http.ResponseWriter, r *http.Request) {
61 body, ok := srv.allShards[r.URL.Path]
62 if !ok {
63 w.WriteHeader(404)
64 return
65 }
66 w.WriteHeader(200)
67 w.Write(body)
68 }
69
70 func (srv *s3TestSrv) handleQuery(w http.ResponseWriter, r *http.Request) {
71 if r.Method != "GET" {
72 w.WriteHeader(405)
73 return
74 }
75
76 serial := r.URL.Query().Get("serial")
77 if serial == "" {
78 w.WriteHeader(400)
79 return
80 }
81
82 srv.RLock()
83 defer srv.RUnlock()
84 reason, ok := srv.allSerials[serial]
85 if !ok {
86 w.WriteHeader(404)
87 return
88 }
89
90 w.WriteHeader(200)
91 w.Write([]byte(fmt.Sprintf("%d", reason)))
92 }
93
94 func main() {
95 listenAddr := flag.String("listen", "0.0.0.0:7890", "Address to listen on")
96 flag.Parse()
97
98 srv := s3TestSrv{
99 allSerials: make(map[string]revocation.Reason),
100 allShards: make(map[string][]byte),
101 }
102
103 http.HandleFunc("/", srv.handleS3)
104 http.HandleFunc("/query", srv.handleQuery)
105
106 s := http.Server{
107 ReadTimeout: 30 * time.Second,
108 Addr: *listenAddr,
109 }
110
111 go func() {
112 err := s.ListenAndServe()
113 if err != nil && err != http.ErrServerClosed {
114 cmd.FailOnError(err, "Running TLS server")
115 }
116 }()
117
118 defer func() {
119 ctx, cancel := context.WithTimeout(context.Background(), time.Second)
120 defer cancel()
121 _ = s.Shutdown(ctx)
122 }()
123
124 cmd.WaitForSignal()
125 }
126
View as plain text