mirror of
https://github.com/hanzoai/graph.git
synced 2026-10-30 18:35:37 +00:00
Derived from Dgraph (github.com/dgraph-io/dgraph) at commit 64804bd2, Apache-2.0. See NOTICE. WHAT THIS IS. The graph engine as a Go library: posting lists, the DQL parser, the type and tokenizer system, the index and schema layers, and the wire types. 39,170 lines of the upstream's 166,337. THE STORE is github.com/luxfi/zapdb, a Badger fork that kept the package name, the subpackages (options, pb, y) and the API — Open, OpenManaged, DB, Options — so the 74 import sites are aliased rather than rewritten. THE CODEC is ZAP. zapdb serializes with ZAP, not protobuf: its pb package builds the ZAP types by default and the protobuf ones only under `-tags grpc`, a path that does not compile (table/builder.go calls pb.Marshal, which that tag removes). One call site in posting needed converting; every other type here is Hanzo's own protobuf and is untouched. NO TRANSPORT. An embedded engine dials nothing, so nothing here imports google.golang.org/grpc. Removed: 20 transport functions in x, the generated service stubs for Raft, Zero and Worker (1,657 lines), and the JWT helper — identity belongs to IAM. The core called none of them. NOT KEPT: worker, conn, raftwal, the cluster commands, the GraphQL layer and the test harnesses. `query`, the DQL execution engine, went with them because it depends on worker; parsing DQL is available here, executing it is not. The history of the upstream project lives at github.com/dgraph-io/dgraph. This repository begins at the derivation because three quarters of that history describes code this fork does not carry.
136 lines
3.6 KiB
Go
136 lines
3.6 KiB
Go
/*
|
|
* SPDX-FileCopyrightText: © 2017-2026 Istari Digital, Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package x
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"crypto/tls"
|
|
"expvar"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/soheilhy/cmux"
|
|
|
|
"github.com/dgraph-io/ristretto/v2/z"
|
|
)
|
|
|
|
var (
|
|
// ServerCloser is used to signal and wait for other goroutines to return gracefully after user
|
|
// requests shutdown.
|
|
ServerCloser = z.NewCloser(0)
|
|
)
|
|
|
|
func StartListenHttpAndHttps(l net.Listener, tlsCfg *tls.Config, closer *z.Closer, h http.Handler) {
|
|
defer closer.Done()
|
|
m := cmux.New(l)
|
|
startServers(m, tlsCfg, h)
|
|
err := m.Serve()
|
|
if err != nil {
|
|
glog.Errorf("error from cmux serve: %v", err)
|
|
}
|
|
}
|
|
|
|
func startServers(m cmux.CMux, tlsConf *tls.Config, h http.Handler) {
|
|
httpRule := m.Match(func(r io.Reader) bool {
|
|
// no tls config is provided. http is being used.
|
|
if tlsConf == nil {
|
|
return true
|
|
}
|
|
path, ok := parseRequestPath(r)
|
|
if !ok {
|
|
// not able to parse the request. Let it be resolved via TLS
|
|
return false
|
|
}
|
|
// health endpoint will always be available over http.
|
|
// This is necessary for orchestration. It needs to be worked for
|
|
// monitoring tools which operate without authentication.
|
|
return strings.HasPrefix(path, "/health")
|
|
})
|
|
go startListen(httpRule, h)
|
|
|
|
// if tls is enabled, make tls encryption based connections as default
|
|
if tlsConf != nil {
|
|
httpsRule := m.Match(cmux.Any())
|
|
// this is chained listener. tls listener will decrypt
|
|
// the message and send it in plain text to HTTP server
|
|
go startListen(tls.NewListener(httpsRule, tlsConf), h)
|
|
}
|
|
}
|
|
|
|
func startListen(l net.Listener, h http.Handler) {
|
|
srv := &http.Server{
|
|
Handler: h, // nil falls back to http.DefaultServeMux
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 600 * time.Second,
|
|
IdleTimeout: 2 * time.Minute,
|
|
ReadHeaderTimeout: 60 * time.Second,
|
|
}
|
|
|
|
err := srv.Serve(l)
|
|
glog.Errorf("Stopped taking more http(s) requests. Err: %v", err)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 630*time.Second)
|
|
defer cancel()
|
|
err = srv.Shutdown(ctx)
|
|
glog.Infoln("All http(s) requests finished.")
|
|
if err != nil {
|
|
glog.Errorf("Http(s) shutdown err: %v", err)
|
|
}
|
|
}
|
|
|
|
func parseRequestPath(r io.Reader) (path string, ok bool) {
|
|
request, err := http.ReadRequest(bufio.NewReader(r))
|
|
if err != nil {
|
|
return "", false
|
|
}
|
|
|
|
return request.URL.Path, true
|
|
}
|
|
|
|
// filteredExpvarHandler serves /debug/vars but omits the "cmdline" key that
|
|
// expvar publishes by default (os.Args), which may contain the admin token
|
|
// from --security "token=...".
|
|
func filteredExpvarHandler(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
fmt.Fprintf(w, "{\n")
|
|
first := true
|
|
expvar.Do(func(kv expvar.KeyValue) {
|
|
if kv.Key == "cmdline" {
|
|
return
|
|
}
|
|
if !first {
|
|
fmt.Fprintf(w, ",\n")
|
|
}
|
|
first = false
|
|
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
|
|
})
|
|
fmt.Fprintf(w, "\n}\n")
|
|
}
|
|
|
|
// SanitizedDefaultServeMux returns an http.Handler that wraps
|
|
// http.DefaultServeMux but blocks endpoints that expose the full process
|
|
// command line (which may include the admin token from --security "token=..."):
|
|
// - /debug/pprof/cmdline — registered by net/http/pprof
|
|
// - /debug/vars — served with a filtered handler that omits "cmdline"
|
|
func SanitizedDefaultServeMux() http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path == "/debug/pprof/cmdline" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
if r.URL.Path == "/debug/vars" {
|
|
filteredExpvarHandler(w, r)
|
|
return
|
|
}
|
|
http.DefaultServeMux.ServeHTTP(w, r)
|
|
})
|
|
}
|