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  }