// Copyright 2016 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. package main import ( "fmt" "html/template" "net" "net/http" "sort" "strings" "github.com/google/syzkaller/pkg/log" ) func (hub *Hub) initHTTP(addr string) { http.HandleFunc("/", hub.httpSummary) ln, err := net.Listen("tcp4", addr) if err != nil { log.Fatalf("failed to listen on %v: %v", addr, err) } log.Logf(0, "serving http on http://%v", ln.Addr()) go func() { err := http.Serve(ln, nil) log.Fatalf("failed to serve http: %v", err) }() } func (hub *Hub) httpSummary(w http.ResponseWriter, r *http.Request) { hub.mu.Lock() defer hub.mu.Unlock() data := &UISummaryData{ Log: log.CachedLogOutput(), } total := UIManager{ Name: "total", Corpus: len(hub.st.Corpus.Records), Repros: len(hub.st.Repros.Records), } for name, mgr := range hub.st.Managers { total.Added += mgr.Added total.Deleted += mgr.Deleted total.New += mgr.New total.SentRepros += mgr.SentRepros total.RecvRepros += mgr.RecvRepros data.Managers = append(data.Managers, UIManager{ Name: name, Corpus: len(mgr.Corpus.Records), Added: mgr.Added, Deleted: mgr.Deleted, New: mgr.New, SentRepros: mgr.SentRepros, RecvRepros: mgr.RecvRepros, }) } sort.Sort(UIManagerArray(data.Managers)) data.Managers = append([]UIManager{total}, data.Managers...) if err := summaryTemplate.Execute(w, data); err != nil { log.Logf(0, "failed to execute template: %v", err) http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError) return } } func compileTemplate(html string) *template.Template { return template.Must(template.New("").Parse(strings.Replace(html, "{{STYLE}}", htmlStyle, -1))) } type UISummaryData struct { Managers []UIManager Log string } type UIManager struct { Name string Corpus int Added int Deleted int New int Repros int SentRepros int RecvRepros int } type UIManagerArray []UIManager func (a UIManagerArray) Len() int { return len(a) } func (a UIManagerArray) Less(i, j int) bool { return a[i].Name < a[j].Name } func (a UIManagerArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } var summaryTemplate = compileTemplate(` <!doctype html> <html> <head> <title>syz-hub</title> {{STYLE}} </head> <body> <b>syz-hub</b> <br><br> <table> <caption>Managers:</caption> <tr> <th>Name</th> <th>Corpus</th> <th>Added</th> <th>Deleted</th> <th>New</th> <th>Repros</th> <th>Sent</th> <th>Recv</th> </tr> {{range $m := $.Managers}} <tr> <td>{{$m.Name}}</td> <td>{{$m.Corpus}}</td> <td>{{$m.Added}}</td> <td>{{$m.Deleted}}</td> <td>{{$m.New}}</td> <td>{{$m.Repros}}</td> <td>{{$m.SentRepros}}</td> <td>{{$m.RecvRepros}}</td> </tr> {{end}} </table> <br><br> Log: <br> <textarea id="log_textarea" readonly rows="50"> {{.Log}} </textarea> <script> var textarea = document.getElementById("log_textarea"); textarea.scrollTop = textarea.scrollHeight; </script> </body></html> `) const htmlStyle = ` <style type="text/css" media="screen"> table { border-collapse:collapse; border:1px solid; } table caption { font-weight: bold; } table td { border:1px solid; padding: 3px; } table th { border:1px solid; padding: 3px; } textarea { width:100%; } </style> `