X-Git-Url: http://jaekl.net/gitweb/?p=quanweb.git;a=blobdiff_plain;f=main%2Fhandler.go;h=8a74c627e96f534ba2f01ace20012601a4840cee;hp=8686f2b3a870f051e8a1c096af01db4cde04c79e;hb=23d77d1681abb3361f68c56bf0a78481ea479248;hpb=ca96e0b6276f6efe56b102ad8286a2534d6e264b diff --git a/main/handler.go b/main/handler.go index 8686f2b..8a74c62 100644 --- a/main/handler.go +++ b/main/handler.go @@ -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) }