106 lines
2.4 KiB
Go
106 lines
2.4 KiB
Go
// Copyright (C) 2018 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package satelliteweb
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/graphql-go/graphql"
|
|
"github.com/zeebo/errs"
|
|
|
|
"storj.io/storj/pkg/auth"
|
|
"storj.io/storj/pkg/satellite/satelliteweb/satelliteql"
|
|
"storj.io/storj/pkg/utils"
|
|
)
|
|
|
|
const (
|
|
authorization = "Authorization"
|
|
contentType = "Content-Type"
|
|
|
|
authorizationBearer = "Bearer "
|
|
|
|
applicationJSON = "application/json"
|
|
applicationGraphql = "application/graphql"
|
|
)
|
|
|
|
// JSON request from graphql clients
|
|
type graphqlJSON struct {
|
|
Query string
|
|
OperationName string
|
|
Variables map[string]interface{}
|
|
}
|
|
|
|
func (gw *gateway) grapqlHandler(w http.ResponseWriter, req *http.Request) {
|
|
w.Header().Set(contentType, applicationJSON)
|
|
|
|
token := getToken(req)
|
|
query, err := getQuery(req)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
result := graphql.Do(graphql.Params{
|
|
Schema: gw.schema,
|
|
Context: auth.WithAPIKey(context.Background(), []byte(token)),
|
|
RequestString: query.Query,
|
|
VariableValues: query.Variables,
|
|
OperationName: query.OperationName,
|
|
})
|
|
|
|
err = json.NewEncoder(w).Encode(result)
|
|
if err != nil {
|
|
gw.logger.Error(err)
|
|
return
|
|
}
|
|
|
|
gw.logger.Debug(result)
|
|
}
|
|
|
|
// getToken retrieves token from request
|
|
func getToken(req *http.Request) string {
|
|
value := req.Header.Get(authorization)
|
|
if value == "" {
|
|
return ""
|
|
}
|
|
|
|
if !strings.HasPrefix(value, authorizationBearer) {
|
|
return ""
|
|
}
|
|
|
|
return value[len(authorizationBearer):]
|
|
}
|
|
|
|
// getQuery retrieves graphql query from request
|
|
func getQuery(req *http.Request) (query graphqlJSON, err error) {
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
query.Query = req.URL.Query().Get(satelliteql.Query)
|
|
return query, nil
|
|
case http.MethodPost:
|
|
return queryPOST(req)
|
|
default:
|
|
return query, errs.New("wrong http request type")
|
|
}
|
|
}
|
|
|
|
// queryPOST retrieves graphql query from POST request
|
|
func queryPOST(req *http.Request) (query graphqlJSON, err error) {
|
|
switch typ := req.Header.Get(contentType); typ {
|
|
case applicationGraphql:
|
|
body, err := ioutil.ReadAll(req.Body)
|
|
query.Query = string(body)
|
|
return query, utils.CombineErrors(err, req.Body.Close())
|
|
case applicationJSON:
|
|
err := json.NewDecoder(req.Body).Decode(&query)
|
|
return query, utils.CombineErrors(err, req.Body.Close())
|
|
default:
|
|
return query, errs.New("can't parse request body of type %s", typ)
|
|
}
|
|
}
|