2016-11-17 17:38:10 +00:00
|
|
|
// 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"
|
|
|
|
|
2018-05-03 12:41:34 +00:00
|
|
|
"github.com/google/syzkaller/pkg/log"
|
2016-11-17 17:38:10 +00:00
|
|
|
)
|
|
|
|
|
2018-03-08 17:48:26 +00:00
|
|
|
func (hub *Hub) initHTTP(addr string) {
|
2016-11-17 17:38:10 +00:00
|
|
|
http.HandleFunc("/", hub.httpSummary)
|
|
|
|
|
|
|
|
ln, err := net.Listen("tcp4", addr)
|
|
|
|
if err != nil {
|
2018-05-03 12:41:34 +00:00
|
|
|
log.Fatalf("failed to listen on %v: %v", addr, err)
|
2016-11-17 17:38:10 +00:00
|
|
|
}
|
2018-05-03 12:41:34 +00:00
|
|
|
log.Logf(0, "serving http on http://%v", ln.Addr())
|
2016-11-17 17:38:10 +00:00
|
|
|
go func() {
|
|
|
|
err := http.Serve(ln, nil)
|
2018-05-03 12:41:34 +00:00
|
|
|
log.Fatalf("failed to serve http: %v", err)
|
2016-11-17 17:38:10 +00:00
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hub *Hub) httpSummary(w http.ResponseWriter, r *http.Request) {
|
|
|
|
hub.mu.Lock()
|
|
|
|
defer hub.mu.Unlock()
|
|
|
|
|
|
|
|
data := &UISummaryData{
|
2018-05-03 12:41:34 +00:00
|
|
|
Log: log.CachedLogOutput(),
|
2016-11-17 17:38:10 +00:00
|
|
|
}
|
|
|
|
total := UIManager{
|
|
|
|
Name: "total",
|
2017-01-16 19:44:56 +00:00
|
|
|
Corpus: len(hub.st.Corpus.Records),
|
2017-08-06 14:47:16 +00:00
|
|
|
Repros: len(hub.st.Repros.Records),
|
2016-11-17 17:38:10 +00:00
|
|
|
}
|
|
|
|
for name, mgr := range hub.st.Managers {
|
|
|
|
total.Added += mgr.Added
|
2017-06-14 12:59:45 +00:00
|
|
|
total.Deleted += mgr.Deleted
|
2016-11-17 17:38:10 +00:00
|
|
|
total.New += mgr.New
|
2017-08-06 14:47:16 +00:00
|
|
|
total.SentRepros += mgr.SentRepros
|
|
|
|
total.RecvRepros += mgr.RecvRepros
|
2016-11-17 17:38:10 +00:00
|
|
|
data.Managers = append(data.Managers, UIManager{
|
2017-08-06 14:47:16 +00:00
|
|
|
Name: name,
|
|
|
|
Corpus: len(mgr.Corpus.Records),
|
|
|
|
Added: mgr.Added,
|
|
|
|
Deleted: mgr.Deleted,
|
|
|
|
New: mgr.New,
|
|
|
|
SentRepros: mgr.SentRepros,
|
|
|
|
RecvRepros: mgr.RecvRepros,
|
2016-11-17 17:38:10 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
sort.Sort(UIManagerArray(data.Managers))
|
|
|
|
data.Managers = append([]UIManager{total}, data.Managers...)
|
|
|
|
if err := summaryTemplate.Execute(w, data); err != nil {
|
2018-05-03 12:41:34 +00:00
|
|
|
log.Logf(0, "failed to execute template: %v", err)
|
2016-11-17 17:38:10 +00:00
|
|
|
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 {
|
2017-08-06 14:47:16 +00:00
|
|
|
Name string
|
|
|
|
Corpus int
|
|
|
|
Added int
|
|
|
|
Deleted int
|
|
|
|
New int
|
|
|
|
Repros int
|
|
|
|
SentRepros int
|
|
|
|
RecvRepros int
|
2016-11-17 17:38:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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>
|
2017-08-06 14:47:16 +00:00
|
|
|
<th>Repros</th>
|
|
|
|
<th>Sent</th>
|
|
|
|
<th>Recv</th>
|
2016-11-17 17:38:10 +00:00
|
|
|
</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>
|
2017-08-06 14:47:16 +00:00
|
|
|
<td>{{$m.Repros}}</td>
|
|
|
|
<td>{{$m.SentRepros}}</td>
|
|
|
|
<td>{{$m.RecvRepros}}</td>
|
2016-11-17 17:38:10 +00:00
|
|
|
</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>
|
|
|
|
`
|