14 const PARAM_IDS = "ids"
17 // ============================================================================
18 func bookMimeType(bookPath string) string {
19 upper := strings.ToUpper(bookPath)
21 if strings.HasSuffix(upper, ".EPUB") {
22 return "application/epub+zip"
23 } else if strings.HasSuffix(upper, ".PDF") {
24 return "application/pdf"
26 fmt.Println("Warning: Cannot determine MIME type, will use application/octet-stream:", bookPath)
27 return "application/octet-stream"
31 func efsPathForId(efsId int) string {
34 idStr := fmt.Sprintf("%010d", efsId)
35 path := fmt.Sprintf("%s/efs/%s/%s/%s/%s/%s.dat", config.basePath, idStr[0:2], idStr[2:4], idStr[4:6], idStr[6:8], idStr)
40 func handler(w http.ResponseWriter, r *http.Request) {
43 fmt.Fprintln(w, "ERROR!", err)
47 action := strings.Split(r.URL.Path[1:], "/")[0]
59 fmt.Fprintf(w, "Unrecognized request: %s\n", r.URL.Path[1:])
60 fmt.Fprintf(w, "id: %s\n", r.FormValue("id"))
62 fmt.Fprintln(w, "URL: ", r.URL)
63 fmt.Fprintln(w, "Query: ", r.URL.Query())
67 // Download a book, based on the path stored in the DB
68 func handleBook(w http.ResponseWriter, r *http.Request) {
69 path := r.URL.Path[1:]
70 tok := strings.Split(path, "/")
72 fmt.Fprintln(w, "Unexpected path for book download:", path)
76 bookId, err := strconv.Atoi(tok[1])
77 if (nil != err) || (0 == bookId) {
78 fmt.Fprintln(w, "Invalid id for book download:", path, err)
82 bookPath := queryBookPathById(bookId)
83 if 0 == len(bookPath) {
84 fmt.Fprintln(w, "No book for ID:", bookId)
88 bookFileName := filepath.Base(bookPath)
90 mimeType := bookMimeType(bookPath)
91 if 0 == len(mimeType) {
92 fmt.Fprintln(w, "Failed to determine MIME type for book:", bookPath)
97 info, err = os.Stat(bookPath)
99 fmt.Fprintln(w, "Failed to read file metadata:", bookPath, err)
102 modTime := info.ModTime()
105 fd, err = os.Open(bookPath)
107 fmt.Fprintln(w, "Failed to open file:", bookPath, err)
112 // TODO: handle non-ASCII file names. Need to look up the permutations on how to encode that.
113 w.Header().Set("Content-Disposition", "attachment; filename=" + bookFileName)
114 w.Header().Set("Content-Type", mimeType)
115 http.ServeContent(w, r, bookFileName, modTime, fd)
118 func handleDownload(w http.ResponseWriter, r *http.Request) {
119 path := r.URL.Path[1:]
120 tok := strings.Split(path, "/")
122 fmt.Fprintln(w, "Unexpected path for download:", path)
125 efsId, err := strconv.Atoi(tok[1])
126 if (nil != err) || (0 == efsId) {
127 fmt.Fprintln(w, "Invalid id for download:", path, err)
131 mimeType := queryMimeTypeByEfsId(efsId)
132 if 0 == len(mimeType) {
133 fmt.Fprintln(w, "No MIME type found for id:", efsId)
137 efsPath := efsPathForId(efsId)
140 fd, err = os.Open(efsPath)
142 fmt.Fprintln(w, "Failed to read file for id:", efsId, err)
147 w.Header().Set("Content-Type", mimeType)
151 func handleInfo(w http.ResponseWriter, r *http.Request) {
152 idParams := r.Form[PARAM_IDS]
153 if 1 != len(idParams) {
154 fmt.Fprintln(w, "ERROR! Detected either zero or multiple ids= parameters. Exactly one expected.")
158 idParam := idParams[0]
159 idStrings := strings.Split(idParam, ",")
160 ids := make([]int, len(idStrings))
162 for i, v := range(idStrings) {
163 ids[i], err = strconv.Atoi(v)
169 books := queryBooksByIds(ids)
172 jsonValue, err = json.Marshal(books)
174 fmt.Fprintln(w, "ERROR!", err)
180 func handleSearch(w http.ResponseWriter, r *http.Request) {
183 fields := []Field{Author, Title, Series}
185 terms := make([]SearchTerm, len(fields))
188 for _, fv := range(fields) {
189 paramName := fv.String()
190 paramValues := r.Form[paramName]
191 for _, pv := range(paramValues) {
192 if count >= len(terms) {
193 fmt.Printf("WARNING: limit of %d search terms exceeded. One or more terms ignored.", len(terms))
196 terms[count] = SearchTerm{Attribute:fv, Text:pv}
201 terms = terms[:count]
203 ids := queryIds(terms)
205 jsonValue, err := json.Marshal(ids)
207 fmt.Fprintln(w, "ERROR!", err)