// FixContentType ensures proper content-type // (uses mimemagic for "" and application/octet-stream) func FixContentType(body []byte, contentType, fileName string) string { switch contentType { case "application/x-zip-compressed": return "application/zip" case "application/x-rar-compressed": return "application/rar" case "", "application/octet-stream", "application/pdf", "application/x-as400attachment", "application/save-as": //log.Printf("body=%s", body) if nct := mimemagic.Match(contentType, body); nct != "" { return nct } } if GetConverter(contentType, nil) == nil { // no converter for this if nct := mimemagic.Match(contentType, body); nct != "" { return nct } } if fileName != "" && (contentType == "" || contentType == "application/octet-stream" || GetConverter(contentType, nil) == nil) { if i := strings.LastIndex(fileName, "."); i >= 0 { if nct, ok := ExtContentType[fileName[i+1:]]; ok { return nct } if nct := mime.TypeByExtension(fileName[i:]); nct != "" { return nct } } } //log.Printf("ct=%s ==> %s", ct, contentType) return contentType }
func guessMime(path string, buf []byte) string { s := mimemagic.Match("", buf) if s == "" { s = mime.TypeByExtension(filepath.Ext(path)) } for _, extension := range TextFileExtensions { if extension == filepath.Ext(path) { return "text/generic" } } return s }
func main() { b := make([]byte, 1024) for _, fn := range os.Args { f, e := os.Open(fn) if e != nil { panic(e) } f.Read(b) fmt.Printf("%-30s %s\n", mimemagic.Match("", b), fn) f.Close() } }
func processUpload(upReq UploadRequest) (upload Upload, err error) { // Determine the appropriate filename, then write to disk barename, extension := barePlusExt(upReq.filename) if upReq.randomBarename || len(barename) == 0 { barename = generateBarename() } var header []byte if len(extension) == 0 { // Pull the first 512 bytes off for use in MIME detection header = make([]byte, 512) n, _ := upReq.src.Read(header) if n == 0 { return upload, errors.New("Empty file") } header = header[:n] // Determine the type of file from header mimetype := mimemagic.Match("", header) // If the mime type is in our map, use that // otherwise just use "ext" if val, exists := mimeToExtension[mimetype]; exists { extension = val } else { extension = "ext" } } upload.Filename = strings.Join([]string{barename, extension}, ".") _, err = os.Stat(path.Join(Config.filesDir, upload.Filename)) fileexists := err == nil // Check if the delete key matches, in which case overwrite if fileexists { metad, merr := metadataRead(upload.Filename) if merr == nil { if upReq.deletionKey == metad.DeleteKey { fileexists = false } } } for fileexists { counter, err := strconv.Atoi(string(barename[len(barename)-1])) if err != nil { barename = barename + "1" } else { barename = barename[:len(barename)-1] + strconv.Itoa(counter+1) } upload.Filename = strings.Join([]string{barename, extension}, ".") _, err = os.Stat(path.Join(Config.filesDir, upload.Filename)) fileexists = err == nil } if fileBlacklist[strings.ToLower(upload.Filename)] { return upload, errors.New("Prohibited filename") } dst, err := os.Create(path.Join(Config.filesDir, upload.Filename)) if err != nil { return } defer dst.Close() // Get the rest of the metadata needed for storage var expiry time.Time if upReq.expiry == 0 { expiry = neverExpire } else { expiry = time.Now().Add(upReq.expiry) } bytes, err := io.Copy(dst, io.MultiReader(bytes.NewReader(header), upReq.src)) if bytes == 0 { os.Remove(path.Join(Config.filesDir, upload.Filename)) return upload, errors.New("Empty file") } else if err != nil { os.Remove(path.Join(Config.filesDir, upload.Filename)) return } else if bytes > Config.maxSize { os.Remove(path.Join(Config.filesDir, upload.Filename)) return upload, errors.New("File too large") } upload.Metadata, err = generateMetadata(upload.Filename, expiry, upReq.deletionKey) if err != nil { os.Remove(path.Join(Config.filesDir, upload.Filename)) os.Remove(path.Join(Config.metaDir, upload.Filename)) return } err = metadataWrite(upload.Filename, &upload.Metadata) if err != nil { os.Remove(path.Join(Config.filesDir, upload.Filename)) os.Remove(path.Join(Config.metaDir, upload.Filename)) return } return }
func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) { fileName := c.URLParams["name"] filePath := path.Join(Config.filesDir, fileName) fileInfo, err := os.Stat(filePath) if !fileExistsAndNotExpired(fileName) { notFoundHandler(c, w, r) return } expiry, _ := metadataGetExpiry(fileName) var expiryHuman string if !expiry.IsZero() { expiryHuman = humanize.RelTime(time.Now(), expiry, "", "") } sizeHuman := humanize.Bytes(uint64(fileInfo.Size())) extra := make(map[string]string) file, _ := os.Open(filePath) header := make([]byte, 512) file.Read(header) file.Close() mimetype := mimemagic.Match("", header) extension := strings.TrimPrefix(filepath.Ext(fileName), ".") if strings.EqualFold("application/json", r.Header.Get("Accept")) { js, _ := json.Marshal(map[string]string{ "filename": fileName, "mimetype": mimetype, "expiry": strconv.FormatInt(expiry.Unix(), 10), "size": strconv.FormatInt(fileInfo.Size(), 10), }) w.Write(js) return } var tpl *pongo2.Template if strings.HasPrefix(mimetype, "image/") { tpl = Templates["display/image.html"] } else if strings.HasPrefix(mimetype, "video/") { tpl = Templates["display/video.html"] } else if strings.HasPrefix(mimetype, "audio/") { tpl = Templates["display/audio.html"] } else if mimetype == "application/pdf" { tpl = Templates["display/pdf.html"] } else if supportedBinExtension(extension) { if fileInfo.Size() < maxDisplayFileSizeBytes { bytes, err := ioutil.ReadFile(filePath) if err != nil { tpl = Templates["display/file.html"] } else { extra["extension"] = extension extra["lang_hl"], extra["lang_ace"] = extensionToHlAndAceLangs(extension) extra["contents"] = string(bytes) tpl = Templates["display/bin.html"] } } else { tpl = Templates["display/file.html"] } } else { tpl = Templates["display/file.html"] } err = tpl.ExecuteWriter(pongo2.Context{ "mime": mimetype, "filename": fileName, "size": sizeHuman, "expiry": expiryHuman, "extra": extra, }, w) if err != nil { oopsHandler(c, w, r, RespHTML, "") } }
func generateMetadata(fName string, exp time.Time, delKey string) (m Metadata, err error) { file, err := fileBackend.Open(fName) if err != nil { return } defer file.Close() m.Size, err = fileBackend.Size(fName) if err != nil { return } m.Expiry = exp if delKey == "" { m.DeleteKey = uniuri.NewLen(30) } else { m.DeleteKey = delKey } // Get first 512 bytes for mimetype detection header := make([]byte, 512) file.Read(header) m.Mimetype = mimemagic.Match("", header) if m.Mimetype == "" { // Check if the file seems anything like text if printable(header) { m.Mimetype = "text/plain" } else { m.Mimetype = "application/octet-stream" } } // Compute the sha256sum hasher := sha256.New() file.Seek(0, 0) _, err = io.Copy(hasher, file) if err == nil { m.Sha256sum = hex.EncodeToString(hasher.Sum(nil)) } file.Seek(0, 0) // If archive, grab list of filenames if m.Mimetype == "application/x-tar" { tReadr := tar.NewReader(file) for { hdr, err := tReadr.Next() if err == io.EOF || err != nil { break } if hdr.Typeflag == tar.TypeDir || hdr.Typeflag == tar.TypeReg { m.ArchiveFiles = append(m.ArchiveFiles, hdr.Name) } } sort.Strings(m.ArchiveFiles) } else if m.Mimetype == "application/x-gzip" { gzf, err := gzip.NewReader(file) if err == nil { tReadr := tar.NewReader(gzf) for { hdr, err := tReadr.Next() if err == io.EOF || err != nil { break } if hdr.Typeflag == tar.TypeDir || hdr.Typeflag == tar.TypeReg { m.ArchiveFiles = append(m.ArchiveFiles, hdr.Name) } } sort.Strings(m.ArchiveFiles) } } else if m.Mimetype == "application/x-bzip" { bzf := bzip2.NewReader(file) tReadr := tar.NewReader(bzf) for { hdr, err := tReadr.Next() if err == io.EOF || err != nil { break } if hdr.Typeflag == tar.TypeDir || hdr.Typeflag == tar.TypeReg { m.ArchiveFiles = append(m.ArchiveFiles, hdr.Name) } } sort.Strings(m.ArchiveFiles) } else if m.Mimetype == "application/zip" { zf, err := zip.NewReader(file, m.Size) if err == nil { for _, f := range zf.File { m.ArchiveFiles = append(m.ArchiveFiles, f.Name) } } sort.Strings(m.ArchiveFiles) } return }
func processUpload(upReq UploadRequest) (upload Upload, err error) { // Determine the appropriate filename, then write to disk barename, extension := barePlusExt(upReq.filename) if upReq.randomBarename || len(barename) == 0 { barename = generateBarename() } var header []byte if len(extension) == 0 { // Pull the first 512 bytes off for use in MIME detection header = make([]byte, 512) n, err := upReq.src.Read(header) if n == 0 || err != nil { return upload, errors.New("Empty file") } header = header[:n] // Determine the type of file from header mimetype := mimemagic.Match("", header) // If the mime type is in our map, use that // otherwise just use "ext" if val, exists := mimeToExtension[mimetype]; exists { extension = val } else { extension = "ext" } } upload.Filename = strings.Join([]string{barename, extension}, ".") _, err = os.Stat(path.Join(Config.filesDir, upload.Filename)) fileexists := err == nil for fileexists { counter, err := strconv.Atoi(string(barename[len(barename)-1])) if err != nil { barename = barename + "1" } else { barename = barename[:len(barename)-1] + strconv.Itoa(counter+1) } upload.Filename = strings.Join([]string{barename, extension}, ".") _, err = os.Stat(path.Join(Config.filesDir, upload.Filename)) fileexists = err == nil } if fileBlacklist[strings.ToLower(upload.Filename)] { return upload, errors.New("Prohibited filename") } dst, err := os.Create(path.Join(Config.filesDir, upload.Filename)) if err != nil { return } defer dst.Close() // Get the rest of the metadata needed for storage if upReq.expiry != 0 { upload.Expiry = time.Now().Add(upReq.expiry) } // If no delete key specified, pick a random one. if upReq.deletionKey == "" { upload.DeleteKey = uniuri.NewLen(30) } else { upload.DeleteKey = upReq.deletionKey } metadataWrite(upload.Filename, &upload) bytes, err := io.Copy(dst, io.MultiReader(bytes.NewReader(header), upReq.src)) if bytes == 0 { os.Remove(path.Join(Config.filesDir, upload.Filename)) os.Remove(path.Join(Config.metaDir, upload.Filename)) return upload, errors.New("Empty file") } else if err != nil { os.Remove(path.Join(Config.filesDir, upload.Filename)) os.Remove(path.Join(Config.metaDir, upload.Filename)) return } upload.Size = bytes return }
func detectContentType(sample []byte) (string, error) { return mimemagic.Match("", sample), nil }