github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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  			HTTP:       mgr.HTTP,
    52  			Domain:     mgr.Domain,
    53  			Corpus:     len(mgr.Corpus.Records),
    54  			Added:      mgr.Added,
    55  			Deleted:    mgr.Deleted,
    56  			New:        mgr.New,
    57  			SentRepros: mgr.SentRepros,
    58  			RecvRepros: mgr.RecvRepros,
    59  		})
    60  	}
    61  	sort.Slice(data.Managers, func(i, j int) bool {
    62  		return data.Managers[i].Name < data.Managers[j].Name
    63  	})
    64  	data.Managers = append([]UIManager{total}, data.Managers...)
    65  	if err := summaryTemplate.Execute(w, data); err != nil {
    66  		log.Logf(0, "failed to execute template: %v", err)
    67  		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
    68  		return
    69  	}
    70  }
    71  
    72  func compileTemplate(html string) *template.Template {
    73  	return template.Must(template.New("").Parse(strings.ReplaceAll(html, "{{STYLE}}", htmlStyle)))
    74  }
    75  
    76  type UISummaryData struct {
    77  	Managers []UIManager
    78  	Log      string
    79  }
    80  
    81  type UIManager struct {
    82  	Name       string
    83  	HTTP       string
    84  	Domain     string
    85  	Corpus     int
    86  	Added      int
    87  	Deleted    int
    88  	New        int
    89  	Repros     int
    90  	SentRepros int
    91  	RecvRepros int
    92  }
    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>URL</th>
   110  		<th>Domain</th>
   111  		<th>Corpus</th>
   112  		<th>Added</th>
   113  		<th>Deleted</th>
   114  		<th>New</th>
   115  		<th>Repros</th>
   116  		<th>Sent</th>
   117  		<th>Recv</th>
   118  	</tr>
   119  	{{range $m := $.Managers}}
   120  	<tr>
   121  		<td>{{$m.Name}}</td>
   122  		<td><a href="{{$m.HTTP}}">{{$m.HTTP}}</a></td>
   123  		<td>{{$m.Domain}}</td>
   124  		<td>{{$m.Corpus}}</td>
   125  		<td>{{$m.Added}}</td>
   126  		<td>{{$m.Deleted}}</td>
   127  		<td>{{$m.New}}</td>
   128  		<td>{{$m.Repros}}</td>
   129  		<td>{{$m.SentRepros}}</td>
   130  		<td>{{$m.RecvRepros}}</td>
   131  	</tr>
   132  	{{end}}
   133  </table>
   134  <br><br>
   135  
   136  Log:
   137  <br>
   138  <textarea id="log_textarea" readonly rows="50">
   139  {{.Log}}
   140  </textarea>
   141  <script>
   142  	var textarea = document.getElementById("log_textarea");
   143  	textarea.scrollTop = textarea.scrollHeight;
   144  </script>
   145  
   146  </body></html>
   147  `)
   148  
   149  const htmlStyle = `
   150  	<style type="text/css" media="screen">
   151  		table {
   152  			border-collapse:collapse;
   153  			border:1px solid;
   154  		}
   155  		table caption {
   156  			font-weight: bold;
   157  		}
   158  		table td {
   159  			border:1px solid;
   160  			padding: 3px;
   161  		}
   162  		table th {
   163  			border:1px solid;
   164  			padding: 3px;
   165  		}
   166  		textarea {
   167  			width:100%;
   168  		}
   169  	</style>
   170  `