-
-
{{ error_message|default:"Oops! Something went wrong." }}
+
{% endblock %}
diff --git a/templates/paste.html b/templates/paste.html
new file mode 100644
index 0000000..b22ca96
--- /dev/null
+++ b/templates/paste.html
@@ -0,0 +1,41 @@
+{% extends "base.html" %}
+
+{% block title %}{{sitename}} - Paste{% endblock %}
+
+{% block content %}
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/torrent.go b/torrent.go
index 5235c35..c5e7a58 100644
--- a/torrent.go
+++ b/torrent.go
@@ -2,73 +2,44 @@ package main
import (
"bytes"
- "crypto/sha1"
"fmt"
"io"
"net/http"
- "os"
- "path"
"time"
+ "github.com/andreimarcu/linx-server/backends"
+ "github.com/andreimarcu/linx-server/expiry"
+ "github.com/andreimarcu/linx-server/torrent"
"github.com/zeebo/bencode"
"github.com/zenazn/goji/web"
)
-const (
- TORRENT_PIECE_LENGTH = 262144
-)
+func createTorrent(fileName string, f io.Reader, r *http.Request) ([]byte, error) {
+ url := getSiteURL(r) + Config.selifPath + fileName
+ chunk := make([]byte, torrent.TORRENT_PIECE_LENGTH)
-type TorrentInfo struct {
- PieceLength int `bencode:"piece length"`
- Pieces string `bencode:"pieces"`
- Name string `bencode:"name"`
- Length int `bencode:"length"`
-}
-
-type Torrent struct {
- Encoding string `bencode:"encoding"`
- Info TorrentInfo `bencode:"info"`
- UrlList []string `bencode:"url-list"`
-}
-
-func hashPiece(piece []byte) []byte {
- h := sha1.New()
- h.Write(piece)
- return h.Sum(nil)
-}
-
-func CreateTorrent(fileName string, filePath string) ([]byte, error) {
- chunk := make([]byte, TORRENT_PIECE_LENGTH)
-
- torrent := Torrent{
+ t := torrent.Torrent{
Encoding: "UTF-8",
- Info: TorrentInfo{
- PieceLength: TORRENT_PIECE_LENGTH,
+ Info: torrent.TorrentInfo{
+ PieceLength: torrent.TORRENT_PIECE_LENGTH,
Name: fileName,
},
- UrlList: []string{fmt.Sprintf("%sselif/%s", Config.siteURL, fileName)},
- }
-
- f, err := os.Open(filePath)
- if err != nil {
- return []byte{}, err
+ UrlList: []string{url},
}
for {
- n, err := f.Read(chunk)
+ n, err := io.ReadFull(f, chunk)
if err == io.EOF {
break
- } else if err != nil {
+ } else if err != nil && err != io.ErrUnexpectedEOF {
return []byte{}, err
}
- torrent.Info.Length += n
- torrent.Info.Pieces += string(hashPiece(chunk[:n]))
+ t.Info.Length += n
+ t.Info.Pieces += string(torrent.HashPiece(chunk[:n]))
}
- f.Close()
-
- data, err := bencode.EncodeBytes(&torrent)
+ data, err := bencode.EncodeBytes(&t)
if err != nil {
return []byte{}, err
}
@@ -78,21 +49,32 @@ func CreateTorrent(fileName string, filePath string) ([]byte, error) {
func fileTorrentHandler(c web.C, w http.ResponseWriter, r *http.Request) {
fileName := c.URLParams["name"]
- filePath := path.Join(Config.filesDir, fileName)
- if !fileExistsAndNotExpired(fileName) {
+ metadata, f, err := storageBackend.Get(fileName)
+ if err == backends.NotFoundErr {
+ notFoundHandler(c, w, r)
+ return
+ } else if err == backends.BadMetadata {
+ oopsHandler(c, w, r, RespAUTO, "Corrupt metadata.")
+ return
+ } else if err != nil {
+ oopsHandler(c, w, r, RespAUTO, err.Error())
+ return
+ }
+ defer f.Close()
+
+ if expiry.IsTsExpired(metadata.Expiry) {
+ storageBackend.Delete(fileName)
notFoundHandler(c, w, r)
return
}
- encoded, err := CreateTorrent(fileName, filePath)
+ encoded, err := createTorrent(fileName, f, r)
if err != nil {
- oopsHandler(c, w, r) // 500 - creating torrent failed
+ oopsHandler(c, w, r, RespHTML, "Could not create torrent.")
return
}
w.Header().Set(`Content-Disposition`, fmt.Sprintf(`attachment; filename="%s.torrent"`, fileName))
http.ServeContent(w, r, "", time.Now(), bytes.NewReader(encoded))
}
-
-// vim:set ts=8 sw=8 noet:
diff --git a/torrent/torrent.go b/torrent/torrent.go
new file mode 100644
index 0000000..a47d884
--- /dev/null
+++ b/torrent/torrent.go
@@ -0,0 +1,28 @@
+package torrent
+
+import (
+ "crypto/sha1"
+)
+
+const (
+ TORRENT_PIECE_LENGTH = 262144
+)
+
+type TorrentInfo struct {
+ PieceLength int `bencode:"piece length"`
+ Pieces string `bencode:"pieces"`
+ Name string `bencode:"name"`
+ Length int `bencode:"length"`
+}
+
+type Torrent struct {
+ Encoding string `bencode:"encoding"`
+ Info TorrentInfo `bencode:"info"`
+ UrlList []string `bencode:"url-list"`
+}
+
+func HashPiece(piece []byte) []byte {
+ h := sha1.New()
+ h.Write(piece)
+ return h.Sum(nil)
+}
diff --git a/torrent_test.go b/torrent_test.go
index 5a1d34a..f14c613 100644
--- a/torrent_test.go
+++ b/torrent_test.go
@@ -2,16 +2,24 @@ package main
import (
"fmt"
+ "os"
"testing"
+ "github.com/andreimarcu/linx-server/torrent"
"github.com/zeebo/bencode"
)
func TestCreateTorrent(t *testing.T) {
fileName := "server.go"
- var decoded Torrent
+ var decoded torrent.Torrent
- encoded, err := CreateTorrent(fileName, fileName)
+ f, err := os.Open("server.go")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+
+ encoded, err := createTorrent(fileName, f, nil)
if err != nil {
t.Fatal(err)
}
@@ -38,25 +46,29 @@ func TestCreateTorrent(t *testing.T) {
t.Fatal("Length was less than or equal to 0, expected more")
}
- tracker := fmt.Sprintf("%sselif/%s", Config.siteURL, fileName)
+ tracker := fmt.Sprintf("%s%s%s", Config.siteURL, Config.selifPath, fileName)
if decoded.UrlList[0] != tracker {
t.Fatalf("First entry in URL list was %s, expected %s", decoded.UrlList[0], tracker)
}
}
func TestCreateTorrentWithImage(t *testing.T) {
- var decoded Torrent
+ var decoded torrent.Torrent
- encoded, err := CreateTorrent("test.jpg", "static/images/404.jpg")
+ f, err := os.Open("static/images/404.jpg")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+
+ encoded, err := createTorrent("test.jpg", f, nil)
if err != nil {
t.Fatal(err)
}
bencode.DecodeBytes(encoded, &decoded)
- if decoded.Info.Pieces != "r\x01\x80j\x99\x84\n\xd3dZ;1NX\xec;\x9d$+f" {
+ if decoded.Info.Pieces != "\xd6\xff\xbf'^)\x85?\xb4.\xb0\xc1|\xa3\x83\xeeX\xf9\xfd\xd7" {
t.Fatal("Torrent pieces did not match expected pieces for image")
}
}
-
-// vim:set ts=8 sw=8 noet:
diff --git a/upload.go b/upload.go
index 341fa9d..0485c22 100644
--- a/upload.go
+++ b/upload.go
@@ -6,241 +6,433 @@ import (
"errors"
"fmt"
"io"
+ "log"
"net/http"
- "os"
+ "net/url"
"path"
+ "path/filepath"
"regexp"
"strconv"
"strings"
+ "time"
- "bitbucket.org/taruti/mimemagic"
+ "github.com/andreimarcu/linx-server/auth/apikeys"
+ "github.com/andreimarcu/linx-server/backends"
+ "github.com/andreimarcu/linx-server/expiry"
+ "github.com/dchest/uniuri"
+ "github.com/gabriel-vasile/mimetype"
"github.com/zenazn/goji/web"
)
+var FileTooLargeError = errors.New("File too large.")
+var fileBlacklist = map[string]bool{
+ "favicon.ico": true,
+ "index.htm": true,
+ "index.html": true,
+ "index.php": true,
+ "robots.txt": true,
+ "crossdomain.xml": true,
+}
// Describes metadata directly from the user request
type UploadRequest struct {
src io.Reader
+ size int64
filename string
- expiry int64 // Seconds until expiry, 0 = never
+ expiry time.Duration // Seconds until expiry, 0 = never
+ deleteKey string // Empty string if not defined
randomBarename bool
- deletionKey string // Empty string if not defined
+ accessKey string // Empty string if not defined
+ srcIp string // Empty string if not defined
}
// Metadata associated with a file as it would actually be stored
type Upload struct {
- Filename string // Final filename on disk
- Size int64
- Expiry int64 // Unix timestamp of expiry, 0=never
- DeleteKey string // Deletion key, one generated if not provided
+ Filename string // Final filename on disk
+ Metadata backends.Metadata
}
func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) {
+ if !strictReferrerCheck(r, getSiteURL(r), []string{"Linx-Delete-Key", "Linx-Expiry", "Linx-Randomize", "X-Requested-With"}) {
+ badRequestHandler(c, w, r, RespAUTO, "")
+ return
+ }
+
upReq := UploadRequest{}
uploadHeaderProcess(r, &upReq)
- if r.Header.Get("Content-Type") == "application/octet-stream" {
- if r.URL.Query().Get("randomize") == "true" {
- upReq.randomBarename = true
- }
- upReq.expiry = parseExpiry(r.URL.Query().Get("expires"))
-
- defer r.Body.Close()
- upReq.src = r.Body
- upReq.filename = r.URL.Query().Get("qqfile")
-
- } else {
+ contentType := r.Header.Get("Content-Type")
+ if strings.HasPrefix(contentType, "multipart/form-data") {
file, headers, err := r.FormFile("file")
if err != nil {
- oopsHandler(c, w, r)
+ oopsHandler(c, w, r, RespHTML, "Could not upload file.")
return
}
defer file.Close()
- r.ParseForm()
- if r.Form.Get("randomize") == "true" {
- upReq.randomBarename = true
- }
- upReq.expiry = parseExpiry(r.Form.Get("expires"))
upReq.src = file
+ upReq.size = headers.Size
upReq.filename = headers.Filename
+ } else {
+ if r.PostFormValue("content") == "" {
+ badRequestHandler(c, w, r, RespAUTO, "Empty file")
+ return
+ }
+ extension := r.PostFormValue("extension")
+ if extension == "" {
+ extension = "txt"
+ }
+
+ content := r.PostFormValue("content")
+
+ upReq.src = strings.NewReader(content)
+ upReq.size = int64(len(content))
+ upReq.filename = r.PostFormValue("filename") + "." + extension
}
- upload, err := processUpload(upReq)
- if err != nil {
- oopsHandler(c, w, r)
- return
+ upReq.expiry = parseExpiry(r.PostFormValue("expires"))
+ upReq.accessKey = r.PostFormValue(accessKeyParamName)
+ if r.PostFormValue("randomize") == "true" {
+ upReq.randomBarename = true
}
+ upReq.srcIp = r.Header.Get("X-Forwarded-For")
+ upload, err := processUpload(upReq)
if strings.EqualFold("application/json", r.Header.Get("Accept")) {
- js := generateJSONresponse(upload)
+ if err == FileTooLargeError || err == backends.FileEmptyError {
+ badRequestHandler(c, w, r, RespJSON, err.Error())
+ return
+ } else if err != nil {
+ oopsHandler(c, w, r, RespJSON, "Could not upload file: "+err.Error())
+ return
+ }
+
+ js := generateJSONresponse(upload, r)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Write(js)
} else {
- http.Redirect(w, r, "/"+upload.Filename, 301)
- }
+ if err == FileTooLargeError || err == backends.FileEmptyError {
+ badRequestHandler(c, w, r, RespHTML, err.Error())
+ return
+ } else if err != nil {
+ oopsHandler(c, w, r, RespHTML, "Could not upload file: "+err.Error())
+ return
+ }
+ http.Redirect(w, r, Config.sitePath+upload.Filename, 303)
+ }
}
func uploadPutHandler(c web.C, w http.ResponseWriter, r *http.Request) {
upReq := UploadRequest{}
uploadHeaderProcess(r, &upReq)
-
+
defer r.Body.Close()
upReq.filename = c.URLParams["name"]
- upReq.src = r.Body
-
+ upReq.src = http.MaxBytesReader(w, r.Body, Config.maxSize)
+ upReq.srcIp = r.Header.Get("X-Forwarded-For")
upload, err := processUpload(upReq)
- if err != nil {
- oopsHandler(c, w, r)
- return
- }
if strings.EqualFold("application/json", r.Header.Get("Accept")) {
- js := generateJSONresponse(upload)
+ if err == FileTooLargeError || err == backends.FileEmptyError {
+ badRequestHandler(c, w, r, RespJSON, err.Error())
+ return
+ } else if err != nil {
+ oopsHandler(c, w, r, RespJSON, "Could not upload file: "+err.Error())
+ return
+ }
+
+ js := generateJSONresponse(upload, r)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.Write(js)
} else {
- fmt.Fprintf(w, Config.siteURL+upload.Filename)
+ if err == FileTooLargeError || err == backends.FileEmptyError {
+ badRequestHandler(c, w, r, RespPLAIN, err.Error())
+ return
+ } else if err != nil {
+ oopsHandler(c, w, r, RespPLAIN, "Could not upload file: "+err.Error())
+ return
+ }
+
+ fmt.Fprintf(w, "%s\n", getSiteURL(r)+upload.Filename)
+ }
+}
+
+func uploadRemote(c web.C, w http.ResponseWriter, r *http.Request) {
+ if Config.remoteAuthFile != "" {
+ key := r.FormValue("key")
+ if key == "" && Config.basicAuth {
+ _, password, ok := r.BasicAuth()
+ if ok {
+ key = password
+ }
+ }
+ result, err := apikeys.CheckAuth(remoteAuthKeys, key)
+ if err != nil || !result {
+ if Config.basicAuth {
+ rs := ""
+ if Config.siteName != "" {
+ rs = fmt.Sprintf(` realm="%s"`, Config.siteName)
+ }
+ w.Header().Set("WWW-Authenticate", `Basic`+rs)
+ }
+ unauthorizedHandler(c, w, r)
+ return
+ }
+ }
+
+ if r.FormValue("url") == "" {
+ http.Redirect(w, r, Config.sitePath, 303)
+ return
+ }
+
+ upReq := UploadRequest{}
+ grabUrl, _ := url.Parse(r.FormValue("url"))
+ directURL := r.FormValue("direct_url") == "yes"
+
+ resp, err := http.Get(grabUrl.String())
+ if err != nil {
+ oopsHandler(c, w, r, RespAUTO, "Could not retrieve URL")
+ return
+ }
+
+ upReq.filename = filepath.Base(grabUrl.Path)
+ upReq.src = http.MaxBytesReader(w, resp.Body, Config.maxSize)
+ upReq.deleteKey = r.FormValue("deletekey")
+ upReq.accessKey = r.FormValue(accessKeyParamName)
+ upReq.randomBarename = r.FormValue("randomize") == "yes"
+ upReq.expiry = parseExpiry(r.FormValue("expiry"))
+ upReq.srcIp = r.Header.Get("X-Forwarded-For")
+ upload, err := processUpload(upReq)
+
+ if strings.EqualFold("application/json", r.Header.Get("Accept")) {
+ if err != nil {
+ oopsHandler(c, w, r, RespJSON, "Could not upload file: "+err.Error())
+ return
+ }
+
+ js := generateJSONresponse(upload, r)
+ w.Header().Set("Content-Type", "application/json; charset=UTF-8")
+ w.Write(js)
+ } else {
+ if err != nil {
+ oopsHandler(c, w, r, RespHTML, "Could not upload file: "+err.Error())
+ return
+ }
+
+ if directURL {
+ http.Redirect(w, r, Config.sitePath+Config.selifPath+upload.Filename, 303)
+ } else {
+ http.Redirect(w, r, Config.sitePath+upload.Filename, 303)
+ }
}
}
func uploadHeaderProcess(r *http.Request, upReq *UploadRequest) {
- // For legacy reasons
- if r.Header.Get("X-Randomized-Filename") == "yes" {
- upReq.randomBarename = true
- } else if r.Header.Get("X-Randomized-Barename") == "yes" {
+ if r.Header.Get("Linx-Randomize") == "yes" {
upReq.randomBarename = true
+ } else {
+ upReq.randomBarename = false
}
-
- upReq.deletionKey = r.Header.Get("X-Delete-Key")
-
+ upReq.deleteKey = r.Header.Get("Linx-Delete-Key")
+ upReq.accessKey = r.Header.Get(accessKeyHeaderName)
// Get seconds until expiry. Non-integer responses never expire.
- expStr := r.Header.Get("X-File-Expiry")
+ expStr := r.Header.Get("Linx-Expiry")
upReq.expiry = parseExpiry(expStr)
-
}
func processUpload(upReq UploadRequest) (upload Upload, err error) {
- // Determine the appropriate filename, then write to disk
- barename, extension := barePlusExt(upReq.filename)
-
- // Pull the first 512 bytes off for use in MIME detection if needed
- header := make([]byte, 512)
- _, err = upReq.src.Read(header)
- if err != nil {
- return
+ if upReq.size > Config.maxSize {
+ return upload, FileTooLargeError
}
+ // Determine the appropriate filename
+ barename, extension := barePlusExt(upReq.filename)
+ randomize := false
+
+ // Randomize the "barename" (filename without extension) if needed
if upReq.randomBarename || len(barename) == 0 {
barename = generateBarename()
+ randomize = true
}
+ var header []byte
if len(extension) == 0 {
- // Determine the type of file from header
- mimetype := mimemagic.Match("", header)
+ // 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, backends.FileEmptyError
+ }
+ header = header[:n]
- // If the mime type is in our map, use that
- // otherwise just use "ext"
- if val, exists := mimeToExtension[mimetype]; exists {
- extension = val
+ // Determine the type of file from header
+ kind := mimetype.Detect(header)
+ if len(kind.Extension()) < 2 {
+ extension = "file"
} else {
- extension = "ext"
+ extension = kind.Extension()[1:] // remove leading "."
}
}
upload.Filename = strings.Join([]string{barename, extension}, ".")
+ upload.Filename = strings.Replace(upload.Filename, " ", "", -1)
- _, err = os.Stat(path.Join(Config.filesDir, upload.Filename))
+ fileexists, _ := storageBackend.Exists(upload.Filename)
+
+ // Check if the delete key matches, in which case overwrite
+ if fileexists {
+ metad, merr := storageBackend.Head(upload.Filename)
+ if merr == nil {
+ if upReq.deleteKey == metad.DeleteKey {
+ fileexists = false
+ } else if Config.forceRandomFilename == true {
+ // the file exists
+ // the delete key doesn't match
+ // force random filenames is enabled
+ randomize = true
+ }
+ }
+ } else if Config.forceRandomFilename == true {
+ // the file doesn't exist
+ // force random filenames is enabled
+ randomize = true
+
+ // set fileexists to true to generate a new barename
+ fileexists = true
+ }
- fileexists := err == nil
for fileexists {
- counter, err := strconv.Atoi(string(barename[len(barename)-1]))
- if err != nil {
- barename = barename + "1"
+ if randomize {
+ barename = generateBarename()
} else {
- barename = barename[:len(barename)-1] + strconv.Itoa(counter+1)
+ 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
+ fileexists, err = storageBackend.Exists(upload.Filename)
}
- dst, err := os.Create(path.Join(Config.filesDir, upload.Filename))
- if err != nil {
- return
+ if fileBlacklist[strings.ToLower(upload.Filename)] {
+ return upload, errors.New("Prohibited filename")
+ }
+
+ // Lock the upload
+ log.Printf("Lock %s", upload.Filename)
+ err = storageBackend.Lock(upload.Filename)
+ if err != nil {
+ return upload, err
}
- defer dst.Close()
// Get the rest of the metadata needed for storage
- upload.Expiry = getFutureTimestamp(upReq.expiry)
-
- // If no delete key specified, pick a random one.
- if upReq.deletionKey == "" {
- upload.DeleteKey = randomString(30)
+ var fileExpiry time.Time
+ maxDurationTime := time.Duration(Config.maxDurationTime) * time.Second
+ if upReq.expiry == 0 {
+ if upReq.size > Config.maxDurationSize && maxDurationTime > 0 {
+ fileExpiry = time.Now().Add(maxDurationTime)
+ } else {
+ fileExpiry = expiry.NeverExpire
+ }
} else {
- upload.DeleteKey = upReq.deletionKey
+ if upReq.size > Config.maxDurationSize && upReq.expiry > maxDurationTime {
+ fileExpiry = time.Now().Add(maxDurationTime)
+ } else {
+ fileExpiry = time.Now().Add(upReq.expiry)
+ }
}
- metadataWrite(upload.Filename, &upload)
-
- // Make a multi-reader from the header and the remainder of bytes
- // in the upReq.src io.Reader
- src := io.MultiReader(bytes.NewReader(header), upReq.src)
- bytes, err := io.Copy(dst, src)
+ if upReq.deleteKey == "" {
+ upReq.deleteKey = uniuri.NewLen(30)
+ }
+ if Config.disableAccessKey == true {
+ upReq.accessKey = ""
+ }
+ log.Printf("Write %s", upload.Filename)
+ upload.Metadata, err = storageBackend.Put(upload.Filename, io.MultiReader(bytes.NewReader(header), upReq.src), fileExpiry, upReq.deleteKey, upReq.accessKey, upReq.srcIp)
if err != nil {
- return
- } else 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")
+ return upload, err
+ }
+
+ // Unlock the upload
+ log.Printf("Unlock %s", upload.Filename)
+ err = storageBackend.Unlock(upload.Filename)
+ if err != nil {
+ return upload, err
}
- upload.Size = bytes
return
}
func generateBarename() string {
- return randomString(8)
+ return uniuri.NewLenChars(8, []byte("abcdefghijklmnopqrstuvwxyz0123456789"))
}
-func generateJSONresponse(upload Upload) []byte {
+func generateJSONresponse(upload Upload, r *http.Request) []byte {
js, _ := json.Marshal(map[string]string{
- "url": Config.siteURL + upload.Filename,
+ "url": getSiteURL(r) + upload.Filename,
+ "direct_url": getSiteURL(r) + Config.selifPath + upload.Filename,
"filename": upload.Filename,
- "delete_key": upload.DeleteKey,
- "expiry": strconv.FormatInt(int64(upload.Expiry), 10),
- "size": strconv.FormatInt(upload.Size, 10),
+ "delete_key": upload.Metadata.DeleteKey,
+ "access_key": upload.Metadata.AccessKey,
+ "expiry": strconv.FormatInt(upload.Metadata.Expiry.Unix(), 10),
+ "size": strconv.FormatInt(upload.Metadata.Size, 10),
+ "mimetype": upload.Metadata.Mimetype,
+ "sha256sum": upload.Metadata.Sha256sum,
})
return js
}
-var barePlusRe = regexp.MustCompile(`[^A-Za-z0-9\-]`)
+var bareRe = regexp.MustCompile(`[^A-Za-z0-9\-]`)
+var extRe = regexp.MustCompile(`[^A-Za-z0-9\-\.]`)
+var compressedExts = map[string]bool{
+ ".bz2": true,
+ ".gz": true,
+ ".xz": true,
+}
+var archiveExts = map[string]bool{
+ ".tar": true,
+}
func barePlusExt(filename string) (barename, extension string) {
-
filename = strings.TrimSpace(filename)
filename = strings.ToLower(filename)
extension = path.Ext(filename)
barename = filename[:len(filename)-len(extension)]
+ if compressedExts[extension] {
+ ext2 := path.Ext(barename)
+ if archiveExts[ext2] {
+ barename = barename[:len(barename)-len(ext2)]
+ extension = ext2 + extension
+ }
+ }
- extension = barePlusRe.ReplaceAllString(extension, "")
- barename = barePlusRe.ReplaceAllString(barename, "")
+ extension = extRe.ReplaceAllString(extension, "")
+ barename = bareRe.ReplaceAllString(barename, "")
+
+ extension = strings.Trim(extension, "-.")
+ barename = strings.Trim(barename, "-")
return
}
-func parseExpiry(expStr string) int64 {
+func parseExpiry(expStr string) time.Duration {
if expStr == "" {
- return 0
+ return time.Duration(Config.defaultExpiry) * time.Second
} else {
- expiry, err := strconv.ParseInt(expStr, 10, 64)
+ fileExpiry, err := strconv.ParseUint(expStr, 10, 64)
if err != nil {
- return 0
+ return time.Duration(Config.defaultExpiry) * time.Second
} else {
- return int64(expiry)
+ if Config.maxExpiry > 0 && (fileExpiry > Config.maxExpiry || fileExpiry == 0) {
+ fileExpiry = Config.maxExpiry
+ }
+ return time.Duration(fileExpiry) * time.Second
}
}
}
diff --git a/util.go b/util.go
index 565951e..dabe227 100644
--- a/util.go
+++ b/util.go
@@ -1,804 +1,75 @@
package main
-import (
- "math/rand"
- "time"
-)
-
-// from http://stackoverflow.com/a/31832326
-var src = rand.NewSource(time.Now().UnixNano())
-
-const letterBytes = "abcdefghijklmnopqrstuvwxyz1234567890"
-const (
- letterIdxBits = 6 // 6 bits to represent a letter index
- letterIdxMask = 1<
= 0; {
- if remain == 0 {
- cache, remain = src.Int63(), letterIdxMax
- }
- if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
- b[i] = letterBytes[idx]
- i--
- }
- cache >>= letterIdxBits
- remain--
+func extensionToHlLang(extension string) (hlExt string) {
+ hlExt, exists := extensionToHl[extension]
+ if !exists {
+ hlExt = "text"
}
-
- return string(b)
+ return
}
-var mimeToExtension = map[string]string{
- "application/andrew-inset": "ez",
- "application/applixware": "aw",
- "application/atom+xml": "atom",
- "application/atomcat+xml": "atomcat",
- "application/atomsvc+xml": "atomsvc",
- "application/ccxml+xml": "ccxml",
- "application/cdmi-capability": "cdmia",
- "application/cdmi-container": "cdmic",
- "application/cdmi-domain": "cdmid",
- "application/cdmi-object": "cdmio",
- "application/cdmi-queue": "cdmiq",
- "application/cu-seeme": "cu",
- "application/davmount+xml": "davmount",
- "application/docbook+xml": "dbk",
- "application/dssc+der": "dssc",
- "application/dssc+xml": "xdssc",
- "application/ecmascript": "ecma",
- "application/emma+xml": "emma",
- "application/epub+zip": "epub",
- "application/exi": "exi",
- "application/font-tdpfr": "pfr",
- "application/gml+xml": "gml",
- "application/gpx+xml": "gpx",
- "application/gxf": "gxf",
- "application/hyperstudio": "stk",
- "application/inkml+xml": "ink inkml",
- "application/ipfix": "ipfix",
- "application/java-archive": "jar",
- "application/java-serialized-object": "ser",
- "application/java-vm": "class",
- "application/javascript": "js",
- "application/json": "json",
- "application/jsonml+json": "jsonml",
- "application/lost+xml": "lostxml",
- "application/mac-binhex40": "hqx",
- "application/mac-compactpro": "cpt",
- "application/mads+xml": "mads",
- "application/marc": "mrc",
- "application/marcxml+xml": "mrcx",
- "application/mathematica": "ma",
- "application/mathml+xml": "mathml",
- "application/mbox": "mbox",
- "application/mediaservercontrol+xml": "mscml",
- "application/metalink+xml": "metalink",
- "application/metalink4+xml": "meta4",
- "application/mets+xml": "mets",
- "application/mods+xml": "mods",
- "application/mp21": "mp21",
- "application/mp4": "mp4s",
- "application/msword": "doc",
- "application/mxf": "mxf",
- "application/octet-stream": "bin",
- "application/oda": "oda",
- "application/oebps-package+xml": "opf",
- "application/ogg": "ogx",
- "application/omdoc+xml": "omdoc",
- "application/onenote": "onetoc",
- "application/oxps": "oxps",
- "application/patch-ops-error+xml": "xer",
- "application/pdf": "pdf",
- "application/pgp-encrypted": "pgp",
- "application/pgp-signature": "asc",
- "application/pics-rules": "prf",
- "application/pkcs10": "p10",
- "application/pkcs7-mime": "p7m",
- "application/pkcs7-signature": "p7s",
- "application/pkcs8": "p8",
- "application/pkix-attr-cert": "ac",
- "application/pkix-cert": "cer",
- "application/pkix-crl": "crl",
- "application/pkix-pkipath": "pkipath",
- "application/pkixcmp": "pki",
- "application/pls+xml": "pls",
- "application/postscript": "ps",
- "application/prs.cww": "cww",
- "application/pskc+xml": "pskcxml",
- "application/rdf+xml": "rdf",
- "application/reginfo+xml": "rif",
- "application/relax-ng-compact-syntax": "rnc",
- "application/resource-lists+xml": "rl",
- "application/resource-lists-diff+xml": "rld",
- "application/rls-services+xml": "rs",
- "application/rpki-ghostbusters": "gbr",
- "application/rpki-manifest": "mft",
- "application/rpki-roa": "roa",
- "application/rsd+xml": "rsd",
- "application/rss+xml": "rss",
- "application/rtf": "rtf",
- "application/sbml+xml": "sbml",
- "application/scvp-cv-request": "scq",
- "application/scvp-cv-response": "scs",
- "application/scvp-vp-request": "spq",
- "application/scvp-vp-response": "spp",
- "application/sdp": "sdp",
- "application/set-payment-initiation": "setpay",
- "application/set-registration-initiation": "setreg",
- "application/shf+xml": "shf",
- "application/smil+xml": "smil",
- "application/sparql-query": "rq",
- "application/sparql-results+xml": "srx",
- "application/srgs": "gram",
- "application/srgs+xml": "grxml",
- "application/sru+xml": "sru",
- "application/ssdl+xml": "ssdl",
- "application/ssml+xml": "ssml",
- "application/tei+xml": "tei",
- "application/thraud+xml": "tfi",
- "application/timestamped-data": "tsd",
- "application/vnd.3gpp.pic-bw-large": "plb",
- "application/vnd.3gpp.pic-bw-small": "psb",
- "application/vnd.3gpp.pic-bw-var": "pvb",
- "application/vnd.3gpp2.tcap": "tcap",
- "application/vnd.3m.post-it-notes": "pwn",
- "application/vnd.accpac.simply.aso": "aso",
- "application/vnd.accpac.simply.imp": "imp",
- "application/vnd.acucobol": "acu",
- "application/vnd.acucorp": "atc acutc",
- "application/vnd.adobe.air-application-installer-package+zip": "air",
- "application/vnd.adobe.formscentral.fcdt": "fcdt",
- "application/vnd.adobe.fxp": "fxp",
- "application/vnd.adobe.xdp+xml": "xdp",
- "application/vnd.adobe.xfdf": "xfdf",
- "application/vnd.ahead.space": "ahead",
- "application/vnd.airzip.filesecure.azf": "azf",
- "application/vnd.airzip.filesecure.azs": "azs",
- "application/vnd.amazon.ebook": "azw",
- "application/vnd.americandynamics.acc": "acc",
- "application/vnd.amiga.ami": "ami",
- "application/vnd.android.package-archive": "apk",
- "application/vnd.anser-web-certificate-issue-initiation": "cii",
- "application/vnd.anser-web-funds-transfer-initiation": "fti",
- "application/vnd.antix.game-component": "atx",
- "application/vnd.apple.installer+xml": "mpkg",
- "application/vnd.apple.mpegurl": "m3u8",
- "application/vnd.aristanetworks.swi": "swi",
- "application/vnd.astraea-software.iota": "iota",
- "application/vnd.audiograph": "aep",
- "application/vnd.blueice.multipass": "mpm",
- "application/vnd.bmi": "bmi",
- "application/vnd.businessobjects": "rep",
- "application/vnd.chemdraw+xml": "cdxml",
- "application/vnd.chipnuts.karaoke-mmd": "mmd",
- "application/vnd.cinderella": "cdy",
- "application/vnd.claymore": "cla",
- "application/vnd.cloanto.rp9": "rp9",
- "application/vnd.clonk.c4group": "c4g",
- "application/vnd.cluetrust.cartomobile-config": "c11amc",
- "application/vnd.cluetrust.cartomobile-config-pkg": "c11amz",
- "application/vnd.commonspace": "csp",
- "application/vnd.contact.cmsg": "cdbcmsg",
- "application/vnd.cosmocaller": "cmc",
- "application/vnd.crick.clicker": "clkx",
- "application/vnd.crick.clicker.keyboard": "clkk",
- "application/vnd.crick.clicker.palette": "clkp",
- "application/vnd.crick.clicker.template": "clkt",
- "application/vnd.crick.clicker.wordbank": "clkw",
- "application/vnd.criticaltools.wbs+xml": "wbs",
- "application/vnd.ctc-posml": "pml",
- "application/vnd.cups-ppd": "ppd",
- "application/vnd.curl.car": "car",
- "application/vnd.curl.pcurl": "pcurl",
- "application/vnd.dart": "dart",
- "application/vnd.data-vision.rdz": "rdz",
- "application/vnd.dece.data": "uvf",
- "application/vnd.dece.ttml+xml": "uvt",
- "application/vnd.dece.unspecified": "uvx",
- "application/vnd.dece.zip": "uvz",
- "application/vnd.denovo.fcselayout-link": "fe_launch",
- "application/vnd.dna": "dna",
- "application/vnd.dolby.mlp": "mlp",
- "application/vnd.dpgraph": "dpg",
- "application/vnd.dreamfactory": "dfac",
- "application/vnd.ds-keypoint": "kpxx",
- "application/vnd.dvb.ait": "ait",
- "application/vnd.dvb.service": "svc",
- "application/vnd.dynageo": "geo",
- "application/vnd.ecowin.chart": "mag",
- "application/vnd.enliven": "nml",
- "application/vnd.epson.esf": "esf",
- "application/vnd.epson.msf": "msf",
- "application/vnd.epson.quickanime": "qam",
- "application/vnd.epson.salt": "slt",
- "application/vnd.epson.ssf": "ssf",
- "application/vnd.eszigno3+xml": "es3",
- "application/vnd.ezpix-album": "ez2",
- "application/vnd.ezpix-package": "ez3",
- "application/vnd.fdf": "fdf",
- "application/vnd.fdsn.mseed": "mseed",
- "application/vnd.fdsn.seed": "seed",
- "application/vnd.flographit": "gph",
- "application/vnd.fluxtime.clip": "ftc",
- "application/vnd.framemaker": "fm",
- "application/vnd.frogans.fnc": "fnc",
- "application/vnd.frogans.ltf": "ltf",
- "application/vnd.fsc.weblaunch": "fsc",
- "application/vnd.fujitsu.oasys": "oas",
- "application/vnd.fujitsu.oasys2": "oa2",
- "application/vnd.fujitsu.oasys3": "oa3",
- "application/vnd.fujitsu.oasysgp": "fg5",
- "application/vnd.fujitsu.oasysprs": "bh2",
- "application/vnd.fujixerox.ddd": "ddd",
- "application/vnd.fujixerox.docuworks": "xdw",
- "application/vnd.fujixerox.docuworks.binder": "xbd",
- "application/vnd.fuzzysheet": "fzs",
- "application/vnd.genomatix.tuxedo": "txd",
- "application/vnd.geogebra.file": "ggb",
- "application/vnd.geogebra.tool": "ggt",
- "application/vnd.geometry-explorer": "gex gre",
- "application/vnd.geonext": "gxt",
- "application/vnd.geoplan": "g2w",
- "application/vnd.geospace": "g3w",
- "application/vnd.gmx": "gmx",
- "application/vnd.google-earth.kml+xml": "kml",
- "application/vnd.google-earth.kmz": "kmz",
- "application/vnd.grafeq": "gqf gqs",
- "application/vnd.groove-account": "gac",
- "application/vnd.groove-help": "ghf",
- "application/vnd.groove-identity-message": "gim",
- "application/vnd.groove-injector": "grv",
- "application/vnd.groove-tool-message": "gtm",
- "application/vnd.groove-tool-template": "tpl",
- "application/vnd.groove-vcard": "vcg",
- "application/vnd.hal+xml": "hal",
- "application/vnd.handheld-entertainment+xml": "zmm",
- "application/vnd.hbci": "hbci",
- "application/vnd.hhe.lesson-player": "les",
- "application/vnd.hp-hpgl": "hpgl",
- "application/vnd.hp-hpid": "hpid",
- "application/vnd.hp-hps": "hps",
- "application/vnd.hp-jlyt": "jlt",
- "application/vnd.hp-pcl": "pcl",
- "application/vnd.hp-pclxl": "pclxl",
- "application/vnd.hydrostatix.sof-data": "sfd-hdstx",
- "application/vnd.ibm.minipay": "mpy",
- "application/vnd.ibm.modcap": "afp",
- "application/vnd.ibm.rights-management": "irm",
- "application/vnd.ibm.secure-container": "sc",
- "application/vnd.iccprofile": "icc icm",
- "application/vnd.igloader": "igl",
- "application/vnd.immervision-ivp": "ivp",
- "application/vnd.immervision-ivu": "ivu",
- "application/vnd.insors.igm": "igm",
- "application/vnd.intercon.formnet": "xpw",
- "application/vnd.intergeo": "i2g",
- "application/vnd.intu.qbo": "qbo",
- "application/vnd.intu.qfx": "qfx",
- "application/vnd.ipunplugged.rcprofile": "rcprofile",
- "application/vnd.irepository.package+xml": "irp",
- "application/vnd.is-xpr": "xpr",
- "application/vnd.isac.fcs": "fcs",
- "application/vnd.jam": "jam",
- "application/vnd.jcp.javame.midlet-rms": "rms",
- "application/vnd.jisp": "jisp",
- "application/vnd.joost.joda-archive": "joda",
- "application/vnd.kahootz": "ktz",
- "application/vnd.kde.karbon": "karbon",
- "application/vnd.kde.kchart": "chrt",
- "application/vnd.kde.kformula": "kfo",
- "application/vnd.kde.kivio": "flw",
- "application/vnd.kde.kontour": "kon",
- "application/vnd.kde.kpresenter": "kpr",
- "application/vnd.kde.kspread": "ksp",
- "application/vnd.kde.kword": "kwd",
- "application/vnd.kenameaapp": "htke",
- "application/vnd.kidspiration": "kia",
- "application/vnd.kinar": "kne knp",
- "application/vnd.koan": "skp",
- "application/vnd.kodak-descriptor": "sse",
- "application/vnd.las.las+xml": "lasxml",
- "application/vnd.llamagraphics.life-balance.desktop": "lbd",
- "application/vnd.llamagraphics.life-balance.exchange+xml": "lbe",
- "application/vnd.lotus-1-2-3": "123",
- "application/vnd.lotus-approach": "apr",
- "application/vnd.lotus-freelance": "pre",
- "application/vnd.lotus-notes": "nsf",
- "application/vnd.lotus-organizer": "org",
- "application/vnd.lotus-screencam": "scm",
- "application/vnd.lotus-wordpro": "lwp",
- "application/vnd.macports.portpkg": "portpkg",
- "application/vnd.mcd": "mcd",
- "application/vnd.medcalcdata": "mc1",
- "application/vnd.mediastation.cdkey": "cdkey",
- "application/vnd.mfer": "mwf",
- "application/vnd.mfmp": "mfm",
- "application/vnd.micrografx.flo": "flo",
- "application/vnd.micrografx.igx": "igx",
- "application/vnd.mif": "mif",
- "application/vnd.mobius.daf": "daf",
- "application/vnd.mobius.dis": "dis",
- "application/vnd.mobius.mbk": "mbk",
- "application/vnd.mobius.mqy": "mqy",
- "application/vnd.mobius.msl": "msl",
- "application/vnd.mobius.plc": "plc",
- "application/vnd.mobius.txf": "txf",
- "application/vnd.mophun.application": "mpn",
- "application/vnd.mophun.certificate": "mpc",
- "application/vnd.mozilla.xul+xml": "xul",
- "application/vnd.ms-artgalry": "cil",
- "application/vnd.ms-cab-compressed": "cab",
- "application/vnd.ms-excel": "xls",
- "application/vnd.ms-excel.addin.macroenabled.12": "xlam",
- "application/vnd.ms-excel.sheet.binary.macroenabled.12": "xlsb",
- "application/vnd.ms-excel.sheet.macroenabled.12": "xlsm",
- "application/vnd.ms-excel.template.macroenabled.12": "xltm",
- "application/vnd.ms-fontobject": "eot",
- "application/vnd.ms-htmlhelp": "chm",
- "application/vnd.ms-ims": "ims",
- "application/vnd.ms-lrm": "lrm",
- "application/vnd.ms-officetheme": "thmx",
- "application/vnd.ms-pki.seccat": "cat",
- "application/vnd.ms-pki.stl": "stl",
- "application/vnd.ms-powerpoint": "ppt pps pot",
- "application/vnd.ms-powerpoint.addin.macroenabled.12": "ppam",
- "application/vnd.ms-powerpoint.presentation.macroenabled.12": "pptm",
- "application/vnd.ms-powerpoint.slide.macroenabled.12": "sldm",
- "application/vnd.ms-powerpoint.slideshow.macroenabled.12": "ppsm",
- "application/vnd.ms-powerpoint.template.macroenabled.12": "potm",
- "application/vnd.ms-project": "mpp mpt",
- "application/vnd.ms-word.document.macroenabled.12": "docm",
- "application/vnd.ms-word.template.macroenabled.12": "dotm",
- "application/vnd.ms-works": "wps",
- "application/vnd.ms-wpl": "wpl",
- "application/vnd.ms-xpsdocument": "xps",
- "application/vnd.mseq": "mseq",
- "application/vnd.musician": "mus",
- "application/vnd.muvee.style": "msty",
- "application/vnd.mynfc": "taglet",
- "application/vnd.neurolanguage.nlu": "nlu",
- "application/vnd.nitf": "ntf nitf",
- "application/vnd.noblenet-directory": "nnd",
- "application/vnd.noblenet-sealer": "nns",
- "application/vnd.noblenet-web": "nnw",
- "application/vnd.nokia.n-gage.data": "ngdat",
- "application/vnd.nokia.n-gage.symbian.install": "n-gage",
- "application/vnd.nokia.radio-preset": "rpst",
- "application/vnd.nokia.radio-presets": "rpss",
- "application/vnd.novadigm.edm": "edm",
- "application/vnd.novadigm.edx": "edx",
- "application/vnd.novadigm.ext": "ext",
- "application/vnd.oasis.opendocument.chart": "odc",
- "application/vnd.oasis.opendocument.chart-template": "otc",
- "application/vnd.oasis.opendocument.database": "odb",
- "application/vnd.oasis.opendocument.formula": "odf",
- "application/vnd.oasis.opendocument.formula-template": "odft",
- "application/vnd.oasis.opendocument.graphics": "odg",
- "application/vnd.oasis.opendocument.graphics-template": "otg",
- "application/vnd.oasis.opendocument.image": "odi",
- "application/vnd.oasis.opendocument.image-template": "oti",
- "application/vnd.oasis.opendocument.presentation": "odp",
- "application/vnd.oasis.opendocument.presentation-template": "otp",
- "application/vnd.oasis.opendocument.spreadsheet": "ods",
- "application/vnd.oasis.opendocument.spreadsheet-template": "ots",
- "application/vnd.oasis.opendocument.text": "odt",
- "application/vnd.oasis.opendocument.text-master": "odm",
- "application/vnd.oasis.opendocument.text-template": "ott",
- "application/vnd.oasis.opendocument.text-web": "oth",
- "application/vnd.olpc-sugar": "xo",
- "application/vnd.oma.dd2+xml": "dd2",
- "application/vnd.openofficeorg.extension": "oxt",
- "application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
- "application/vnd.openxmlformats-officedocument.presentationml.slide": "sldx",
- "application/vnd.openxmlformats-officedocument.presentationml.slideshow": "ppsx",
- "application/vnd.openxmlformats-officedocument.presentationml.template": "potx",
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
- "application/vnd.openxmlformats-officedocument.spreadsheetml.template": "xltx",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.template": "dotx",
- "application/vnd.osgeo.mapguide.package": "mgp",
- "application/vnd.osgi.dp": "dp",
- "application/vnd.osgi.subsystem": "esa",
- "application/vnd.palm": "pdb pqa oprc",
- "application/vnd.pawaafile": "paw",
- "application/vnd.pg.format": "str",
- "application/vnd.pg.osasli": "ei6",
- "application/vnd.picsel": "efif",
- "application/vnd.pmi.widget": "wg",
- "application/vnd.pocketlearn": "plf",
- "application/vnd.powerbuilder6": "pbd",
- "application/vnd.previewsystems.box": "box",
- "application/vnd.proteus.magazine": "mgz",
- "application/vnd.publishare-delta-tree": "qps",
- "application/vnd.pvi.ptid1": "ptid",
- "application/vnd.quark.quarkxpress": "qxd",
- "application/vnd.realvnc.bed": "bed",
- "application/vnd.recordare.musicxml": "mxl",
- "application/vnd.recordare.musicxml+xml": "musicxml",
- "application/vnd.rig.cryptonote": "cryptonote",
- "application/vnd.rim.cod": "cod",
- "application/vnd.rn-realmedia": "rm",
- "application/vnd.rn-realmedia-vbr": "rmvb",
- "application/vnd.route66.link66+xml": "link66",
- "application/vnd.sailingtracker.track": "st",
- "application/vnd.seemail": "see",
- "application/vnd.sema": "sema",
- "application/vnd.semd": "semd",
- "application/vnd.semf": "semf",
- "application/vnd.shana.informed.formdata": "ifm",
- "application/vnd.shana.informed.formtemplate": "itp",
- "application/vnd.shana.informed.interchange": "iif",
- "application/vnd.shana.informed.package": "ipk",
- "application/vnd.simtech-mindmapper": "twd",
- "application/vnd.smaf": "mmf",
- "application/vnd.smart.teacher": "teacher",
- "application/vnd.solent.sdkm+xml": "sdkm",
- "application/vnd.spotfire.dxp": "dxp",
- "application/vnd.spotfire.sfs": "sfs",
- "application/vnd.stardivision.calc": "sdc",
- "application/vnd.stardivision.draw": "sda",
- "application/vnd.stardivision.impress": "sdd",
- "application/vnd.stardivision.math": "smf",
- "application/vnd.stardivision.writer": "sdw",
- "application/vnd.stardivision.writer-global": "sgl",
- "application/vnd.stepmania.package": "smzip",
- "application/vnd.stepmania.stepchart": "sm",
- "application/vnd.sun.xml.calc": "sxc",
- "application/vnd.sun.xml.calc.template": "stc",
- "application/vnd.sun.xml.draw": "sxd",
- "application/vnd.sun.xml.draw.template": "std",
- "application/vnd.sun.xml.impress": "sxi",
- "application/vnd.sun.xml.impress.template": "sti",
- "application/vnd.sun.xml.math": "sxm",
- "application/vnd.sun.xml.writer": "sxw",
- "application/vnd.sun.xml.writer.global": "sxg",
- "application/vnd.sun.xml.writer.template": "stw",
- "application/vnd.sus-calendar": "sus",
- "application/vnd.svd": "svd",
- "application/vnd.symbian.install": "sis",
- "application/vnd.syncml+xml": "xsm",
- "application/vnd.syncml.dm+wbxml": "bdm",
- "application/vnd.syncml.dm+xml": "xdm",
- "application/vnd.tao.intent-module-archive": "tao",
- "application/vnd.tcpdump.pcap": "pcap",
- "application/vnd.tmobile-livetv": "tmo",
- "application/vnd.trid.tpt": "tpt",
- "application/vnd.triscape.mxs": "mxs",
- "application/vnd.trueapp": "tra",
- "application/vnd.ufdl": "ufdl",
- "application/vnd.uiq.theme": "utz",
- "application/vnd.umajin": "umj",
- "application/vnd.unity": "unityweb",
- "application/vnd.uoml+xml": "uoml",
- "application/vnd.vcx": "vcx",
- "application/vnd.visio": "vsd",
- "application/vnd.visionary": "vis",
- "application/vnd.vsf": "vsf",
- "application/vnd.wap.wbxml": "wbxml",
- "application/vnd.wap.wmlc": "wmlc",
- "application/vnd.wap.wmlscriptc": "wmlsc",
- "application/vnd.webturbo": "wtb",
- "application/vnd.wolfram.player": "nbp",
- "application/vnd.wordperfect": "wpd",
- "application/vnd.wqd": "wqd",
- "application/vnd.wt.stf": "stf",
- "application/vnd.xara": "xar",
- "application/vnd.xfdl": "xfdl",
- "application/vnd.yamaha.hv-dic": "hvd",
- "application/vnd.yamaha.hv-script": "hvs",
- "application/vnd.yamaha.hv-voice": "hvp",
- "application/vnd.yamaha.openscoreformat": "osf",
- "application/vnd.yamaha.openscoreformat.osfpvg+xml": "osfpvg",
- "application/vnd.yamaha.smaf-audio": "saf",
- "application/vnd.yamaha.smaf-phrase": "spf",
- "application/vnd.yellowriver-custom-menu": "cmp",
- "application/vnd.zul": "zir",
- "application/vnd.zzazz.deck+xml": "zaz",
- "application/voicexml+xml": "vxml",
- "application/widget": "wgt",
- "application/winhlp": "hlp",
- "application/wsdl+xml": "wsdl",
- "application/wspolicy+xml": "wspolicy",
- "application/x-7z-compressed": "7z",
- "application/x-abiword": "abw",
- "application/x-ace-compressed": "ace",
- "application/x-apple-diskimage": "dmg",
- "application/x-authorware-bin": "aab",
- "application/x-authorware-map": "aam",
- "application/x-authorware-seg": "aas",
- "application/x-bcpio": "bcpio",
- "application/x-bittorrent": "torrent",
- "application/x-blorb": "blb",
- "application/x-bzip": "bz",
- "application/x-bzip2": "bz2",
- "application/x-cbr": "cbr",
- "application/x-cdlink": "vcd",
- "application/x-cfs-compressed": "cfs",
- "application/x-chat": "chat",
- "application/x-chess-pgn": "pgn",
- "application/x-conference": "nsc",
- "application/x-cpio": "cpio",
- "application/x-csh": "csh",
- "application/x-debian-package": "deb",
- "application/x-dgc-compressed": "dgc",
- "application/x-director": "dir",
- "application/x-doom": "wad",
- "application/x-dtbncx+xml": "ncx",
- "application/x-dtbook+xml": "dtb",
- "application/x-dtbresource+xml": "res",
- "application/x-dvi": "dvi",
- "application/x-envoy": "evy",
- "application/x-eva": "eva",
- "application/x-font-bdf": "bdf",
- "application/x-font-ghostscript": "gsf",
- "application/x-font-linux-psf": "psf",
- "application/x-font-otf": "otf",
- "application/x-font-pcf": "pcf",
- "application/x-font-snf": "snf",
- "application/x-font-ttf": "ttf",
- "application/x-font-type1": "pfa",
- "application/x-font-woff": "woff",
- "application/x-freearc": "arc",
- "application/x-futuresplash": "spl",
- "application/x-gca-compressed": "gca",
- "application/x-glulx": "ulx",
- "application/x-gnumeric": "gnumeric",
- "application/x-gramps-xml": "gramps",
- "application/x-gtar": "gtar",
- "application/x-hdf": "hdf",
- "application/x-install-instructions": "install",
- "application/x-iso9660-image": "iso",
- "application/x-java-jnlp-file": "jnlp",
- "application/x-latex": "latex",
- "application/x-lzh-compressed": "lzh",
- "application/x-mie": "mie",
- "application/x-mobipocket-ebook": "prc",
- "application/x-ms-application": "application",
- "application/x-ms-shortcut": "lnk",
- "application/x-ms-wmd": "wmd",
- "application/x-ms-wmz": "wmz",
- "application/x-ms-xbap": "xbap",
- "application/x-msaccess": "mdb",
- "application/x-msbinder": "obd",
- "application/x-mscardfile": "crd",
- "application/x-msclip": "clp",
- "application/x-msdownload": "exe",
- "application/x-msmediaview": "mvb",
- "application/x-msmetafile": "wmf",
- "application/x-msmoney": "mny",
- "application/x-mspublisher": "pub",
- "application/x-msschedule": "scd",
- "application/x-msterminal": "trm",
- "application/x-mswrite": "wri",
- "application/x-netcdf": "nc",
- "application/x-nzb": "nzb",
- "application/x-pkcs12": "p12",
- "application/x-pkcs7-certificates": "p7b",
- "application/x-pkcs7-certreqresp": "p7r",
- "application/x-rar-compressed": "rar",
- "application/x-research-info-systems": "ris",
- "application/x-sh": "sh",
- "application/x-shar": "shar",
- "application/x-shockwave-flash": "swf",
- "application/x-silverlight-app": "xap",
- "application/x-sql": "sql",
- "application/x-stuffit": "sit",
- "application/x-stuffitx": "sitx",
- "application/x-subrip": "srt",
- "application/x-sv4cpio": "sv4cpio",
- "application/x-sv4crc": "sv4crc",
- "application/x-t3vm-image": "t3",
- "application/x-tads": "gam",
- "application/x-tar": "tar",
- "application/x-tcl": "tcl",
- "application/x-tex": "tex",
- "application/x-tex-tfm": "tfm",
- "application/x-texinfo": "texinfo",
- "application/x-tgif": "obj",
- "application/x-ustar": "ustar",
- "application/x-wais-source": "src",
- "application/x-x509-ca-cert": "der",
- "application/x-xfig": "fig",
- "application/x-xliff+xml": "xlf",
- "application/x-xpinstall": "xpi",
- "application/x-xz": "xz",
- "application/x-zmachine": "z1",
- "application/xaml+xml": "xaml",
- "application/xcap-diff+xml": "xdf",
- "application/xenc+xml": "xenc",
- "application/xhtml+xml": "xhtml",
- "application/xml": "xml",
- "application/xml-dtd": "dtd",
- "application/xop+xml": "xop",
- "application/xproc+xml": "xpl",
- "application/xslt+xml": "xslt",
- "application/xspf+xml": "xspf",
- "application/xv+xml": "mxml",
- "application/yang": "yang",
- "application/yin+xml": "yin",
- "application/zip": "zip",
- "audio/adpcm": "adp",
- "audio/basic": "au",
- "audio/midi": "mid",
- "audio/mp4": "mp4a",
- "audio/mpeg": "mpga",
- "audio/ogg": "oga",
- "audio/s3m": "s3m",
- "audio/silk": "sil",
- "audio/vnd.dece.audio": "uva",
- "audio/vnd.digital-winds": "eol",
- "audio/vnd.dra": "dra",
- "audio/vnd.dts": "dts",
- "audio/vnd.dts.hd": "dtshd",
- "audio/vnd.lucent.voice": "lvp",
- "audio/vnd.ms-playready.media.pya": "pya",
- "audio/vnd.nuera.ecelp4800": "ecelp4800",
- "audio/vnd.nuera.ecelp7470": "ecelp7470",
- "audio/vnd.nuera.ecelp9600": "ecelp9600",
- "audio/vnd.rip": "rip",
- "audio/webm": "weba",
- "audio/x-aac": "aac",
- "audio/x-aiff": "aif",
- "audio/x-caf": "caf",
- "audio/x-flac": "flac",
- "audio/x-matroska": "mka",
- "audio/x-mpegurl": "m3u",
- "audio/x-ms-wax": "wax",
- "audio/x-ms-wma": "wma",
- "audio/x-pn-realaudio": "ram",
- "audio/x-pn-realaudio-plugin": "rmp",
- "audio/x-wav": "wav",
- "audio/xm": "xm",
- "chemical/x-cdx": "cdx",
- "chemical/x-cif": "cif",
- "chemical/x-cmdf": "cmdf",
- "chemical/x-cml": "cml",
- "chemical/x-csml": "csml",
- "chemical/x-xyz": "xyz",
- "image/bmp": "bmp",
- "image/cgm": "cgm",
- "image/g3fax": "g3",
- "image/gif": "gif",
- "image/ief": "ief",
- "image/jpeg": "jpg",
- "image/ktx": "ktx",
- "image/png": "png",
- "image/prs.btif": "btif",
- "image/sgi": "sgi",
- "image/svg+xml": "svg svgz",
- "image/tiff": "tiff tif",
- "image/vnd.adobe.photoshop": "psd",
- "image/vnd.dece.graphic": "uvi",
- "image/vnd.dvb.subtitle": "sub",
- "image/vnd.djvu": "djvu",
- "image/vnd.dwg": "dwg",
- "image/vnd.dxf": "dxf",
- "image/vnd.fastbidsheet": "fbs",
- "image/vnd.fpx": "fpx",
- "image/vnd.fst": "fst",
- "image/vnd.fujixerox.edmics-mmr": "mmr",
- "image/vnd.fujixerox.edmics-rlc": "rlc",
- "image/vnd.ms-modi": "mdi",
- "image/vnd.ms-photo": "wdp",
- "image/vnd.net-fpx": "npx",
- "image/vnd.wap.wbmp": "wbmp",
- "image/vnd.xiff": "xif",
- "image/webp": "webp",
- "image/x-3ds": "3ds",
- "image/x-cmu-raster": "ras",
- "image/x-cmx": "cmx",
- "image/x-freehand": "fh",
- "image/x-icon": "ico",
- "image/x-mrsid-image": "sid",
- "image/x-pcx": "pcx",
- "image/x-pict": "pic",
- "image/x-portable-anymap": "pnm",
- "image/x-portable-bitmap": "pbm",
- "image/x-portable-graymap": "pgm",
- "image/x-portable-pixmap": "ppm",
- "image/x-rgb": "rgb",
- "image/x-tga": "tga",
- "image/x-xbitmap": "xbm",
- "image/x-xpixmap": "xpm",
- "image/x-xwindowdump": "xwd",
- "message/rfc822": "eml mime",
- "model/iges": "igs",
- "model/mesh": "mesh",
- "model/vnd.collada+xml": "dae",
- "model/vnd.dwf": "dwf",
- "model/vnd.gdl": "gdl",
- "model/vnd.gtw": "gtw",
- "model/vnd.mts": "mts",
- "model/vnd.vtu": "vtu",
- "model/vrml": "wrl vrml",
- "model/x3d+binary": "x3db",
- "model/x3d+vrml": "x3dv",
- "model/x3d+xml": "x3d",
- "text/cache-manifest": "appcache",
- "text/calendar": "ics ifb",
- "text/css": "css",
- "text/csv": "csv",
- "text/html": "html",
- "text/n3": "n3",
- "text/plain": "txt",
- "text/prs.lines.tag": "dsc",
- "text/richtext": "rtx",
- "text/sgml": "sgml sgm",
- "text/tab-separated-values": "tsv",
- "text/troff": "t",
- "text/turtle": "ttl",
- "text/uri-list": "uri",
- "text/vcard": "vcard",
- "text/vnd.curl": "curl",
- "text/vnd.curl.dcurl": "dcurl",
- "text/vnd.curl.scurl": "scurl",
- "text/vnd.curl.mcurl": "mcurl",
- "text/vnd.dvb.subtitle": "sub",
- "text/vnd.fly": "fly",
- "text/vnd.fmi.flexstor": "flx",
- "text/vnd.graphviz": "gv",
- "text/vnd.in3d.3dml": "3dml",
- "text/vnd.in3d.spot": "spot",
- "text/vnd.sun.j2me.app-descriptor": "jad",
- "text/vnd.wap.wml": "wml",
- "text/vnd.wap.wmlscript": "wmls",
- "text/x-asm": "s asm",
- "text/x-c": "c",
- "text/x-fortran": "f",
- "text/x-java-source": "java",
- "text/x-opml": "opml",
- "text/x-pascal": "p pas",
- "text/x-nfo": "nfo",
- "text/x-shellscript": "sh",
- "text/x-setext": "etx",
- "text/x-sfv": "sfv",
- "text/x-tex": "tex",
- "text/x-uuencode": "uu",
- "text/x-vcalendar": "vcs",
- "text/x-vcard": "vcf",
- "video/3gpp": "3gp",
- "video/3gpp2": "3g2",
- "video/h261": "h261",
- "video/h263": "h263",
- "video/h264": "h264",
- "video/jpeg": "jpgv",
- "video/jpm": "jpm",
- "video/mj2": "mj2",
- "video/mp4": "mp4",
- "video/mpeg": "mpeg",
- "video/ogg": "ogv",
- "video/quicktime": "qt",
- "video/vnd.dece.hd": "uvh",
- "video/vnd.dece.mobile": "uvm",
- "video/vnd.dece.pd": "uvp",
- "video/vnd.dece.sd": "uvs",
- "video/vnd.dece.video": "uvv",
- "video/vnd.dvb.file": "dvb",
- "video/vnd.fvt": "fvt",
- "video/vnd.mpegurl": "m4u",
- "video/vnd.ms-playready.media.pyv": "pyv",
- "video/vnd.uvvu.mp4": "uvvu",
- "video/vnd.vivo": "viv",
- "video/webm": "webm",
- "video/x-f4v": "f4v",
- "video/x-fli": "fli",
- "video/x-flv": "flv",
- "video/x-m4v": "m4v",
- "video/x-matroska": "mkv",
- "video/x-mng": "mng",
- "video/x-ms-asf": "asf",
- "video/x-ms-vob": "vob",
- "video/x-ms-wm": "wm",
- "video/x-ms-wmv": "wmv",
- "video/x-ms-wmx": "wmx",
- "video/x-ms-wvx": "wvx",
- "video/x-msvideo": "avi",
- "video/x-sgi-movie": "movie",
- "video/x-smv": "smv",
- "x-conference/x-cooltalk": "ice",
+func supportedBinExtension(extension string) bool {
+ _, exists := extensionToHl[extension]
+ return exists
+}
+
+var extensionToHl = map[string]string{
+ "ahk": "autohotkey",
+ "apache": "apache",
+ "applescript": "applescript",
+ "bas": "basic",
+ "bash": "sh",
+ "bat": "dos",
+ "c": "cpp",
+ "cfc": "coldfusion",
+ "clj": "clojure",
+ "cmake": "cmake",
+ "coffee": "coffee",
+ "cpp": "c_cpp",
+ "cs": "csharp",
+ "css": "css",
+ "d": "d",
+ "dart": "dart",
+ "diff": "diff",
+ "dockerfile": "dockerfile",
+ "elm": "elm",
+ "erl": "erlang",
+ "for": "fortran",
+ "go": "go",
+ "h": "cpp",
+ "htm": "html",
+ "html": "html",
+ "ini": "ini",
+ "java": "java",
+ "js": "javascript",
+ "json": "json",
+ "jsp": "jsp",
+ "kt": "kotlin",
+ "less": "less",
+ "lisp": "lisp",
+ "lua": "lua",
+ "m": "objectivec",
+ "nginx": "nginx",
+ "ocaml": "ocaml",
+ "php": "php",
+ "pl": "perl",
+ "proto": "protobuf",
+ "ps": "powershell",
+ "py": "python",
+ "rb": "ruby",
+ "rs": "rust",
+ "scala": "scala",
+ "scm": "scheme",
+ "scpt": "applescript",
+ "scss": "scss",
+ "sh": "sh",
+ "sql": "sql",
+ "tcl": "tcl",
+ "tex": "latex",
+ "toml": "ini",
+ "ts": "typescript",
+ "txt": "text",
+ "xml": "xml",
+ "yaml": "yaml",
+ "yml": "yaml",
}