package main import ( "encoding/json" "fmt" "io" "net/http" "os" "strconv" "strings" ) const PARAM_IDS = "ids" const MAX_TERMS = 10 // ============================================================================ 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 { fmt.Fprintln(w, "ERROR!", err) return } action := strings.Split(r.URL.Path[1:], "/")[0] switch(action) { case "download": handleDownload(w, r) case "info": handleInfo(w, r) case "search": handleSearch(w, r) default: fmt.Fprintf(w, "Unrecognized request: %s\n", r.URL.Path[1:]) fmt.Fprintf(w, "id: %s\n", r.FormValue("id")) fmt.Fprintln(w, "URL: ", r.URL) fmt.Fprintln(w, "Query: ", r.URL.Query()) } } /* func handleApp(w http.ResponseWriter, r *http.Request) { fmt.Println("handleApp():", r.URL.Path) // 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) return } fileName := "../app" + r.URL.Path _, err := os.Stat(fileName) if nil != err { fmt.Fprintln(w, "Failed to find file:", fileName, err) return } http.ServeFile(w, r, "../app/" + r.URL.Path[1:]) } */ 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() io.Copy(w, fd) } func handleInfo(w http.ResponseWriter, r *http.Request) { idParams := r.Form[PARAM_IDS] if 1 != len(idParams) { fmt.Fprintln(w, "ERROR! Detected either zero or multiple ids= parameters. Exactly one expected.") return } idParam := idParams[0] idStrings := strings.Split(idParam, ",") ids := make([]int, len(idStrings)) var err error for i, v := range(idStrings) { ids[i], err = strconv.Atoi(v) if nil != err { ids[i] = 0 } } books := queryBooksByIds(ids) var jsonValue []byte jsonValue, err = json.Marshal(books) if nil != err { fmt.Fprintln(w, "ERROR!", err) } else { w.Write(jsonValue) } } func handleSearch(w http.ResponseWriter, r *http.Request) { var err error fmt.Println("DEBUG: handleSearch(): " + r.URL.Path) fields := []Field{Author, Title, Series} terms := make([]SearchTerm, len(fields)) count := 0 for _, fv := range(fields) { paramName := fv.String() paramValues := r.Form[paramName] for _, pv := range(paramValues) { fmt.Println("DEBUG: handleSearch(): ", paramName, "=", pv) if count >= len(terms) { fmt.Printf("WARNING: limit of %d search terms exceeded. One or more terms ignored.", len(terms)) break } terms[count] = SearchTerm{Attribute:fv, Text:pv} count++ } } terms = terms[:count] ids := queryIds(terms) jsonValue, err := json.Marshal(ids) if nil != err { fmt.Fprintln(w, "ERROR!", err) } else { w.Write(jsonValue) } }