github.com/letsencrypt/boulder@v0.20251208.0/test/chall-test-srv/history.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 9 "github.com/letsencrypt/challtestsrv" 10 ) 11 12 // clearHistory handles an HTTP POST request to clear the challenge server 13 // request history for a specific hostname and type of event. 14 // 15 // The POST body is expected to have two parameters: 16 // "host" - the hostname to clear history for. 17 // "type" - the type of event to clear. May be "http", "dns", or "tlsalpn". 18 // 19 // A successful POST will write http.StatusOK to the client. 20 func (srv *managementServer) clearHistory(w http.ResponseWriter, r *http.Request) { 21 var request struct { 22 Host string 23 Type string `json:"type"` 24 } 25 if err := mustParsePOST(&request, r); err != nil { 26 http.Error(w, err.Error(), http.StatusBadRequest) 27 return 28 } 29 typeMap := map[string]challtestsrv.RequestEventType{ 30 "http": challtestsrv.HTTPRequestEventType, 31 "dns": challtestsrv.DNSRequestEventType, 32 "tlsalpn": challtestsrv.TLSALPNRequestEventType, 33 } 34 if request.Host == "" { 35 http.Error(w, "host parameter must not be empty", http.StatusBadRequest) 36 return 37 } 38 if code, ok := typeMap[request.Type]; ok { 39 srv.challSrv.ClearRequestHistory(request.Host, code) 40 srv.log.Printf("Cleared challenge server request history for %q %q events\n", 41 request.Host, request.Type) 42 w.WriteHeader(http.StatusOK) 43 return 44 } 45 46 http.Error(w, fmt.Sprintf("%q event type unknown", request.Type), http.StatusBadRequest) 47 } 48 49 // getHTTPHistory returns only the HTTPRequestEvents for the given hostname 50 // from the challenge server's request history in JSON form. 51 func (srv *managementServer) getHTTPHistory(w http.ResponseWriter, r *http.Request) { 52 host, err := requestHost(r) 53 if err != nil { 54 http.Error(w, err.Error(), http.StatusBadRequest) 55 return 56 } 57 srv.writeHistory( 58 srv.challSrv.RequestHistory(host, challtestsrv.HTTPRequestEventType), 59 w) 60 } 61 62 // getDNSHistory returns only the DNSRequestEvents from the challenge 63 // server's request history in JSON form. 64 func (srv *managementServer) getDNSHistory(w http.ResponseWriter, r *http.Request) { 65 host, err := requestHost(r) 66 if err != nil { 67 http.Error(w, err.Error(), http.StatusBadRequest) 68 return 69 } 70 srv.writeHistory( 71 srv.challSrv.RequestHistory(host, challtestsrv.DNSRequestEventType), 72 w) 73 } 74 75 // getTLSALPNHistory returns only the TLSALPNRequestEvents from the challenge 76 // server's request history in JSON form. 77 func (srv *managementServer) getTLSALPNHistory(w http.ResponseWriter, r *http.Request) { 78 host, err := requestHost(r) 79 if err != nil { 80 http.Error(w, err.Error(), http.StatusBadRequest) 81 return 82 } 83 srv.writeHistory( 84 srv.challSrv.RequestHistory(host, challtestsrv.TLSALPNRequestEventType), 85 w) 86 } 87 88 // requestHost extracts the Host parameter of a JSON POST body in the provided 89 // request, or returns an error. 90 func requestHost(r *http.Request) (string, error) { 91 var request struct { 92 Host string 93 } 94 if err := mustParsePOST(&request, r); err != nil { 95 return "", err 96 } 97 if request.Host == "" { 98 return "", errors.New("host parameter of POST body must not be empty") 99 } 100 return request.Host, nil 101 } 102 103 // writeHistory writes the provided list of challtestsrv.RequestEvents to the 104 // provided http.ResponseWriter in JSON form. 105 func (srv *managementServer) writeHistory( 106 history []challtestsrv.RequestEvent, w http.ResponseWriter, 107 ) { 108 // Always write an empty JSON list instead of `null` 109 if history == nil { 110 history = []challtestsrv.RequestEvent{} 111 } 112 jsonHistory, err := json.MarshalIndent(history, "", " ") 113 if err != nil { 114 srv.log.Printf("Error marshaling history: %v\n", err) 115 w.WriteHeader(http.StatusInternalServerError) 116 return 117 } 118 119 w.Header().Set("Content-Type", "application/json; charset=utf-8") 120 w.WriteHeader(http.StatusOK) 121 _, _ = w.Write(jsonHistory) 122 }