github.com/go-graphite/carbonapi@v0.17.0/cmd/carbonapi/http/capability.go (about) 1 package http 2 3 import ( 4 "encoding/json" 5 "io" 6 "net/http" 7 "os" 8 "time" 9 10 pb "github.com/go-graphite/protocol/carbonapi_v3_pb" 11 "github.com/lomik/zapwriter" 12 "go.uber.org/zap" 13 14 "github.com/go-graphite/carbonapi/zipper/httpHeaders" 15 ) 16 17 func capabilityHandler(wr http.ResponseWriter, req *http.Request) { 18 t0 := time.Now() 19 20 accessLogger := zapwriter.Logger("access").With( 21 zap.String("handler", "capability"), 22 zap.String("url", req.URL.RequestURI()), 23 zap.String("peer", req.RemoteAddr), 24 ) 25 26 format := req.FormValue("format") 27 28 accepts := req.Header["Accept"] 29 for _, accept := range accepts { 30 if accept == httpHeaders.ContentTypeCarbonAPIv3PB { 31 format = "carbonapi_v3_pb" 32 break 33 } 34 } 35 36 if formatCode, ok := knownFormats[format]; ok { 37 body, err := io.ReadAll(req.Body) 38 if err != nil { 39 accessLogger.Error("find failed", 40 zap.Duration("runtime_seconds", time.Since(t0)), 41 zap.String("reason", err.Error()), 42 zap.Int("http_code", http.StatusBadRequest), 43 ) 44 http.Error(wr, "Bad request (unsupported format)", 45 http.StatusBadRequest, 46 ) 47 } 48 49 var pv3Request pb.CapabilityRequest 50 err = pv3Request.Unmarshal(body) 51 if err != nil { 52 accessLogger.Error("find failed", 53 zap.Duration("runtime_seconds", time.Since(t0)), 54 zap.String("reason", err.Error()), 55 zap.Int("http_code", http.StatusBadRequest), 56 ) 57 http.Error(wr, "Bad request (malformed body)", 58 http.StatusBadRequest, 59 ) 60 } 61 62 hostname, err := os.Hostname() 63 if err != nil { 64 hostname = "(unknown)" 65 } 66 pvResponse := pb.CapabilityResponse{ 67 SupportedProtocols: []string{"carbonapi_v3_pb", "carbonapi_v2_pb", "graphite-web-pickle", "graphite-web-pickle-1.1", "carbonapi_v2_json"}, 68 Name: hostname, 69 HighPrecisionTimestamps: false, 70 SupportFilteringFunctions: false, 71 LikeSplittedRequests: false, 72 SupportStreaming: false, 73 } 74 75 var data []byte 76 contentType := "" 77 switch formatCode { 78 case jsonFormat: 79 contentType = httpHeaders.ContentTypeJSON 80 data, err = json.Marshal(pvResponse) 81 case protoV3Format: 82 contentType = httpHeaders.ContentTypeCarbonAPIv3PB 83 data, err = pvResponse.Marshal() 84 } 85 86 if err != nil { 87 accessLogger.Error("capability failed", 88 zap.Duration("runtime_seconds", time.Since(t0)), 89 zap.String("reason", err.Error()), 90 zap.Int("http_code", http.StatusBadRequest), 91 ) 92 http.Error(wr, "Bad request (unsupported format)", 93 http.StatusBadRequest, 94 ) 95 } 96 97 wr.Header().Set("Content-Type", contentType) 98 _, _ = wr.Write(data) 99 } else { 100 accessLogger.Error("capability failed", 101 zap.Duration("runtime_seconds", time.Since(t0)), 102 zap.String("reason", "supported only for protoV3 format"), 103 zap.Int("http_code", http.StatusBadRequest), 104 ) 105 http.Error(wr, "Bad request (unsupported format)", 106 http.StatusBadRequest, 107 ) 108 } 109 110 accessLogger.Info("capability success", 111 zap.Duration("runtime_seconds", time.Since(t0)), 112 zap.Int("http_code", http.StatusOK), 113 ) 114 }