internal/httphandler/httphandler.go (61 lines of code) (raw):

// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package httphandler import ( "encoding/json" "fmt" "net/http" "sync" "github.com/GoogleCloudPlatform/gcping/internal/config" ) // Options contains parameters for Handler. type Options struct { // StaticRoot is the root for static serving content. StaticRoot http.FileSystem // Region is the region where the instance runs (e.g. us-west1). Region string // Endpoints is a list of available endpoints. Endpoints map[string]config.Endpoint } // Handler is a http.Handler implementation type Handler struct { Options once sync.Once handler http.Handler } // New returns a new intance of Handler based on opt. func New(opts *Options) *Handler { s := &Handler{ Options: *opts, } mux := http.NewServeMux() mux.HandleFunc("/", s.StaticHandler()) // TODO: clean up after PR#138 is merged and tested https://github.com/GoogleCloudPlatform/gcping/pull/138 mux.HandleFunc("/api/endpoints", s.HandleEndpoints) mux.HandleFunc("/api/ping", s.HandlePing) // Serve /ping with region response to fix issue#96 on older cli versions. mux.HandleFunc("/ping", s.HandlePing) s.handler = mux return s } // ServeHTTP implements http.Handler. func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { s.handler.ServeHTTP(w, r) } // StaticHandler returns a handler for static files at StaticRoot. func (s *Handler) StaticHandler() http.HandlerFunc { h := http.FileServer(s.StaticRoot) return func(w http.ResponseWriter, r *http.Request) { // TODO: add HTST header to static files. // addHTSTHeader(w) h.ServeHTTP(w, r) } } // HandleEndpoints returns a list of available endpoints as JSON. func (s *Handler) HandleEndpoints(w http.ResponseWriter, r *http.Request) { addHeaders(w) w.Header().Add("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(s.Endpoints); err != nil { w.WriteHeader(http.StatusInternalServerError) } } // HandlePing returns the current region as a response for ping. func (s *Handler) HandlePing(w http.ResponseWriter, r *http.Request) { addHeaders(w) s.once.Do(func() { w.Header().Add("X-First-Request", "true") }) fmt.Fprintln(w, s.Region) } func addHTSTHeader(w http.ResponseWriter) { w.Header().Add("Strict-Transport-Security", "max-age=3600; includeSubdomains; preload") } func addHeaders(w http.ResponseWriter) { addHTSTHeader(w) w.Header().Add("Cache-Control", "no-store") w.Header().Add("Access-Control-Allow-Origin", "*") }