github.com/bazelbuild/rules_webtesting@v0.2.0/go/wsl/wsl.go (about) 1 // Copyright 2018 Google Inc. 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 15 // Package wsl implements the basic server code for WSL (Webdriver Server Light), 16 // a lightweight replacement for Selenium Server. 17 package wsl 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "log" 24 "net/http" 25 "runtime" 26 "time" 27 28 "github.com/bazelbuild/rules_webtesting/go/httphelper" 29 "github.com/bazelbuild/rules_webtesting/go/wsl/hub" 30 "github.com/bazelbuild/rules_webtesting/go/wsl/upload" 31 ) 32 33 // Run starts the WSL server. 34 func Run(localHost string, port int, downloadRoot, uploadRoot string) { 35 ctx, cancel := context.WithCancel(context.Background()) 36 defer cancel() 37 38 handler := createHandler(hub.New(localHost, &upload.Uploader{Root: uploadRoot}), downloadRoot, cancel) 39 40 if err := startServer(ctx, port, handler); err != nil { 41 log.Print(err) 42 } 43 } 44 45 func startServer(ctx context.Context, port int, handler http.Handler) error { 46 server := &http.Server{ 47 Addr: fmt.Sprintf(":%d", port), 48 Handler: handler, 49 } 50 51 errChan := make(chan error) 52 53 go func() { 54 log.Printf("Listening on %s", server.Addr) 55 errChan <- server.ListenAndServe() 56 close(errChan) 57 }() 58 59 select { 60 case <-ctx.Done(): 61 shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 62 defer cancel() 63 return server.Shutdown(shutdownCtx) 64 case err := <-errChan: 65 return err 66 } 67 } 68 69 func createHandler(hub http.Handler, downloadRoot string, shutdown func()) http.Handler { 70 handler := http.NewServeMux() 71 72 shutdownFunc := func(w http.ResponseWriter, _ *http.Request) { 73 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 74 httphelper.SetDefaultResponseHeaders(w.Header()) 75 w.WriteHeader(http.StatusOK) 76 77 w.Write([]byte("shutting down")) 78 shutdown() 79 } 80 81 handler.HandleFunc("/quitquitquit", shutdownFunc) 82 83 handler.HandleFunc("/shutdown", shutdownFunc) 84 85 handler.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { 86 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 87 httphelper.SetDefaultResponseHeaders(w.Header()) 88 w.WriteHeader(http.StatusOK) 89 w.Write([]byte("ok")) 90 }) 91 92 handler.Handle("/session", hub) 93 handler.Handle("/session/", hub) 94 95 handler.HandleFunc("/status", func(w http.ResponseWriter, _ *http.Request) { 96 w.Header().Set("Content-Type", "application/json; charset=utf-8") 97 httphelper.SetDefaultResponseHeaders(w.Header()) 98 w.WriteHeader(http.StatusOK) 99 100 respJSON := map[string]interface{}{ 101 "status": 0, 102 "value": map[string]interface{}{ 103 "build": map[string]interface{}{ 104 "version": "unknown", 105 "revision": "unknown", 106 "time": "unknown", 107 }, 108 "os": map[string]interface{}{ 109 "arch": runtime.GOARCH, 110 "name": runtime.GOOS, 111 "version": "unknown", 112 }, 113 "ready": true, 114 "message": "ready to create new sessions", 115 }, 116 } 117 118 json.NewEncoder(w).Encode(respJSON) 119 }) 120 121 handler.Handle("/google/staticfile/", http.StripPrefix("/google/staticfile/", http.FileServer(http.Dir(downloadRoot)))) 122 123 return handler 124 }