"io"
"net/http"
"os"
+ "path/filepath"
"strconv"
"strings"
)
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()
action := strings.Split(r.URL.Path[1:], "/")[0]
switch(action) {
+ case "book":
+ handleBook(w, r)
case "download":
handleDownload(w, r)
case "info":
}
}
-/*
-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:]
}
defer fd.Close()
+ w.Header().Set("Content-Type", mimeType)
io.Copy(w, fd)
}