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  }