kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/serving/tools/http_server/http_server.go (about) 1 /* 2 * Copyright 2015 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Binary http_server exposes HTTP interfaces for the xrefs and filetree 18 // services backed by a combined serving table. 19 package main 20 21 import ( 22 "context" 23 "flag" 24 "net/http" 25 "os" 26 "path/filepath" 27 28 "kythe.io/kythe/go/services/filetree" 29 "kythe.io/kythe/go/services/graph" 30 "kythe.io/kythe/go/services/xrefs" 31 ftsrv "kythe.io/kythe/go/serving/filetree" 32 gsrv "kythe.io/kythe/go/serving/graph" 33 "kythe.io/kythe/go/serving/identifiers" 34 xsrv "kythe.io/kythe/go/serving/xrefs" 35 "kythe.io/kythe/go/storage/leveldb" 36 "kythe.io/kythe/go/storage/table" 37 "kythe.io/kythe/go/util/flagutil" 38 "kythe.io/kythe/go/util/log" 39 40 "golang.org/x/net/http2" 41 42 _ "kythe.io/kythe/go/services/graphstore/proxy" 43 ) 44 45 var ( 46 servingTable = flag.String("serving_table", "", "LevelDB serving table") 47 48 httpListeningAddr = flag.String("listen", "localhost:8080", "Listening address for HTTP server (\":<port>\" allows access from any machine)") 49 httpAllowOrigin = flag.String("http_allow_origin", "", "If set, each HTTP response will contain a Access-Control-Allow-Origin header with the given value") 50 publicResources = flag.String("public_resources", "", "Path to directory of static resources to serve") 51 52 tlsListeningAddr = flag.String("tls_listen", "", "Listening address for TLS HTTP server") 53 tlsCertFile = flag.String("tls_cert_file", "", "Path to file with concatenation of TLS certificates") 54 tlsKeyFile = flag.String("tls_key_file", "", "Path to file with TLS private key") 55 56 maxTicketsPerRequest = flag.Int("max_tickets_per_request", 20, "Maximum number of tickets allowed per request") 57 ) 58 59 func init() { 60 flag.Usage = flagutil.SimpleUsage("Exposes HTTP interfaces for the xrefs and filetree services", 61 "(--graphstore spec | --serving_table path) [--listen addr] [--public_resources dir]") 62 } 63 64 func main() { 65 flag.Parse() 66 if *servingTable == "" { 67 flagutil.UsageError("missing --serving_table") 68 } else if *httpListeningAddr == "" && *tlsListeningAddr == "" { 69 flagutil.UsageError("missing either --listen or --tls_listen argument") 70 } else if *tlsListeningAddr != "" && (*tlsCertFile == "" || *tlsKeyFile == "") { 71 flagutil.UsageError("--tls_cert_file and --tls_key_file are required if given --tls_listen") 72 } else if flag.NArg() > 0 { 73 flagutil.UsageErrorf("unknown non-flag arguments given: %v", flag.Args()) 74 } 75 76 var ( 77 xs xrefs.Service 78 gs graph.Service 79 it identifiers.Service 80 ft filetree.Service 81 ) 82 83 ctx := context.Background() 84 db, err := leveldb.Open(*servingTable, &leveldb.Options{MustExist: true}) 85 if err != nil { 86 log.Fatalf("Error opening db at %q: %v", *servingTable, err) 87 } 88 defer db.Close(ctx) 89 xs = xsrv.NewService(ctx, db) 90 gs = gsrv.NewService(ctx, db) 91 if *maxTicketsPerRequest > 0 { 92 xs = xrefs.BoundedRequests{ 93 Service: xs, 94 MaxTickets: *maxTicketsPerRequest, 95 } 96 gs = graph.BoundedRequests{ 97 Service: gs, 98 MaxTickets: *maxTicketsPerRequest, 99 } 100 } 101 tbl := &table.KVProto{db} 102 ft = &ftsrv.Table{Proto: tbl, PrefixedKeys: true} 103 it = &identifiers.Table{tbl} 104 105 if *httpListeningAddr != "" || *tlsListeningAddr != "" { 106 apiMux := http.NewServeMux() 107 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 108 if *httpAllowOrigin != "" { 109 w.Header().Set("Access-Control-Allow-Origin", *httpAllowOrigin) 110 } 111 apiMux.ServeHTTP(w, r) 112 }) 113 114 xrefs.RegisterHTTPHandlers(ctx, xs, apiMux) 115 graph.RegisterHTTPHandlers(ctx, gs, apiMux) 116 identifiers.RegisterHTTPHandlers(ctx, it, apiMux) 117 filetree.RegisterHTTPHandlers(ctx, ft, apiMux) 118 if *publicResources != "" { 119 log.Info("Serving public resources at", *publicResources) 120 if s, err := os.Stat(*publicResources); err != nil { 121 log.Fatalf("ERROR: could not get FileInfo for %q: %v", *publicResources, err) 122 } else if !s.IsDir() { 123 log.Fatalf("ERROR: %q is not a directory", *publicResources) 124 } 125 apiMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 126 http.ServeFile(w, r, filepath.Join(*publicResources, filepath.Clean(r.URL.Path))) 127 }) 128 } 129 } 130 if *httpListeningAddr != "" { 131 go startHTTP() 132 } 133 if *tlsListeningAddr != "" { 134 go startTLS() 135 } 136 137 select {} // block forever 138 } 139 140 func startHTTP() { 141 log.Infof("HTTP server listening on %q", *httpListeningAddr) 142 log.Fatal(http.ListenAndServe(*httpListeningAddr, nil)) 143 } 144 145 func startTLS() { 146 srv := &http.Server{Addr: *tlsListeningAddr} 147 http2.ConfigureServer(srv, nil) 148 149 log.Infof("TLS HTTP2 server listening on %q", *tlsListeningAddr) 150 log.Fatal(srv.ListenAndServeTLS(*tlsCertFile, *tlsKeyFile)) 151 }