From 36c4174018976ca73fb70c5be2f16692f4ba5cd5 Mon Sep 17 00:00:00 2001
From: Jehiah Czebotar <jehiah@gmail.com>
Date: Fri, 31 Jul 2015 15:15:43 -0400
Subject: [PATCH 1/2] nsqadmin: properly write responses

---
 internal/http_api/api_response.go | 16 +++++++++---
 nsqadmin/http.go                  | 43 +++++++++++++++----------------
 2 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/internal/http_api/api_response.go b/internal/http_api/api_response.go
index 664db786a..b95a16623 100644
--- a/internal/http_api/api_response.go
+++ b/internal/http_api/api_response.go
@@ -41,10 +41,18 @@ func PlainText(f APIHandler) APIHandler {
 			code = err.(Err).Code
 			data = err.Error()
 		}
-		response := data.(string)
-		w.Header().Set("Content-Length", strconv.Itoa(len(response)))
-		w.WriteHeader(code)
-		io.WriteString(w, response)
+		switch d := data.(type) {
+		case string:
+			w.Header().Set("Content-Length", strconv.Itoa(len(d)))
+			w.WriteHeader(code)
+			io.WriteString(w, d)
+		case []byte:
+			w.Header().Set("Content-Length", strconv.Itoa(len(d)))
+			w.WriteHeader(code)
+			w.Write(d)
+		default:
+			panic(fmt.Sprintf("unknown response type %T", data))
+		}
 		return nil, nil
 	}
 }
diff --git a/nsqadmin/http.go b/nsqadmin/http.go
index d2f365d5f..099c86d32 100644
--- a/nsqadmin/http.go
+++ b/nsqadmin/http.go
@@ -89,27 +89,27 @@ func NewHTTPServer(ctx *Context) *httpServer {
 
 	router.Handle("GET", "/ping", http_api.Decorate(s.pingHandler, log, http_api.PlainText))
 
-	router.Handle("GET", "/", http_api.Decorate(s.indexHandler, log))
-	router.Handle("GET", "/nodes", http_api.Decorate(s.nodesHandler, log))
-	router.Handle("GET", "/node/:node", http_api.Decorate(s.nodeHandler, log))
-	router.Handle("GET", "/topic/:topic", http_api.Decorate(s.topicHandler, log))
-	router.Handle("GET", "/topic/:topic/:channel", http_api.Decorate(s.channelHandler, log))
-	router.Handle("GET", "/static/:asset", http_api.Decorate(s.embeddedAssetHandler, log))
-	router.Handle("GET", "/counter", http_api.Decorate(s.counterHandler, log))
-	router.Handle("GET", "/counter/data", http_api.Decorate(s.counterDataHandler, log))
-	router.Handle("GET", "/lookup", http_api.Decorate(s.lookupHandler, log))
-	router.Handle("GET", "/graphite_data", http_api.Decorate(s.graphiteDataHandler, log))
-
-	router.Handle("POST", "/tombstone_topic_producer", http_api.Decorate(s.tombstoneTopicProducerHandler, log))
-	router.Handle("POST", "/empty_topic", http_api.Decorate(s.emptyTopicHandler, log))
-	router.Handle("POST", "/delete_topic", http_api.Decorate(s.deleteTopicHandler, log))
-	router.Handle("POST", "/pause_topic", http_api.Decorate(s.pauseTopicHandler, log))
-	router.Handle("POST", "/unpause_topic", http_api.Decorate(s.pauseTopicHandler, log))
-	router.Handle("POST", "/empty_channel", http_api.Decorate(s.emptyChannelHandler, log))
-	router.Handle("POST", "/delete_channel", http_api.Decorate(s.deleteChannelHandler, log))
-	router.Handle("POST", "/pause_channel", http_api.Decorate(s.pauseChannelHandler, log))
-	router.Handle("POST", "/unpause_channel", http_api.Decorate(s.pauseChannelHandler, log))
-	router.Handle("POST", "/create_topic_channel", http_api.Decorate(s.createTopicChannelHandler, log))
+	router.Handle("GET", "/", http_api.Decorate(s.indexHandler, log, http_api.PlainText))
+	router.Handle("GET", "/nodes", http_api.Decorate(s.nodesHandler, log, http_api.PlainText))
+	router.Handle("GET", "/node/:node", http_api.Decorate(s.nodeHandler, log, http_api.PlainText))
+	router.Handle("GET", "/topic/:topic", http_api.Decorate(s.topicHandler, log, http_api.PlainText))
+	router.Handle("GET", "/topic/:topic/:channel", http_api.Decorate(s.channelHandler, log, http_api.PlainText))
+	router.Handle("GET", "/static/:asset", http_api.Decorate(s.embeddedAssetHandler, log, http_api.PlainText))
+	router.Handle("GET", "/counter", http_api.Decorate(s.counterHandler, log, http_api.PlainText))
+	router.Handle("GET", "/counter/data", http_api.Decorate(s.counterDataHandler, log, http_api.PlainText))
+	router.Handle("GET", "/lookup", http_api.Decorate(s.lookupHandler, log, http_api.PlainText))
+	router.Handle("GET", "/graphite_data", http_api.Decorate(s.graphiteDataHandler, log, http_api.PlainText))
+
+	router.Handle("POST", "/tombstone_topic_producer", http_api.Decorate(s.tombstoneTopicProducerHandler, log, http_api.PlainText))
+	router.Handle("POST", "/empty_topic", http_api.Decorate(s.emptyTopicHandler, log, http_api.PlainText))
+	router.Handle("POST", "/delete_topic", http_api.Decorate(s.deleteTopicHandler, log, http_api.PlainText))
+	router.Handle("POST", "/pause_topic", http_api.Decorate(s.pauseTopicHandler, log, http_api.PlainText))
+	router.Handle("POST", "/unpause_topic", http_api.Decorate(s.pauseTopicHandler, log, http_api.PlainText))
+	router.Handle("POST", "/empty_channel", http_api.Decorate(s.emptyChannelHandler, log, http_api.PlainText))
+	router.Handle("POST", "/delete_channel", http_api.Decorate(s.deleteChannelHandler, log, http_api.PlainText))
+	router.Handle("POST", "/pause_channel", http_api.Decorate(s.pauseChannelHandler, log, http_api.PlainText))
+	router.Handle("POST", "/unpause_channel", http_api.Decorate(s.pauseChannelHandler, log, http_api.PlainText))
+	router.Handle("POST", "/create_topic_channel", http_api.Decorate(s.createTopicChannelHandler, log, http_api.PlainText))
 
 	if s.ctx.nsqadmin.opts.ProxyGraphite {
 		router.Handler("GET", "/render", s.proxy)
@@ -139,7 +139,6 @@ func (s *httpServer) embeddedAssetHandler(w http.ResponseWriter, req *http.Reque
 	} else if strings.HasSuffix(assetName, ".css") {
 		w.Header().Set("Content-Type", "text/css")
 	}
-
 	return asset, nil
 }
 

From e188f4039440ba93b23827bd37e1ff2aed33182f Mon Sep 17 00:00:00 2001
From: Jehiah Czebotar <jehiah@gmail.com>
Date: Fri, 31 Jul 2015 15:29:18 -0400
Subject: [PATCH 2/2] nsqadmin: wildcard subdirectories for /static/*

---
 nsqadmin/http.go | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/nsqadmin/http.go b/nsqadmin/http.go
index 099c86d32..8140b7554 100644
--- a/nsqadmin/http.go
+++ b/nsqadmin/http.go
@@ -94,7 +94,7 @@ func NewHTTPServer(ctx *Context) *httpServer {
 	router.Handle("GET", "/node/:node", http_api.Decorate(s.nodeHandler, log, http_api.PlainText))
 	router.Handle("GET", "/topic/:topic", http_api.Decorate(s.topicHandler, log, http_api.PlainText))
 	router.Handle("GET", "/topic/:topic/:channel", http_api.Decorate(s.channelHandler, log, http_api.PlainText))
-	router.Handle("GET", "/static/:asset", http_api.Decorate(s.embeddedAssetHandler, log, http_api.PlainText))
+	router.Handle("GET", "/static/*asset", http_api.Decorate(s.embeddedAssetHandler, log, http_api.PlainText))
 	router.Handle("GET", "/counter", http_api.Decorate(s.counterHandler, log, http_api.PlainText))
 	router.Handle("GET", "/counter/data", http_api.Decorate(s.counterDataHandler, log, http_api.PlainText))
 	router.Handle("GET", "/lookup", http_api.Decorate(s.lookupHandler, log, http_api.PlainText))
@@ -128,6 +128,9 @@ func (s *httpServer) pingHandler(w http.ResponseWriter, req *http.Request, ps ht
 
 func (s *httpServer) embeddedAssetHandler(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
 	assetName := ps.ByName("asset")
+	if strings.HasPrefix(assetName, "/") {
+		assetName = assetName[1:]
+	}
 
 	asset, error := templates.Asset(assetName)
 	if error != nil {