1// Copyright 2017 Istio Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package env 16 17import ( 18 "fmt" 19 "io/ioutil" 20 "log" 21 "net" 22 "net/http" 23 "strconv" 24 "sync" 25 "time" 26) 27 28// If HTTP header has non empty FailHeader, 29// HTTP server will fail the request with 400 with FailBody in the response body. 30const ( 31 FailHeader = "x-istio-backend-fail" 32 FailBody = "Bad request from backend." 33) 34 35const publicKey = ` 36{ 37 "keys": [ 38 { 39 "alg": "RS256", 40 "e": "AQAB", 41 "kid": "62a93512c9ee4c7f8067b5a216dade2763d32a47", 42 "kty": "RSA", 43 "n": "` + 44 "0YWnm_eplO9BFtXszMRQNL5UtZ8HJdTH2jK7vjs4XdLkPW7YBkkm_2xNgcaVpkW0VT2l4mU3KftR-6" + 45 "s3Oa5Rnz5BrWEUkCTVVolR7VYksfqIB2I_x5yZHdOiomMTcm3DheUUCgbJRv5OKRnNqszA4xHn3tA3" + 46 "Ry8VO3X7BgKZYAUh9fyZTFLlkeAh0-bLK5zvqCmKW5QgDIXSxUTJxPjZCgfx1vmAfGqaJb-nvmrORX" + 47 "Q6L284c73DUL7mnt6wj3H6tVqPKA27j56N0TB1Hfx4ja6Slr8S4EB3F1luYhATa1PKUSH8mYDW11Ho" + 48 "lzZmTQpRoLV8ZoHbHEaTfqX_aYahIw" + 49 `", 50 "use": "sig" 51 }, 52 { 53 "alg": "RS256", 54 "e": "AQAB", 55 "kid": "b3319a147514df7ee5e4bcdee51350cc890cc89e", 56 "kty": "RSA", 57 "n": "` + 58 "qDi7Tx4DhNvPQsl1ofxxc2ePQFcs-L0mXYo6TGS64CY_2WmOtvYlcLNZjhuddZVV2X88m0MfwaSA16w" + 59 "E-RiKM9hqo5EY8BPXj57CMiYAyiHuQPp1yayjMgoE1P2jvp4eqF-BTillGJt5W5RuXti9uqfMtCQdag" + 60 "B8EC3MNRuU_KdeLgBy3lS3oo4LOYd-74kRBVZbk2wnmmb7IhP9OoLc1-7-9qU1uhpDxmE6JwBau0mDS" + 61 "wMnYDS4G_ML17dC-ZDtLd1i24STUw39KH0pcSdfFbL2NtEZdNeam1DDdk0iUtJSPZliUHJBI_pj8M-2" + 62 "Mn_oA8jBuI8YKwBqYkZCN1I95Q" + 63 `", 64 "use": "sig" 65 } 66 ] 67} 68` 69 70// HTTPServer stores data for a HTTP server. 71type HTTPServer struct { 72 port uint16 73 lis net.Listener 74 75 reqHeaders http.Header 76 mu sync.Mutex 77} 78 79func pubkeyHandler(w http.ResponseWriter, _ *http.Request) { 80 _, _ = fmt.Fprintf(w, "%v", publicKey) 81} 82 83// handle handles a request and sends response. If ?delay=n is in request URL, then sleeps for 84// n second and sends response. 85func (s *HTTPServer) handle(w http.ResponseWriter, r *http.Request) { 86 body, err := ioutil.ReadAll(r.Body) 87 if err != nil { 88 http.Error(w, err.Error(), http.StatusInternalServerError) 89 return 90 } 91 92 // Fail if there is such header. 93 if r.Header.Get(FailHeader) != "" { 94 w.WriteHeader(http.StatusBadRequest) 95 _, _ = w.Write([]byte(FailBody)) 96 return 97 } 98 99 // echo back the Content-Type and Content-Length in the response 100 for _, k := range []string{"Content-Type", "Content-Length"} { 101 if v := r.Header.Get(k); v != "" { 102 w.Header().Set(k, v) 103 } 104 } 105 106 if delay := r.URL.Query().Get("delay"); delay != "" { 107 delaySeconds, err := strconv.ParseInt(delay, 10, 64) 108 if err != nil { 109 w.WriteHeader(http.StatusBadRequest) 110 _, _ = w.Write([]byte("Bad request parameter: delay")) 111 return 112 } 113 time.Sleep(time.Duration(delaySeconds) * time.Second) 114 } 115 116 w.WriteHeader(http.StatusOK) 117 118 reqHeaders := make(http.Header) 119 reqHeaders[":method"] = []string{r.Method} 120 reqHeaders[":authority"] = []string{r.Host} 121 reqHeaders[":path"] = []string{r.URL.String()} 122 for name, headers := range r.Header { 123 reqHeaders[name] = append(reqHeaders[name], headers...) 124 } 125 126 s.mu.Lock() 127 s.reqHeaders = reqHeaders 128 s.mu.Unlock() 129 130 _, _ = w.Write(body) 131} 132 133// NewHTTPServer creates a new HTTP server. 134func NewHTTPServer(port uint16) (*HTTPServer, error) { 135 log.Printf("Http server listening on port %v\n", port) 136 lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 137 if err != nil { 138 log.Fatal(err) 139 return nil, err 140 } 141 return &HTTPServer{ 142 port: port, 143 lis: lis, 144 }, nil 145} 146 147// Start starts the server 148func (s *HTTPServer) Start() <-chan error { 149 errCh := make(chan error) 150 go func() { 151 http.HandleFunc("/", s.handle) 152 http.HandleFunc("/pubkey", pubkeyHandler) 153 errCh <- http.Serve(s.lis, nil) 154 }() 155 go func() { 156 url := fmt.Sprintf("http://localhost:%v/echo", s.port) 157 errCh <- WaitForHTTPServer(url) 158 }() 159 160 return errCh 161} 162 163// Stop shutdown the server 164func (s *HTTPServer) Stop() { 165 log.Printf("Close HTTP server\n") 166 _ = s.lis.Close() 167 log.Printf("Close HTTP server -- Done\n") 168} 169 170// LastRequestHeaders returns the headers from the last request and clears the value 171func (s *HTTPServer) LastRequestHeaders() http.Header { 172 s.mu.Lock() 173 out := s.reqHeaders 174 s.reqHeaders = nil 175 s.mu.Unlock() 176 177 return out 178} 179