Skip to content

Commit

Permalink
More comprehensive tests for HTTP verb endpoints (rakyll#88)
Browse files Browse the repository at this point in the history
We were not explicitly testing the behavior of some HTTP verb endpoints
like /put and /patch, because they currently share an underlying handler
with /post which is thoroughly tested.

The addition of the /anything endpoint in rakyll#83 made me realize a bit more
explicit test coverage would be good, so here we're landing a bit of a
refactoring of the test suite to generate tests for all of those
endpoints.

Along the way, we also improve compatibility with the original httpbin
implementation by tricking the stdlib net/http machinery into parsing
request bodies for DELETE requests.
  • Loading branch information
mccutchen authored Oct 19, 2022
1 parent cc8e598 commit 4ec6c82
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 92 deletions.
26 changes: 13 additions & 13 deletions httpbin/digest/digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ type authorization struct {
// parseAuthorizationHeader parses an Authorization header into an
// Authorization struct, given a an authorization header like:
//
// Authorization: Digest username="Mufasa",
// realm="[email protected]",
// nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
// uri="/dir/index.html",
// qop=auth,
// nc=00000001,
// cnonce="0a4f113b",
// response="6629fae49393a05397450978507c4ef1",
// opaque="5ccc069c403ebaf9f0171e9517f40e41"
// Authorization: Digest username="Mufasa",
// realm="[email protected]",
// nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
// uri="/dir/index.html",
// qop=auth,
// nc=00000001,
// cnonce="0a4f113b",
// response="6629fae49393a05397450978507c4ef1",
// opaque="5ccc069c403ebaf9f0171e9517f40e41"
//
// If the given value does not contain a Digest authorization header, or is in
// some other way malformed, nil is returned.
Expand Down Expand Up @@ -174,7 +174,7 @@ func hash(data []byte, algorithm digestAlgorithm) string {

// makeHA1 returns the HA1 hash, where
//
// HA1 = H(A1) = H(username:realm:password)
// HA1 = H(A1) = H(username:realm:password)
//
// and H is one of MD5 or SHA256.
func makeHA1(realm, username, password string, algorithm digestAlgorithm) string {
Expand All @@ -184,7 +184,7 @@ func makeHA1(realm, username, password string, algorithm digestAlgorithm) string

// makeHA2 returns the HA2 hash, where
//
// HA2 = H(A2) = H(method:digestURI)
// HA2 = H(A2) = H(method:digestURI)
//
// and H is one of MD5 or SHA256.
func makeHA2(auth *authorization, method, uri string) string {
Expand All @@ -195,11 +195,11 @@ func makeHA2(auth *authorization, method, uri string) string {
// Response calculates the correct digest auth response. If the qop directive's
// value is "auth" or "auth-int" , then compute the response as
//
// RESPONSE = H(HA1:nonce:nonceCount:clientNonce:qop:HA2)
// RESPONSE = H(HA1:nonce:nonceCount:clientNonce:qop:HA2)
//
// and if the qop directive is unspecified, then compute the response as
//
// RESPONSE = H(HA1:nonce:HA2)
// RESPONSE = H(HA1:nonce:HA2)
//
// where H is one of MD5 or SHA256.
func response(auth *authorization, password, method, uri string) string {
Expand Down
14 changes: 12 additions & 2 deletions httpbin/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (h *HTTPBin) UTF8(w http.ResponseWriter, r *http.Request) {

// Get handles HTTP GET requests
func (h *HTTPBin) Get(w http.ResponseWriter, r *http.Request) {
resp := &getResponse{
resp := &noBodyResponse{
Args: r.URL.Query(),
Headers: getRequestHeaders(r),
Origin: getClientIP(r),
Expand All @@ -58,6 +58,16 @@ func (h *HTTPBin) Get(w http.ResponseWriter, r *http.Request) {
writeJSON(w, body, http.StatusOK)
}

// Anything returns anything that is passed to request.
func (h *HTTPBin) Anything(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET", "HEAD":
h.Get(w, r)
default:
h.RequestWithBody(w, r)
}
}

// RequestWithBody handles POST, PUT, and PATCH requests
func (h *HTTPBin) RequestWithBody(w http.ResponseWriter, r *http.Request) {
resp := &bodyResponse{
Expand Down Expand Up @@ -712,7 +722,7 @@ func (h *HTTPBin) ETag(w http.ResponseWriter, r *http.Request) {

// TODO: This mostly duplicates the work of Get() above, should this be
// pulled into a little helper?
resp := &getResponse{
resp := &noBodyResponse{
Args: r.URL.Query(),
Headers: getRequestHeaders(r),
Origin: getClientIP(r),
Expand Down
Loading

0 comments on commit 4ec6c82

Please sign in to comment.