func main() { help := flag.Bool("help", false, "Show this help") file := flag.String("file", "", "A file to calculate the uuid for") base := flag.String("base", "cmbr://image/", "The base URI for the entity") port := flag.Int("port", 0, "A port to listen for image requests on") flag.Parse() if *help { flag.PrintDefaults() return } baseURL, err := url.Parse(*base) if err != nil { log.Fatalf("Could not parse the base URI %q: %s", *base, err) } var reader io.Reader if *file != "" { fileReader, err := os.Open(*file) if err != nil { log.Fatalf("Could not open the specified file %q for reading: %s", *file, err) } defer fileReader.Close() reader = fileReader } stat, _ := os.Stdin.Stat() if (stat.Mode() & os.ModeCharDevice) == 0 { reader = os.Stdin } if reader != nil { enc := json.NewEncoder(os.Stdout) res, err := getFileInfo(baseURL, reader) if err != nil { log.Fatalf("Failed to get file info: %s", err) } err = enc.Encode(res) if err != nil { log.Fatalf("Failed to encode result: %s", err) } } if *port != 0 { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() enc := json.NewEncoder(w) w.Header().Add("Content-type", "application/json") results := make(map[string]interface{}) reader, err := r.MultipartReader() if err != nil { badRequest(w, err.Error()) return } for { part, err := reader.NextPart() if err == io.EOF { break } if err != nil { badRequest(w, err.Error()) return } if len(part.Header["Content-Disposition"]) == 0 { badRequest(w, "Missing Content-Disposition header in multipart part") return } _, params, err := mime.ParseMediaType(part.Header["Content-Disposition"][0]) if err != nil { badRequest(w, "Failed to parse Content-Disposition %q", part.Header["Content-Disposition"][0]) return } fieldName, ok := params["name"] if !ok { badRequest(w, "Missing Content-Disposition name in %q", part.Header["Content-Disposition"][0]) return } res, err := getFileInfo(baseURL, part) if err != nil { results[fieldName] = map[string]interface{}{ "error": err.Error(), } log.Printf("Failed to get file info: %s", err) } else { results[fieldName] = res } } w.WriteHeader(http.StatusOK) enc.Encode(results) }) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)) } }
// decodeBody parses body of a message, filling m.Body, m.HTML and m.Parts. func (m *Message) decodeBody(r io.Reader, h textproto.MIMEHeader) error { cth := h.Get("Content-Type") if cth == "" { cth = "text/plain" } ct, ctp, err := mime.ParseMediaType(cth) if err != nil { return fmt.Errorf("invalid content-type: %q", cth) } // Find name. filename := ctp["name"] if filename == "" { cdh := h.Get("Content-Disposition") if cdh != "" { _, cdp, err := mime.ParseMediaType(cdh) if err != nil { return fmt.Errorf("invalid content-disposition: %q", cdh) } filename = cdp["filename"] } } // If it has filename, add as attachment. if filename != "" { name, err := decodeHeader(filename) if err != nil { return fmt.Errorf("decode filename: %v", err) } data, err := ioutil.ReadAll(decodeTransfer(r, h.Get("Content-Transfer-Encoding"))) if err != nil { return fmt.Errorf("read attachment: %v", err) } m.Parts = append(m.Parts, Part{Name: name, Data: data}) return nil } if ct == "text/plain" || ct == "text/html" { buf := new(bytes.Buffer) for { data, err := ioutil.ReadAll(decodeTransfer(r, h.Get("Content-Transfer-Encoding"))) buf.Write(data) if err != nil { if _, ok := err.(base64.CorruptInputError); ok { continue } return fmt.Errorf("read body: %v", err) } break } body, err := decodeCharset(buf.String(), ctp["charset"]) if err != nil { return fmt.Errorf("charsetDecode: %v", err) } if ct == "text/html" { m.HTML += body return nil } m.Body += body return nil } if strings.HasPrefix(ct, "multipart/") { r := multipart.NewReader(r, ctp["boundary"]) for { p, err := r.NextPart() if err != nil { if err == io.EOF { break } return fmt.Errorf("next part: %q", err) } if err := m.decodeBody(p, p.Header); err != nil { p.Close() // p.Close is also called automatically by r.NextPart. return err } } return nil } // TODO: decide what to do with this. //return fmt.Errorf("content-type without filename: %q", ct) return nil }