X-Git-Url: http://jaekl.net/gitweb/?p=quanweb.git;a=blobdiff_plain;f=main%2Fhandler.go;h=2d8076e35720c20e5422ecd87fe9eca83f70c7c9;hp=52d08e5f8ff98f192f9dbc109418424522ac6719;hb=2df0b2d1b40d59b36cb0964f1bbfb5247b55178a;hpb=d4b5c2903e7b0c2267aa7bfdef514a3d1e447de3 diff --git a/main/handler.go b/main/handler.go index 52d08e5..2d8076e 100644 --- a/main/handler.go +++ b/main/handler.go @@ -3,7 +3,10 @@ package main import ( "encoding/json" "fmt" + "io" "net/http" + "os" + "path/filepath" "strconv" "strings" ) @@ -12,6 +15,28 @@ 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() + + idStr := fmt.Sprintf("%010d", efsId) + path := fmt.Sprintf("%s/%s/%s/%s/%s/%s.dat", config.efsBasePath, idStr[0:2], idStr[2:4], idStr[4:6], idStr[6:8], idStr) + + return path +} + func handler(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if nil != err { @@ -19,9 +44,13 @@ func handler(w http.ResponseWriter, r *http.Request) { return } - action := r.URL.Path[1:] + action := strings.Split(r.URL.Path[1:], "/")[0] switch(action) { + case "book": + handleBook(w, r) + case "download": + handleDownload(w, r) case "info": handleInfo(w, r) case "search": @@ -35,6 +64,90 @@ func handler(w http.ResponseWriter, r *http.Request) { } } +// 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) + + mimeType := bookMimeType(bookPath) + if 0 == len(mimeType) { + fmt.Fprintln(w, "Failed to determine MIME type for book:", bookPath) + return + } + + 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() + + // 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:] + tok := strings.Split(path, "/") + if 2 != len(tok) { + fmt.Fprintln(w, "Unexpected path for download:", path) + return + } + efsId, err := strconv.Atoi(tok[1]) + if (nil != err) || (0 == efsId) { + fmt.Fprintln(w, "Invalid id for download:", path, err) + return + } + + mimeType := queryMimeTypeByEfsId(efsId) + if 0 == len(mimeType) { + fmt.Fprintln(w, "No MIME type found for id:", efsId) + return + } + + efsPath := efsPathForId(efsId) + + var fd *os.File + fd, err = os.Open(efsPath) + if nil != err { + fmt.Fprintln(w, "Failed to read file for id:", efsId, err) + return + } + defer fd.Close() + + w.Header().Set("Content-Type", mimeType) + io.Copy(w, fd) +} + func handleInfo(w http.ResponseWriter, r *http.Request) { idParams := r.Form[PARAM_IDS] if 1 != len(idParams) { @@ -45,8 +158,8 @@ func handleInfo(w http.ResponseWriter, r *http.Request) { idParam := idParams[0] idStrings := strings.Split(idParam, ",") ids := make([]int, len(idStrings)) + var err error for i, v := range(idStrings) { - var err error ids[i], err = strconv.Atoi(v) if nil != err { ids[i] = 0 @@ -56,7 +169,6 @@ func handleInfo(w http.ResponseWriter, r *http.Request) { books := queryBooksByIds(ids) var jsonValue []byte - var err error jsonValue, err = json.Marshal(books) if nil != err { fmt.Fprintln(w, "ERROR!", err) @@ -66,6 +178,8 @@ func handleInfo(w http.ResponseWriter, r *http.Request) { } func handleSearch(w http.ResponseWriter, r *http.Request) { + var err error + fields := []Field{Author, Title, Series} terms := make([]SearchTerm, len(fields)) @@ -76,7 +190,7 @@ func handleSearch(w http.ResponseWriter, r *http.Request) { paramValues := r.Form[paramName] for _, pv := range(paramValues) { if count >= len(terms) { - fmt.Printf("WARNING: limit of %v search terms exceeded. One or more terms ignored.") + fmt.Printf("WARNING: limit of %d search terms exceeded. One or more terms ignored.", len(terms)) break } terms[count] = SearchTerm{Attribute:fv, Text:pv} @@ -95,3 +209,4 @@ func handleSearch(w http.ResponseWriter, r *http.Request) { w.Write(jsonValue) } } +