github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/syz-hub/http.go (about)

     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  			Domain:     mgr.Domain,
    52  			Corpus:     len(mgr.Corpus.Records),
    53  			Added:      mgr.Added,
    54  			Deleted:    mgr.Deleted,
    55  			New:        mgr.New,
    56  			SentRepros: mgr.SentRepros,
    57  			RecvRepros: mgr.RecvRepros,
    58  		})
    59  	}
    60  	sort.Slice(data.Managers, func(i, j int) bool {
    61  		return data.Managers[i].Name < data.Managers[j].Name
    62  	})
    63  	data.Managers = append([]UIManager{total}, data.Managers...)
    64  	if err := summaryTemplate.Execute(w, data); err != nil {
    65  		log.Logf(0, "failed to execute template: %v", err)
    66  		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
    67  		return
    68  	}
    69  }
    70  
    71  func compileTemplate(html string) *template.Template {
    72  	return template.Must(template.New("").Parse(strings.Replace(html, "{{STYLE}}", htmlStyle, -1)))
    73  }
    74  
    75  type UISummaryData struct {
    76  	Managers []UIManager
    77  	Log      string
    78  }
    79  
    80  type UIManager struct {
    81  	Name       string
    82  	Domain     string
    83  	Corpus     int
    84  	Added      int
    85  	Deleted    int
    86  	New        int
    87  	Repros     int
    88  	SentRepros int
    89  	RecvRepros int
    90  }
    91  
    92  var summaryTemplate = compileTemplate(`
    93  <!doctype html>
    94  <html>
    95  <head>
    96  	<title>syz-hub</title>
    97  	{{STYLE}}
    98  </head>
    99  <body>
   100  <b>syz-hub</b>
   101  <br><br>
   102  
   103  <table>
   104  	<caption>Managers:</caption>
   105  	<tr>
   106  		<th>Name</th>
   107  		<th>Domain</th>
   108  		<th>Corpus</th>
   109  		<th>Added</th>
   110  		<th>Deleted</th>
   111  		<th>New</th>
   112  		<th>Repros</th>
   113  		<th>Sent</th>
   114  		<th>Recv</th>
   115  	</tr>
   116  	{{range $m := $.Managers}}
   117  	<tr>
   118  		<td>{{$m.Name}}</td>
   119  		<td>{{$m.Domain}}</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  `