Tweak html layout to improve formatting.
[quanweb.git] / main / handler.go
index 8686f2b3a870f051e8a1c096af01db4cde04c79e..8a74c627e96f534ba2f01ace20012601a4840cee 100644 (file)
@@ -6,6 +6,7 @@ import (
   "io"
   "net/http"
   "os"
+  "path/filepath"
   "strconv"
   "strings"
 )
@@ -14,6 +15,19 @@ const PARAM_IDS = "ids"
 const MAX_TERMS = 10
 
 // ============================================================================
+func bookMimeType(bookPath string) string {
+  upper := strings.ToUpper(bookPath)
+  
+  if strings.HasSuffix(upper, ".EPUB") {
+    return "application/epub+zip"
+  } else if strings.HasSuffix(upper, ".PDF") {
+    return "application/pdf"
+  } else {
+    fmt.Println("Warning:  Cannot determine MIME type, will use application/octet-stream:", bookPath)
+    return "application/octet-stream"
+  }
+}
+
 func efsPathForId(efsId int) string {
   config := getConfig()
 
@@ -33,6 +47,8 @@ func handler(w http.ResponseWriter, r *http.Request) {
   action := strings.Split(r.URL.Path[1:], "/")[0]
 
   switch(action) {
+  case "book":
+    handleBook(w, r)
   case "download":
     handleDownload(w, r)
   case "info":
@@ -48,27 +64,56 @@ func handler(w http.ResponseWriter, r *http.Request) {
   }
 }
 
-/*
-func handleApp(w http.ResponseWriter, r *http.Request) {
-  fmt.Println("handleApp():", r.URL.Path)
+// Download a book, based on the path stored in the DB
+func handleBook(w http.ResponseWriter, r *http.Request) {
+  path := r.URL.Path[1:]
+  tok := strings.Split(path, "/")
+  if 2 != len(tok) {
+    fmt.Fprintln(w, "Unexpected path for book download:", path)
+    return
+  }
+
+  bookId, err := strconv.Atoi(tok[1])
+  if (nil != err) || (0 == bookId) {
+    fmt.Fprintln(w, "Invalid id for book download:", path, err)
+    return
+  }
+
+  bookPath := queryBookPathById(bookId)
+  if 0 == len(bookPath) {
+    fmt.Fprintln(w, "No book for ID:", bookId)
+    return
+  }
+
+  bookFileName := filepath.Base(bookPath)
 
-  // Security check:  prevent walking up the directory
-  pos := strings.Index(r.Url.Path, "../")
-  if (-1) == pos {
-    fmt.Fprintln(w, "Paths containing \"../\" are not permitted:", r.URL.Path)
+  mimeType := bookMimeType(bookPath)
+  if 0 == len(mimeType) {
+    fmt.Fprintln(w, "Failed to determine MIME type for book:", bookPath)
     return
   }
 
-  fileName := "../app" + r.URL.Path
-  _, err := os.Stat(fileName)
-  if nil != err { 
-    fmt.Fprintln(w, "Failed to find file:", fileName, err)
+  var info os.FileInfo
+  info, err = os.Stat(bookPath)
+  if nil != err {
+    fmt.Fprintln(w, "Failed to read file metadata:", bookPath, err)
     return
   }
+  modTime := info.ModTime()
+  
+  var fd *os.File
+  fd, err = os.Open(bookPath)
+  if nil != err {
+    fmt.Fprintln(w, "Failed to open file:", bookPath, err)
+    return
+  }
+  defer fd.Close()
 
-  http.ServeFile(w, r, "../app/" + r.URL.Path[1:])
+  // TODO:  handle non-ASCII file names.  Need to look up the permutations on how to encode that.
+  w.Header().Set("Content-Disposition", "attachment; filename=" + bookFileName)
+  w.Header().Set("Content-Type", mimeType)
+  http.ServeContent(w, r, bookFileName, modTime, fd)
 }
-*/
 
 func handleDownload(w http.ResponseWriter, r *http.Request) {
   path := r.URL.Path[1:]
@@ -99,6 +144,7 @@ func handleDownload(w http.ResponseWriter, r *http.Request) {
   }
   defer fd.Close()
 
+  w.Header().Set("Content-Type", mimeType)
   io.Copy(w, fd)
 }