summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBen Morrison <ben@gbmor.dev>2019-05-13 17:20:40 -0400
committerBen Morrison <ben@gbmor.dev>2019-05-13 17:22:28 -0400
commitd6fbc25111a9a76b40f19b2481428a9170c706b0 (patch)
treed071366939de7a6994c56153f81b16e836883043
parent9d31e04f8ec8c53c6f6e2323d7422b86b7a4ad90 (diff)
downloadgetwtxt-d6fbc25111a9a76b40f19b2481428a9170c706b0.tar.gz
serving css virtually instead of directly
-rw-r--r--assets/style.css1
-rw-r--r--handlers.go49
-rw-r--r--handlers_test.go26
-rw-r--r--main.go3
-rw-r--r--types.go5
5 files changed, 75 insertions, 9 deletions
diff --git a/assets/style.css b/assets/style.css
new file mode 100644
index 0000000..e148bda
--- /dev/null
+++ b/assets/style.css
@@ -0,0 +1 @@
+@import url("https://cdn.jsdelivr.net/gh/kognise/water.css@latest/dist/dark.min.css");
diff --git a/handlers.go b/handlers.go
index 01049b0..3b23761 100644
--- a/handlers.go
+++ b/handlers.go
@@ -3,8 +3,10 @@ package main
 import (
 	"crypto/sha256"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"net/http"
+	"os"
 	"time"
 
 	"github.com/gorilla/mux"
@@ -15,7 +17,7 @@ func indexHandler(w http.ResponseWriter, _ *http.Request) {
 	w.Header().Set("Content-Type", htmlutf8)
 	n, err := w.Write([]byte("getwtxt v" + getwtxt))
 	if err != nil || n == 0 {
-		log.Printf("Error writing to HTTP stream: %v\n", err)
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
 	}
 
 }
@@ -33,7 +35,7 @@ func apiBaseHandler(w http.ResponseWriter, r *http.Request) {
 	timerfc3339 = append(timerfc3339, pathdata...)
 	n, err := w.Write(timerfc3339)
 	if err != nil || n == 0 {
-		log.Printf("Error writing to HTTP stream: %v\n", err)
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
 	}
 }
 
@@ -46,7 +48,7 @@ func apiFormatHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", txtutf8)
 	n, err := w.Write([]byte(format + "\n"))
 	if err != nil || n == 0 {
-		log.Printf("Error writing to HTTP stream: %v\n", err)
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
 	}
 }
 
@@ -59,7 +61,7 @@ func apiEndpointHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", htmlutf8)
 	n, err := w.Write([]byte(format + "/" + endpoint))
 	if err != nil || n == 0 {
-		log.Printf("Error writing to HTTP stream: %v\n", err)
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
 	}
 
 }
@@ -73,7 +75,7 @@ func apiEndpointPOSTHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", htmlutf8)
 	n, err := w.Write([]byte(format + "/" + endpoint))
 	if err != nil || n == 0 {
-		log.Printf("Error writing to HTTP stream: %v\n", err)
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
 	}
 
 }
@@ -86,7 +88,7 @@ func apiTagsBaseHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", htmlutf8)
 	n, err := w.Write([]byte("api/" + format + "/tags"))
 	if err != nil || n == 0 {
-		log.Printf("Error writing to HTTP stream: %v\n", err)
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
 	}
 
 }
@@ -100,7 +102,40 @@ func apiTagsHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", htmlutf8)
 	n, err := w.Write([]byte("api/" + format + "/tags/" + tags))
 	if err != nil || n == 0 {
-		log.Printf("Error writing to HTTP stream: %v\n", err)
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
 	}
 
 }
+
+// Serving the stylesheet virtually because
+// files aren't served directly.
+func cssHandler(w http.ResponseWriter, _ *http.Request) {
+	// read the raw bytes of the stylesheet
+	css, err := ioutil.ReadFile("assets/style.css")
+	if err != nil {
+		if os.IsNotExist(err) {
+			log.Printf("CSS file does not exist: /css request 404\n")
+			http.Error(w, err.Error(), http.StatusNotFound)
+			return
+		}
+		log.Printf("%v\n", err)
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	// Get the mod time for the etag header
+	stat, err := os.Stat("assets/style.css")
+	if err != nil {
+		log.Printf("Couldn't stat CSS file to send ETag header: %v\n", err)
+	}
+
+	// Sending the sha256 sum of the modtime in hexadecimal for the ETag header
+	etag := fmt.Sprintf("%x", sha256.Sum256([]byte(stat.ModTime().String())))
+
+	w.Header().Set("ETag", "\""+etag+"\"")
+	w.Header().Set("Content-Type", cssutf8)
+	n, err := w.Write(css)
+	if err != nil || n == 0 {
+		log.Printf("Error writing to HTTP stream: %v bytes,  %v\n", n, err)
+	}
+}
diff --git a/handlers_test.go b/handlers_test.go
index 66c1566..4ae7ae6 100644
--- a/handlers_test.go
+++ b/handlers_test.go
@@ -1,7 +1,9 @@
 package main
 
 import (
+	"bytes"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"net/http"
 	"net/http/httptest"
@@ -98,3 +100,27 @@ func Test_apiTagsHandler(t *testing.T) {
 		}
 	})
 }
+func Test_cssHandler(t *testing.T) {
+	initTestConf()
+
+	name := "CSS Handler Test"
+	css, err := ioutil.ReadFile("assets/style.css")
+	if err != nil {
+		t.Errorf("Couldn't read assets/style.css: %v\n", err)
+	}
+
+	w := httptest.NewRecorder()
+	req := httptest.NewRequest("GET", "localhost"+testport+"/css", nil)
+
+	t.Run(name, func(t *testing.T) {
+		cssHandler(w, req)
+		resp := w.Result()
+		body, _ := ioutil.ReadAll(resp.Body)
+		if resp.StatusCode != 200 {
+			t.Errorf("cssHandler(): %v\n", resp.StatusCode)
+		}
+		if !bytes.Equal(body, css) {
+			t.Errorf("cssHandler(): Byte mismatch\n")
+		}
+	})
+}
diff --git a/main.go b/main.go
index bca7847..8e3a2b2 100644
--- a/main.go
+++ b/main.go
@@ -24,6 +24,9 @@ func main() {
 	index.Path("/").
 		Methods("GET").
 		HandlerFunc(indexHandler)
+	index.Path("/css").
+		Methods("GET").
+		HandlerFunc(cssHandler)
 	index.Path("/api").
 		Methods("GET").
 		HandlerFunc(apiBaseHandler)
diff --git a/types.go b/types.go
index 35f70b3..c7d1c50 100644
--- a/types.go
+++ b/types.go
@@ -1,8 +1,9 @@
 package main
 
 // content-type consts
-const txtutf8 = "text/plain; charset=utf8"
-const htmlutf8 = "text/html; charset=utf8"
+const txtutf8 = "text/plain; charset=utf-8"
+const htmlutf8 = "text/html; charset=utf-8"
+const cssutf8 = "text/css; charset=utf-8"
 
 // config object definition
 type configuration struct {