// ExportDebugHandlers exports a few debugging handlers to an HTTP ServeMux. func (d *Env) ExportDebugHandlers(mux *http.ServeMux) { mux.HandleFunc("/debug/config", func(w http.ResponseWriter, r *http.Request) { w = httputil.Log(w, r, false) defer log.Print(w) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(d.conf) }) for _, thread := range d.threads { thread.ExportDebugHandlers(mux) } }
// Serve starts up an HTTP server using http.DefaultServerMux to handle // requests. This server will server over TLS, using the certs // stored in c.CertPath to verify itself to clients and verify clients. func (e *Env) Serve() error { caCert, caKey, clientCert, clientKey, serverCert, serverKey := filepath.Join(e.conf.CertPath, caCertFilename), filepath.Join(e.conf.CertPath, caKeyFilename), filepath.Join(e.conf.CertPath, clientCertFilename), filepath.Join(e.conf.CertPath, clientKeyFilename), filepath.Join(e.conf.CertPath, serverCertFilename), filepath.Join(e.conf.CertPath, serverKeyFilename) if err := certs.WriteNewCerts(caCert, caKey, "", CA); err != nil { return fmt.Errorf("cannot write ca certs: %v", err) } if err := certs.WriteNewCerts(clientCert, clientKey, caKey, Client); err != nil { return fmt.Errorf("cannot write client certs: %v", err) } if err := certs.WriteNewCerts(serverCert, serverKey, caKey, Server); err != nil { return fmt.Errorf("cannot write server certs: %v", err) } tlsConfig, err := certs.ClientVerifyingTLSConfig(caCert) if err != nil { return fmt.Errorf("cannot verify client cert: %v", err) } server := &http.Server{ Addr: fmt.Sprintf("%s:%d", e.conf.Host, e.conf.Port), TLSConfig: tlsConfig, } http.HandleFunc("/query", func(w http.ResponseWriter, r *http.Request) { w = httputil.Log(w, r, true) defer log.Print(w) queryBytes, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, "could not read request body", http.StatusBadRequest) return } q, err := query.NewQuery(string(queryBytes)) if err != nil { http.Error(w, "could not parse query", http.StatusBadRequest) return } ctx, cancel := httputil.Context(w, r, time.Minute*15) defer cancel() packets := e.Lookup(ctx, q) w.Header().Set("Content-Type", "appliation/octet-stream") base.PacketsToFile(packets, w) }) http.Handle("/debug/stats", stats.S) return server.ListenAndServeTLS(serverCert, serverKey) }
// ExportDebugHandlers exports a set of HTTP handlers on /debug/t<thread id> for // querying internal state from this thread. func (t *Thread) ExportDebugHandlers(mux *http.ServeMux) { prefix := fmt.Sprintf("/debug/t%d", t.id) mux.HandleFunc(prefix+"/files", func(w http.ResponseWriter, r *http.Request) { w = httputil.Log(w, r, false) defer log.Print(w) w.Header().Set("Content-Type", "text/plain") fmt.Fprintf(w, "Thread %d (IDX: %q, PKT: %q)\n", t.id, t.indexPath, t.packetPath) t.mu.RLock() for name := range t.files { fmt.Fprintf(w, "\t%v\n", name) } t.mu.RUnlock() }) mux.HandleFunc(prefix+"/index", func(w http.ResponseWriter, r *http.Request) { w = httputil.Log(w, r, false) defer log.Print(w) t.mu.RLock() defer t.mu.RUnlock() vals := r.URL.Query() file := t.files[vals.Get("name")] if file == nil { http.Error(w, "file not found", http.StatusNotFound) return } var start, finish []byte var err error if s := vals.Get("start"); s != "" { start, err = hex.DecodeString(s) if err != nil { http.Error(w, "bad start", http.StatusBadRequest) return } } if f := vals.Get("finish"); f != "" { finish, err = hex.DecodeString(f) if err != nil { http.Error(w, "bad finish", http.StatusBadRequest) return } } w.Header().Set("Content-Type", "text/plain") file.DumpIndex(w, start, finish) }) mux.HandleFunc(prefix+"/packets", func(w http.ResponseWriter, r *http.Request) { w = httputil.Log(w, r, false) defer log.Print(w) t.mu.RLock() defer t.mu.RUnlock() vals := r.URL.Query() file := t.files[vals.Get("name")] if file == nil { http.Error(w, "file not found", http.StatusNotFound) return } w.Header().Set("Content-Type", "application/octet-stream") base.PacketsToFile(file.AllPackets(), w) }) mux.HandleFunc(prefix+"/positions", func(w http.ResponseWriter, r *http.Request) { w = httputil.Log(w, r, true) defer log.Print(w) t.mu.RLock() defer t.mu.RUnlock() vals := r.URL.Query() file := t.files[vals.Get("name")] if file == nil { http.Error(w, "file not found", http.StatusNotFound) return } queryBytes, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, "could not read request body", http.StatusBadRequest) return } queryStr := string(queryBytes) q, err := query.NewQuery(queryStr) if err != nil { http.Error(w, "could not parse query", http.StatusBadRequest) return } w.Header().Set("Content-Type", "text/plain") positions, err := file.Positions(context.Background(), q) if err != nil { fmt.Fprintf(w, "ERROR: %v", err) return } fmt.Fprintf(w, "POSITIONS:\n") if positions.IsAllPositions() { fmt.Fprintf(w, "\tALL") } else { var buf [4]byte for _, pos := range positions { binary.BigEndian.PutUint32(buf[:], uint32(pos)) fmt.Fprintf(w, "\t%v\n", hex.EncodeToString(buf[:])) } } }) }