| OLD | NEW |
| 1 package main | 1 package main |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "encoding/json" |
| 4 "flag" | 5 "flag" |
| 6 "fmt" |
| 5 htemplate "html/template" | 7 htemplate "html/template" |
| 6 "math/rand" | 8 "math/rand" |
| 7 "net/http" | 9 "net/http" |
| 8 "os" | 10 "os" |
| 9 "path/filepath" | 11 "path/filepath" |
| 10 "runtime" | 12 "runtime" |
| 11 "time" | 13 "time" |
| 12 | 14 |
| 13 » "github.com/BurntSushi/toml" | 15 » "code.google.com/p/google-api-go-client/storage/v1" |
| 14 » "github.com/fiorix/go-web/autogzip" | 16 » "github.com/gorilla/mux" |
| 15 metrics "github.com/rcrowley/go-metrics" | 17 metrics "github.com/rcrowley/go-metrics" |
| 16 "github.com/skia-dev/glog" | 18 "github.com/skia-dev/glog" |
| 17 "go.skia.org/infra/fuzzer/go/config" | 19 "go.skia.org/infra/fuzzer/go/config" |
| 20 "go.skia.org/infra/go/auth" |
| 18 "go.skia.org/infra/go/common" | 21 "go.skia.org/infra/go/common" |
| 22 "go.skia.org/infra/go/login" |
| 23 "go.skia.org/infra/go/metadata" |
| 24 "go.skia.org/infra/go/util" |
| 19 ) | 25 ) |
| 20 | 26 |
| 21 var ( | 27 var ( |
| 22 // indexTemplate is the main index.html page we serve. | 28 // indexTemplate is the main index.html page we serve. |
| 23 indexTemplate *htemplate.Template = nil | 29 indexTemplate *htemplate.Template = nil |
| 24 | 30 |
| 25 » requestsCounter = metrics.NewRegisteredCounter("requests", metrics.Defau
ltRegistry) | 31 » requestsCounter = metrics.NewRegisteredCounter("request
s", metrics.DefaultRegistry) |
| 32 » router *mux.Router = mux.NewRouter() |
| 33 » client *http.Client = nil |
| 34 » store *storage.Service = nil |
| 26 ) | 35 ) |
| 27 | 36 |
| 28 // Command line flags. | 37 // Command line flags. |
| 29 var ( | 38 var ( |
| 30 configFilename = flag.String("config", "fuzzer.toml", "Configuration fil
ename") | 39 configFilename = flag.String("config", "fuzzer.toml", "Configuration fil
ename") |
| 31 ) | 40 ) |
| 32 | 41 |
| 42 const ( |
| 43 // OAUTH2_CALLBACK_PATH is callback endpoint used for the Oauth2 flow. |
| 44 OAUTH2_CALLBACK_PATH = "/oauth2callback/" |
| 45 ) |
| 46 |
| 33 func Init() { | 47 func Init() { |
| 34 rand.Seed(time.Now().UnixNano()) | 48 rand.Seed(time.Now().UnixNano()) |
| 35 | 49 |
| 36 common.InitWithMetricsCB("fuzzer", func() string { | 50 common.InitWithMetricsCB("fuzzer", func() string { |
| 37 » » if _, err := toml.DecodeFile(*configFilename, &config.Config); e
rr != nil { | 51 » » common.DecodeTomlFile(*configFilename, &config.Config) |
| 38 » » » glog.Fatalf("Failed to decode config file: %s", err) | |
| 39 » » } | |
| 40 return config.Config.FrontEnd.GraphiteServer | 52 return config.Config.FrontEnd.GraphiteServer |
| 41 }) | 53 }) |
| 42 | 54 |
| 43 if config.Config.Common.ResourcePath == "" { | 55 if config.Config.Common.ResourcePath == "" { |
| 44 _, filename, _, _ := runtime.Caller(0) | 56 _, filename, _, _ := runtime.Caller(0) |
| 45 config.Config.Common.ResourcePath = filepath.Join(filepath.Dir(f
ilename), "../..") | 57 config.Config.Common.ResourcePath = filepath.Join(filepath.Dir(f
ilename), "../..") |
| 46 } | 58 } |
| 47 | 59 |
| 48 path, err := filepath.Abs(config.Config.Common.ResourcePath) | 60 path, err := filepath.Abs(config.Config.Common.ResourcePath) |
| 49 if err != nil { | 61 if err != nil { |
| 50 glog.Fatalf("Couldn't get absolute path to fuzzer resources: %s"
, err) | 62 glog.Fatalf("Couldn't get absolute path to fuzzer resources: %s"
, err) |
| 51 } | 63 } |
| 52 if err := os.Chdir(path); err != nil { | 64 if err := os.Chdir(path); err != nil { |
| 53 glog.Fatal(err) | 65 glog.Fatal(err) |
| 54 } | 66 } |
| 55 | 67 |
| 56 indexTemplate = htemplate.Must(htemplate.ParseFiles( | 68 indexTemplate = htemplate.Must(htemplate.ParseFiles( |
| 57 filepath.Join(path, "templates/index.html"), | 69 filepath.Join(path, "templates/index.html"), |
| 58 filepath.Join(path, "templates/header.html"), | 70 filepath.Join(path, "templates/header.html"), |
| 71 filepath.Join(path, "templates/titlebar.html"), |
| 59 filepath.Join(path, "templates/footer.html"), | 72 filepath.Join(path, "templates/footer.html"), |
| 60 )) | 73 )) |
| 61 | 74 |
| 75 if client, err = auth.NewClient(config.Config.Common.DoOAuth, config.Con
fig.Common.OAuthCacheFile, storage.DevstorageFull_controlScope); err != nil { |
| 76 glog.Fatalf("Failed to create authenticated HTTP client: %s", er
r) |
| 77 } |
| 78 |
| 79 if store, err = storage.New(client); err != nil { |
| 80 glog.Fatalf("Failed to create storage service client: %s", err) |
| 81 } |
| 62 } | 82 } |
| 63 | 83 |
| 64 // mainHandler handles the GET and POST of the main page. | 84 type IndexContext struct { |
| 85 » LoadFuzzListURL string |
| 86 } |
| 87 |
| 88 func getURL(router *mux.Router, name string, pairs ...string) string { |
| 89 » route := router.Get(name) |
| 90 » if route == nil { |
| 91 » » glog.Fatalf("Couldn't find any route named %s", name) |
| 92 » } |
| 93 |
| 94 » routeURL, err := route.URL(pairs...) |
| 95 » if err != nil { |
| 96 » » glog.Fatalf("Couldn't resolve route %s into a URL", routeURL) |
| 97 » } |
| 98 |
| 99 » return routeURL.String() |
| 100 } |
| 101 |
| 65 func mainHandler(w http.ResponseWriter, r *http.Request) { | 102 func mainHandler(w http.ResponseWriter, r *http.Request) { |
| 66 glog.Infof("Main Handler: %q\n", r.URL.Path) | 103 glog.Infof("Main Handler: %q\n", r.URL.Path) |
| 67 requestsCounter.Inc(1) | 104 requestsCounter.Inc(1) |
| 68 if r.Method == "GET" { | 105 if r.Method == "GET" { |
| 69 // Expand the template. | 106 // Expand the template. |
| 70 w.Header().Set("Content-Type", "text/html") | 107 w.Header().Set("Content-Type", "text/html") |
| 71 » » if err := indexTemplate.Execute(w, struct{}{}); err != nil { | 108 » » fuzzListURL := getURL(router, "fuzzListHandler") |
| 109 » » context := IndexContext{ |
| 110 » » » fuzzListURL, |
| 111 » » } |
| 112 » » if err := indexTemplate.Execute(w, context); err != nil { |
| 72 glog.Errorf("Failed to expand template: %q\n", err) | 113 glog.Errorf("Failed to expand template: %q\n", err) |
| 73 } | 114 } |
| 74 } | 115 } |
| 75 } | 116 } |
| 76 | 117 |
| 118 // makeResourceHandler creates a static file handler that sets a caching policy. |
| 119 func makeResourceHandler() func(http.ResponseWriter, *http.Request) { |
| 120 fileServer := http.FileServer(http.Dir(config.Config.Common.ResourcePath
)) |
| 121 return func(w http.ResponseWriter, r *http.Request) { |
| 122 w.Header().Add("Cache-Control", string(300)) |
| 123 fileServer.ServeHTTP(w, r) |
| 124 } |
| 125 } |
| 126 |
| 127 func getFuzzes(baseDir string) []string { |
| 128 results := []string{} |
| 129 glog.Infof("Opening bucket/directory: %s/%s", config.Config.Common.FuzzO
utputGSBucket, baseDir) |
| 130 |
| 131 req := store.Objects.List(config.Config.Common.FuzzOutputGSBucket).Prefi
x(baseDir + "/").Delimiter("/") |
| 132 for req != nil { |
| 133 resp, err := req.Do() |
| 134 if err != nil { |
| 135 return results |
| 136 } |
| 137 for _, result := range resp.Prefixes { |
| 138 results = append(results, result[len(baseDir)+1:len(resu
lt)-1]) |
| 139 } |
| 140 if len(resp.NextPageToken) > 0 { |
| 141 req.PageToken(resp.NextPageToken) |
| 142 } else { |
| 143 req = nil |
| 144 } |
| 145 } |
| 146 return results |
| 147 } |
| 148 |
| 149 func fuzzListHandler(w http.ResponseWriter, r *http.Request) { |
| 150 if err := r.ParseForm(); err != nil { |
| 151 util.ReportError(w, r, err, "Failed to parse form data.") |
| 152 return |
| 153 } |
| 154 |
| 155 w.Header().Set("Content-Type", "application/json") |
| 156 enc := json.NewEncoder(w) |
| 157 |
| 158 fuzzes := []string{} |
| 159 |
| 160 failed := r.FormValue("failed") |
| 161 passed := r.FormValue("passed") |
| 162 |
| 163 if failed == "true" { |
| 164 fuzzes = append(fuzzes, getFuzzes("failed")...) |
| 165 } |
| 166 if passed == "true" { |
| 167 fuzzes = append(fuzzes, getFuzzes("working")...) |
| 168 } |
| 169 |
| 170 if err := enc.Encode(fuzzes); err != nil { |
| 171 util.ReportError(w, r, err, "Failed to encode results") |
| 172 } |
| 173 } |
| 174 |
| 77 func main() { | 175 func main() { |
| 78 flag.Parse() | 176 flag.Parse() |
| 79 Init() | 177 Init() |
| 80 » // Resources are served directly | 178 |
| 81 » http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) | 179 » // Set up login |
| 82 » http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) | 180 » var cookieSalt = "notverysecret" |
| 181 » var clientID = "31977622648-ubjke2f3staq6ouas64r31h8f8tcbiqp.apps.google
usercontent.com" |
| 182 » var clientSecret = "rK-kRY71CXmcg0v9I9KIgWci" |
| 183 » var useRedirectURL = fmt.Sprintf("http://localhost%s/oauth2callback/", c
onfig.Config.FrontEnd.Port) |
| 184 » if !config.Config.Common.Local { |
| 185 » » cookieSalt = metadata.Must(metadata.ProjectGet(metadata.COOKIESA
LT)) |
| 186 » » clientID = metadata.Must(metadata.ProjectGet(metadata.CLIENT_ID)
) |
| 187 » » clientSecret = metadata.Must(metadata.ProjectGet(metadata.CLIENT
_SECRET)) |
| 188 » » useRedirectURL = config.Config.FrontEnd.RedirectURL |
| 189 » } |
| 190 |
| 191 » login.Init(clientID, clientSecret, useRedirectURL, cookieSalt, login.DEF
AULT_SCOPE, login.DEFAULT_DOMAIN_WHITELIST, config.Config.Common.Local) |
| 192 |
| 193 » // Set up the login related resources. |
| 194 » router.HandleFunc(OAUTH2_CALLBACK_PATH, login.OAuth2CallbackHandler) |
| 195 » router.HandleFunc("/loginstatus/", login.StatusHandler) |
| 196 » router.HandleFunc("/logout/", login.LogoutHandler) |
| 197 |
| 198 » router.HandleFunc("/", mainHandler) |
| 199 » router.HandleFunc("/failed", mainHandler) |
| 200 » router.HandleFunc("/passed", mainHandler) |
| 201 » router.PathPrefix("/res/").HandlerFunc(makeResourceHandler()) |
| 202 |
| 203 » jsonRouter := router.PathPrefix("/_").Subrouter() |
| 204 » jsonRouter.HandleFunc("/list", fuzzListHandler).Name("fuzzListHandler") |
| 205 |
| 206 » rootHandler := util.LoggingGzipRequestResponse(router) |
| 207 » if config.Config.FrontEnd.ForceLogin { |
| 208 » » rootHandler = login.ForceAuth(rootHandler, OAUTH2_CALLBACK_PATH) |
| 209 » } |
| 210 |
| 211 » http.Handle("/", rootHandler) |
| 212 |
| 83 glog.Fatal(http.ListenAndServe(config.Config.FrontEnd.Port, nil)) | 213 glog.Fatal(http.ListenAndServe(config.Config.FrontEnd.Port, nil)) |
| 84 } | 214 } |
| OLD | NEW |