github.com/ethersphere/bee/v2@v2.2.0/pkg/jsonhttp/handlers.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package jsonhttp 6 7 import ( 8 "fmt" 9 "net/http" 10 "sort" 11 "strings" 12 ) 13 14 type MethodHandler map[string]http.Handler 15 16 func (h MethodHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 17 HandleMethods(h, `{"message":"Method Not Allowed","code":405}`, DefaultContentTypeHeader, w, r) 18 } 19 20 // HandleMethods uses a corresponding Handler based on HTTP request method. 21 // If Handler is not found, a method not allowed HTTP response is returned 22 // with specified body and Content-Type header. 23 func HandleMethods(methods map[string]http.Handler, body string, contentType string, w http.ResponseWriter, r *http.Request) { 24 if handler, ok := methods[r.Method]; ok { 25 handler.ServeHTTP(w, r) 26 return 27 } 28 29 allow := make([]string, 0, len(methods)) 30 for k := range methods { 31 allow = append(allow, k) 32 } 33 sort.Strings(allow) 34 35 // true if not COR request 36 if len(w.Header().Get("Access-Control-Allow-Methods")) == 0 { 37 w.Header().Set("Allow", strings.Join(allow, ", ")) 38 } else { 39 w.Header().Set("Access-Control-Allow-Methods", strings.Join(allow, ", ")) 40 } 41 if r.Method == http.MethodOptions { 42 w.WriteHeader(http.StatusNoContent) 43 return 44 } 45 w.Header().Set("Content-Type", contentType) 46 w.WriteHeader(http.StatusMethodNotAllowed) 47 fmt.Fprintln(w, body) 48 49 } 50 51 func NotFoundHandler(w http.ResponseWriter, _ *http.Request) { 52 NotFound(w, nil) 53 } 54 55 // NewMaxBodyBytesHandler is an http middleware constructor that limits the 56 // maximal number of bytes that can be read from the request body. When a body 57 // is read, the error can be handled with a helper function HandleBodyReadError 58 // in order to respond with Request Entity Too Large response. 59 // See TestNewMaxBodyBytesHandler as an example. 60 func NewMaxBodyBytesHandler(limit int64) func(http.Handler) http.Handler { 61 return func(h http.Handler) http.Handler { 62 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 63 if r.ContentLength > limit { 64 RequestEntityTooLarge(w, nil) 65 return 66 } 67 r.Body = http.MaxBytesReader(w, r.Body, limit) 68 h.ServeHTTP(w, r) 69 }) 70 } 71 } 72 73 // HandleBodyReadError checks for particular errors and writes appropriate 74 // response accordingly. If no known error is found, no response is written and 75 // the function returns false. 76 func HandleBodyReadError(err error, w http.ResponseWriter) (responded bool) { 77 if err == nil { 78 return false 79 } 80 // http.MaxBytesReader returns an unexported error, 81 // this is the only way to detect it 82 if err.Error() == "http: request body too large" { 83 RequestEntityTooLarge(w, nil) 84 return true 85 } 86 return false 87 }