Home | History | Annotate | Download | only in syz-hub
      1 // Copyright 2016 syzkaller project authors. All rights reserved.
      2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
      3 
      4 package main
      5 
      6 import (
      7 	"fmt"
      8 	"html/template"
      9 	"net"
     10 	"net/http"
     11 	"sort"
     12 	"strings"
     13 
     14 	"github.com/google/syzkaller/pkg/log"
     15 )
     16 
     17 func (hub *Hub) initHTTP(addr string) {
     18 	http.HandleFunc("/", hub.httpSummary)
     19 
     20 	ln, err := net.Listen("tcp4", addr)
     21 	if err != nil {
     22 		log.Fatalf("failed to listen on %v: %v", addr, err)
     23 	}
     24 	log.Logf(0, "serving http on http://%v", ln.Addr())
     25 	go func() {
     26 		err := http.Serve(ln, nil)
     27 		log.Fatalf("failed to serve http: %v", err)
     28 	}()
     29 }
     30 
     31 func (hub *Hub) httpSummary(w http.ResponseWriter, r *http.Request) {
     32 	hub.mu.Lock()
     33 	defer hub.mu.Unlock()
     34 
     35 	data := &UISummaryData{
     36 		Log: log.CachedLogOutput(),
     37 	}
     38 	total := UIManager{
     39 		Name:   "total",
     40 		Corpus: len(hub.st.Corpus.Records),
     41 		Repros: len(hub.st.Repros.Records),
     42 	}
     43 	for name, mgr := range hub.st.Managers {
     44 		total.Added += mgr.Added
     45 		total.Deleted += mgr.Deleted
     46 		total.New += mgr.New
     47 		total.SentRepros += mgr.SentRepros
     48 		total.RecvRepros += mgr.RecvRepros
     49 		data.Managers = append(data.Managers, UIManager{
     50 			Name:       name,
     51 			Corpus:     len(mgr.Corpus.Records),
     52 			Added:      mgr.Added,
     53 			Deleted:    mgr.Deleted,
     54 			New:        mgr.New,
     55 			SentRepros: mgr.SentRepros,
     56 			RecvRepros: mgr.RecvRepros,
     57 		})
     58 	}
     59 	sort.Sort(UIManagerArray(data.Managers))
     60 	data.Managers = append([]UIManager{total}, data.Managers...)
     61 	if err := summaryTemplate.Execute(w, data); err != nil {
     62 		log.Logf(0, "failed to execute template: %v", err)
     63 		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
     64 		return
     65 	}
     66 }
     67 
     68 func compileTemplate(html string) *template.Template {
     69 	return template.Must(template.New("").Parse(strings.Replace(html, "{{STYLE}}", htmlStyle, -1)))
     70 }
     71 
     72 type UISummaryData struct {
     73 	Managers []UIManager
     74 	Log      string
     75 }
     76 
     77 type UIManager struct {
     78 	Name       string
     79 	Corpus     int
     80 	Added      int
     81 	Deleted    int
     82 	New        int
     83 	Repros     int
     84 	SentRepros int
     85 	RecvRepros int
     86 }
     87 
     88 type UIManagerArray []UIManager
     89 
     90 func (a UIManagerArray) Len() int           { return len(a) }
     91 func (a UIManagerArray) Less(i, j int) bool { return a[i].Name < a[j].Name }
     92 func (a UIManagerArray) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
     93 
     94 var summaryTemplate = compileTemplate(`
     95 <!doctype html>
     96 <html>
     97 <head>
     98 	<title>syz-hub</title>
     99 	{{STYLE}}
    100 </head>
    101 <body>
    102 <b>syz-hub</b>
    103 <br><br>
    104 
    105 <table>
    106 	<caption>Managers:</caption>
    107 	<tr>
    108 		<th>Name</th>
    109 		<th>Corpus</th>
    110 		<th>Added</th>
    111 		<th>Deleted</th>
    112 		<th>New</th>
    113 		<th>Repros</th>
    114 		<th>Sent</th>
    115 		<th>Recv</th>
    116 	</tr>
    117 	{{range $m := $.Managers}}
    118 	<tr>
    119 		<td>{{$m.Name}}</td>
    120 		<td>{{$m.Corpus}}</td>
    121 		<td>{{$m.Added}}</td>
    122 		<td>{{$m.Deleted}}</td>
    123 		<td>{{$m.New}}</td>
    124 		<td>{{$m.Repros}}</td>
    125 		<td>{{$m.SentRepros}}</td>
    126 		<td>{{$m.RecvRepros}}</td>
    127 	</tr>
    128 	{{end}}
    129 </table>
    130 <br><br>
    131 
    132 Log:
    133 <br>
    134 <textarea id="log_textarea" readonly rows="50">
    135 {{.Log}}
    136 </textarea>
    137 <script>
    138 	var textarea = document.getElementById("log_textarea");
    139 	textarea.scrollTop = textarea.scrollHeight;
    140 </script>
    141 
    142 </body></html>
    143 `)
    144 
    145 const htmlStyle = `
    146 	<style type="text/css" media="screen">
    147 		table {
    148 			border-collapse:collapse;
    149 			border:1px solid;
    150 		}
    151 		table caption {
    152 			font-weight: bold;
    153 		}
    154 		table td {
    155 			border:1px solid;
    156 			padding: 3px;
    157 		}
    158 		table th {
    159 			border:1px solid;
    160 			padding: 3px;
    161 		}
    162 		textarea {
    163 			width:100%;
    164 		}
    165 	</style>
    166 `
    167