2014-02-18 17:31:16 -05:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2014-03-07 17:22:15 -05:00
package base
2014-02-18 17:31:16 -05:00
import (
"crypto/md5"
2014-03-19 07:21:23 -04:00
"crypto/rand"
"crypto/sha1"
2014-11-07 14:46:13 -05:00
"encoding/base64"
2014-02-18 17:31:16 -05:00
"encoding/hex"
2014-03-14 02:32:11 -04:00
"fmt"
2014-07-24 22:31:59 +02:00
"html/template"
2016-12-26 02:16:37 +01:00
"io"
2014-03-15 12:29:49 -04:00
"math"
2016-12-20 14:32:02 +02:00
"math/big"
2016-02-20 17:10:05 -05:00
"net/http"
2016-11-07 21:49:50 +01:00
"strconv"
2014-03-15 15:28:06 +08:00
"strings"
2014-03-14 02:32:11 -04:00
"time"
2016-02-20 17:10:05 -05:00
"unicode"
2015-12-27 17:02:36 -05:00
"unicode/utf8"
2014-05-25 20:11:25 -04:00
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2016-11-11 13:11:45 +01:00
"github.com/Unknwon/com"
"github.com/Unknwon/i18n"
2016-11-06 01:53:11 +01:00
"github.com/gogits/chardet"
2014-02-18 17:31:16 -05:00
)
2015-11-24 18:49:34 -05:00
// EncodeMD5 encodes string to md5 hex value.
func EncodeMD5 ( str string ) string {
2014-02-18 17:31:16 -05:00
m := md5 . New ( )
m . Write ( [ ] byte ( str ) )
return hex . EncodeToString ( m . Sum ( nil ) )
}
2014-03-14 02:32:11 -04:00
2016-11-24 15:17:44 +08:00
// EncodeSha1 string to sha1 hex value.
2014-11-12 06:48:50 -05:00
func EncodeSha1 ( str string ) string {
h := sha1 . New ( )
h . Write ( [ ] byte ( str ) )
return hex . EncodeToString ( h . Sum ( nil ) )
}
2016-11-07 23:14:50 +01:00
// ShortSha is basically just truncating.
// It is DEPRECATED and will be removed in the future.
2015-11-13 17:10:25 -05:00
func ShortSha ( sha1 string ) string {
2016-11-07 21:36:01 +01:00
return TruncateString ( sha1 , 10 )
2015-11-13 17:10:25 -05:00
}
2016-11-24 15:17:44 +08:00
// DetectEncoding detect the encoding of content
2015-12-31 22:13:47 -05:00
func DetectEncoding ( content [ ] byte ) ( string , error ) {
if utf8 . Valid ( content ) {
2015-12-27 17:02:36 -05:00
log . Debug ( "Detected encoding: utf-8 (fast)" )
2015-12-31 22:13:47 -05:00
return "UTF-8" , nil
2015-12-27 17:02:36 -05:00
}
2015-12-31 22:13:47 -05:00
result , err := chardet . NewTextDetector ( ) . DetectBest ( content )
2016-12-22 03:58:04 -05:00
if err != nil {
return "" , err
}
2015-12-31 22:13:47 -05:00
if result . Charset != "UTF-8" && len ( setting . Repository . AnsiCharset ) > 0 {
2015-12-25 05:45:07 -05:00
log . Debug ( "Using default AnsiCharset: %s" , setting . Repository . AnsiCharset )
2015-12-31 22:13:47 -05:00
return setting . Repository . AnsiCharset , err
2015-12-25 05:45:07 -05:00
}
2015-12-31 22:13:47 -05:00
log . Debug ( "Detected encoding: %s" , result . Charset )
return result . Charset , err
2015-11-13 17:10:25 -05:00
}
2016-11-24 15:17:44 +08:00
// BasicAuthDecode decode basic auth string
2014-12-10 05:10:26 -05:00
func BasicAuthDecode ( encoded string ) ( string , string , error ) {
s , err := base64 . StdEncoding . DecodeString ( encoded )
2014-11-07 14:46:13 -05:00
if err != nil {
2014-12-10 05:10:26 -05:00
return "" , "" , err
2014-11-07 14:46:13 -05:00
}
2014-12-10 11:01:17 +01:00
auth := strings . SplitN ( string ( s ) , ":" , 2 )
2014-12-10 05:10:26 -05:00
return auth [ 0 ] , auth [ 1 ] , nil
2014-11-07 14:46:13 -05:00
}
2016-11-24 15:17:44 +08:00
// BasicAuthEncode encode basic auth string
2014-11-07 14:46:13 -05:00
func BasicAuthEncode ( username , password string ) string {
return base64 . StdEncoding . EncodeToString ( [ ] byte ( username + ":" + password ) )
}
2014-03-23 01:44:02 +08:00
// GetRandomString generate random string by specify chars.
2016-12-20 14:32:02 +02:00
func GetRandomString ( n int ) ( string , error ) {
2014-03-19 07:21:23 -04:00
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
2016-12-20 14:32:02 +02:00
buffer := make ( [ ] byte , n )
max := big . NewInt ( int64 ( len ( alphanum ) ) )
for i := 0 ; i < n ; i ++ {
index , err := randomInt ( max )
if err != nil {
return "" , err
2014-03-23 01:44:02 +08:00
}
2016-12-20 14:32:02 +02:00
buffer [ i ] = alphanum [ index ]
2014-03-19 07:21:23 -04:00
}
2016-12-20 14:32:02 +02:00
return string ( buffer ) , nil
}
2016-12-26 02:16:37 +01:00
// GetRandomBytesAsBase64 generates a random base64 string from n bytes
func GetRandomBytesAsBase64 ( n int ) string {
bytes := make ( [ ] byte , 32 )
_ , err := io . ReadFull ( rand . Reader , bytes )
if err != nil {
2017-01-29 12:13:57 -08:00
log . Fatal ( 4 , "Error reading random bytes: %v" , err )
2016-12-26 02:16:37 +01:00
}
return base64 . RawURLEncoding . EncodeToString ( bytes )
}
2016-12-20 14:32:02 +02:00
func randomInt ( max * big . Int ) ( int , error ) {
rand , err := rand . Int ( rand . Reader , max )
if err != nil {
return 0 , err
}
return int ( rand . Int64 ( ) ) , nil
2014-03-19 07:21:23 -04:00
}
2016-11-24 15:17:44 +08:00
// VerifyTimeLimitCode verify time limit code
2014-03-19 12:50:44 -04:00
func VerifyTimeLimitCode ( data string , minutes int , code string ) bool {
if len ( code ) <= 18 {
return false
}
// split code
start := code [ : 12 ]
lives := code [ 12 : 18 ]
2014-07-26 00:24:27 -04:00
if d , err := com . StrTo ( lives ) . Int ( ) ; err == nil {
2014-03-19 12:50:44 -04:00
minutes = d
}
// right active code
retCode := CreateTimeLimitCode ( data , minutes , start )
if retCode == code && minutes > 0 {
// check time is expired or not
2015-02-16 14:44:27 +02:00
before , _ := time . ParseInLocation ( "200601021504" , start , time . Local )
2014-03-19 12:50:44 -04:00
now := time . Now ( )
if before . Add ( time . Minute * time . Duration ( minutes ) ) . Unix ( ) > now . Unix ( ) {
return true
}
}
return false
}
2016-11-24 15:17:44 +08:00
// TimeLimitCodeLength default value for time limit code
2014-03-19 12:50:44 -04:00
const TimeLimitCodeLength = 12 + 6 + 40
2016-11-24 15:17:44 +08:00
// CreateTimeLimitCode create a time limit code
2014-03-19 07:21:23 -04:00
// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
func CreateTimeLimitCode ( data string , minutes int , startInf interface { } ) string {
2015-02-16 14:44:27 +02:00
format := "200601021504"
2014-03-19 07:21:23 -04:00
var start , end time . Time
var startStr , endStr string
if startInf == nil {
// Use now time create code
start = time . Now ( )
2015-02-16 14:44:27 +02:00
startStr = start . Format ( format )
2014-03-19 07:21:23 -04:00
} else {
// use start string create code
startStr = startInf . ( string )
2015-02-16 14:44:27 +02:00
start , _ = time . ParseInLocation ( format , startStr , time . Local )
startStr = start . Format ( format )
2014-03-19 07:21:23 -04:00
}
end = start . Add ( time . Minute * time . Duration ( minutes ) )
2015-02-16 14:44:27 +02:00
endStr = end . Format ( format )
2014-03-19 07:21:23 -04:00
// create sha1 encode string
sh := sha1 . New ( )
2014-07-26 00:24:27 -04:00
sh . Write ( [ ] byte ( data + setting . SecretKey + startStr + endStr + com . ToStr ( minutes ) ) )
2014-03-19 07:21:23 -04:00
encoded := hex . EncodeToString ( sh . Sum ( nil ) )
code := fmt . Sprintf ( "%s%06d%s" , startStr , minutes , encoded )
return code
}
2016-02-14 23:14:55 -05:00
// HashEmail hashes email address to MD5 string.
// https://en.gravatar.com/site/implement/hash/
func HashEmail ( email string ) string {
2016-11-06 01:53:11 +01:00
return EncodeMD5 ( strings . ToLower ( strings . TrimSpace ( email ) ) )
2016-02-14 23:14:55 -05:00
}
2017-06-29 12:11:34 -04:00
// DefaultAvatarLink the default avatar link
2017-06-29 12:10:33 -04:00
func DefaultAvatarLink ( ) string {
return setting . AppSubURL + "/img/avatar_default.png"
}
2016-08-07 11:01:47 -07:00
// AvatarLink returns relative avatar link to the site domain by given email,
// which includes app sub-url as prefix. However, it is possible
// to return full URL if user enables Gravatar-like service.
2016-11-07 21:13:38 +01:00
func AvatarLink ( email string ) string {
2016-08-07 11:01:47 -07:00
if setting . EnableFederatedAvatar && setting . LibravatarService != nil {
2017-06-29 10:30:58 -04:00
url , err := setting . LibravatarService . FromEmail ( email )
if err != nil {
log . Error ( 4 , "LibravatarService.FromEmail(email=%s): error %v" , email , err )
2017-06-29 12:10:33 -04:00
return DefaultAvatarLink ( )
2017-06-29 10:30:58 -04:00
}
2016-11-07 21:13:38 +01:00
return url
2016-08-07 11:01:47 -07:00
}
2016-11-07 21:13:38 +01:00
if ! setting . DisableGravatar {
return setting . GravatarSource + HashEmail ( email )
2014-03-25 12:12:27 -04:00
}
2016-11-07 21:13:38 +01:00
2017-06-29 12:10:33 -04:00
return DefaultAvatarLink ( )
2014-03-17 00:57:18 -04:00
}
2014-03-14 02:32:11 -04:00
// Seconds-based time units
const (
Minute = 60
Hour = 60 * Minute
Day = 24 * Hour
Week = 7 * Day
Month = 30 * Day
Year = 12 * Month
)
2017-06-28 08:43:28 +03:00
func computeTimeDiff ( diff int64 , lang string ) ( int64 , string ) {
2014-03-22 09:21:57 -04:00
diffStr := ""
switch {
case diff <= 0 :
diff = 0
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.now" )
2014-03-22 09:21:57 -04:00
case diff < 2 :
diff = 0
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.1s" )
2014-03-22 09:21:57 -04:00
case diff < 1 * Minute :
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.seconds" , diff )
2014-03-22 09:21:57 -04:00
diff = 0
case diff < 2 * Minute :
diff -= 1 * Minute
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.1m" )
2014-03-22 09:21:57 -04:00
case diff < 1 * Hour :
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.minutes" , diff / Minute )
2014-03-22 09:21:57 -04:00
diff -= diff / Minute * Minute
case diff < 2 * Hour :
diff -= 1 * Hour
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.1h" )
2014-03-22 09:21:57 -04:00
case diff < 1 * Day :
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.hours" , diff / Hour )
2014-03-22 09:21:57 -04:00
diff -= diff / Hour * Hour
case diff < 2 * Day :
diff -= 1 * Day
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.1d" )
2014-03-22 09:21:57 -04:00
case diff < 1 * Week :
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.days" , diff / Day )
2014-03-22 09:21:57 -04:00
diff -= diff / Day * Day
case diff < 2 * Week :
diff -= 1 * Week
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.1w" )
2014-03-22 09:21:57 -04:00
case diff < 1 * Month :
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.weeks" , diff / Week )
2014-03-22 09:21:57 -04:00
diff -= diff / Week * Week
case diff < 2 * Month :
diff -= 1 * Month
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.1mon" )
2014-03-22 09:21:57 -04:00
case diff < 1 * Year :
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.months" , diff / Month )
2014-03-22 09:21:57 -04:00
diff -= diff / Month * Month
case diff < 2 * Year :
diff -= 1 * Year
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.1y" )
2014-03-22 09:21:57 -04:00
default :
2017-06-28 08:43:28 +03:00
diffStr = i18n . Tr ( lang , "tool.years" , diff / Year )
2016-12-22 03:58:04 -05:00
diff -= ( diff / Year ) * Year
2014-03-22 09:21:57 -04:00
}
return diff , diffStr
}
2017-05-29 09:35:47 +02:00
// MinutesToFriendly returns a user friendly string with number of minutes
// converted to hours and minutes.
2017-06-28 08:43:28 +03:00
func MinutesToFriendly ( minutes int , lang string ) string {
2017-05-29 09:35:47 +02:00
duration := time . Duration ( minutes ) * time . Minute
2017-06-28 08:43:28 +03:00
return TimeSincePro ( time . Now ( ) . Add ( - duration ) , lang )
2017-05-29 09:35:47 +02:00
}
2014-03-22 09:21:57 -04:00
// TimeSincePro calculates the time interval and generate full user-friendly string.
2017-06-28 08:43:28 +03:00
func TimeSincePro ( then time . Time , lang string ) string {
return timeSincePro ( then , time . Now ( ) , lang )
2016-12-22 03:58:04 -05:00
}
2017-06-28 08:43:28 +03:00
func timeSincePro ( then , now time . Time , lang string ) string {
2014-03-22 09:21:57 -04:00
diff := now . Unix ( ) - then . Unix ( )
if then . After ( now ) {
2017-06-28 08:43:28 +03:00
return i18n . Tr ( lang , "tool.future" )
2014-03-22 09:21:57 -04:00
}
2016-12-22 03:58:04 -05:00
if diff == 0 {
2017-06-28 08:43:28 +03:00
return i18n . Tr ( lang , "tool.now" )
2016-12-22 03:58:04 -05:00
}
2014-03-22 09:21:57 -04:00
var timeStr , diffStr string
for {
if diff == 0 {
break
}
2017-06-28 08:43:28 +03:00
diff , diffStr = computeTimeDiff ( diff , lang )
2014-03-22 09:21:57 -04:00
timeStr += ", " + diffStr
}
return strings . TrimPrefix ( timeStr , ", " )
}
2016-12-22 03:58:04 -05:00
func timeSince ( then , now time . Time , lang string ) string {
2017-06-28 08:43:28 +03:00
lbl := "tool.ago"
2014-03-14 02:32:11 -04:00
diff := now . Unix ( ) - then . Unix ( )
if then . After ( now ) {
2017-06-28 08:43:28 +03:00
lbl = "tool.from_now"
2014-03-14 02:32:11 -04:00
diff = then . Unix ( ) - now . Unix ( )
}
2017-06-28 08:43:28 +03:00
if diff <= 0 {
2014-07-26 00:24:27 -04:00
return i18n . Tr ( lang , "tool.now" )
2014-03-14 02:32:11 -04:00
}
2017-06-28 08:43:28 +03:00
_ , diffStr := computeTimeDiff ( diff , lang )
return i18n . Tr ( lang , lbl , diffStr )
2014-03-14 02:32:11 -04:00
}
2014-03-14 19:34:59 -04:00
2016-11-24 15:17:44 +08:00
// RawTimeSince retrieves i18n key of time since t
2015-08-13 16:07:11 +08:00
func RawTimeSince ( t time . Time , lang string ) string {
2016-12-22 03:58:04 -05:00
return timeSince ( t , time . Now ( ) , lang )
2015-08-13 16:07:11 +08:00
}
2014-07-24 22:31:59 +02:00
// TimeSince calculates the time interval and generate user-friendly string.
2016-12-22 03:58:04 -05:00
func TimeSince ( then time . Time , lang string ) template . HTML {
return htmlTimeSince ( then , time . Now ( ) , lang )
}
func htmlTimeSince ( then , now time . Time , lang string ) template . HTML {
return template . HTML ( fmt . Sprintf ( ` <span class="time-since" title="%s">%s</span> ` ,
then . Format ( setting . TimeFormat ) ,
timeSince ( then , now , lang ) ) )
2014-07-24 22:31:59 +02:00
}
2016-11-24 15:17:44 +08:00
// Storage space size types
2014-03-15 12:29:49 -04:00
const (
Byte = 1
KByte = Byte * 1024
MByte = KByte * 1024
GByte = MByte * 1024
TByte = GByte * 1024
PByte = TByte * 1024
EByte = PByte * 1024
)
var bytesSizeTable = map [ string ] uint64 {
"b" : Byte ,
"kb" : KByte ,
"mb" : MByte ,
"gb" : GByte ,
"tb" : TByte ,
"pb" : PByte ,
"eb" : EByte ,
}
func logn ( n , b float64 ) float64 {
return math . Log ( n ) / math . Log ( b )
}
func humanateBytes ( s uint64 , base float64 , sizes [ ] string ) string {
if s < 10 {
return fmt . Sprintf ( "%dB" , s )
}
e := math . Floor ( logn ( float64 ( s ) , base ) )
suffix := sizes [ int ( e ) ]
val := float64 ( s ) / math . Pow ( base , math . Floor ( e ) )
f := "%.0f"
if val < 10 {
f = "%.1f"
}
return fmt . Sprintf ( f + "%s" , val , suffix )
}
// FileSize calculates the file size and generate user-friendly string.
2014-03-15 12:31:12 -04:00
func FileSize ( s int64 ) string {
2014-03-15 12:29:49 -04:00
sizes := [ ] string { "B" , "KB" , "MB" , "GB" , "TB" , "PB" , "EB" }
return humanateBytes ( uint64 ( s ) , 1024 , sizes )
}
2014-03-14 19:34:59 -04:00
// Subtract deals with subtraction of all types of number.
func Subtract ( left interface { } , right interface { } ) interface { } {
var rleft , rright int64
var fleft , fright float64
2016-11-24 15:17:44 +08:00
var isInt = true
2014-03-14 19:34:59 -04:00
switch left . ( type ) {
case int :
rleft = int64 ( left . ( int ) )
case int8 :
rleft = int64 ( left . ( int8 ) )
case int16 :
rleft = int64 ( left . ( int16 ) )
case int32 :
rleft = int64 ( left . ( int32 ) )
case int64 :
rleft = left . ( int64 )
case float32 :
fleft = float64 ( left . ( float32 ) )
isInt = false
case float64 :
fleft = left . ( float64 )
isInt = false
}
switch right . ( type ) {
case int :
rright = int64 ( right . ( int ) )
case int8 :
rright = int64 ( right . ( int8 ) )
case int16 :
rright = int64 ( right . ( int16 ) )
case int32 :
rright = int64 ( right . ( int32 ) )
case int64 :
rright = right . ( int64 )
case float32 :
2016-12-22 03:58:04 -05:00
fright = float64 ( right . ( float32 ) )
2014-03-14 19:34:59 -04:00
isInt = false
case float64 :
2016-12-22 03:58:04 -05:00
fright = right . ( float64 )
2014-03-14 19:34:59 -04:00
isInt = false
}
if isInt {
return rleft - rright
}
2016-11-24 15:17:44 +08:00
return fleft + float64 ( rleft ) - ( fright + float64 ( rright ) )
2014-03-14 19:34:59 -04:00
}
2015-08-10 16:52:08 +08:00
2016-01-11 20:41:43 +08:00
// EllipsisString returns a truncated short string,
// it appends '...' in the end of the length of string is too large.
func EllipsisString ( str string , length int ) string {
2016-11-07 21:27:14 +01:00
if length <= 3 {
return "..."
}
if len ( str ) <= length {
2016-01-11 20:41:43 +08:00
return str
}
return str [ : length - 3 ] + "..."
}
2016-03-05 00:51:51 -05:00
// TruncateString returns a truncated string with given limit,
// it returns input string if length is not reached limit.
func TruncateString ( str string , limit int ) string {
if len ( str ) < limit {
return str
}
return str [ : limit ]
}
2015-08-10 16:52:08 +08:00
// StringsToInt64s converts a slice of string to a slice of int64.
2016-12-22 03:58:04 -05:00
func StringsToInt64s ( strs [ ] string ) ( [ ] int64 , error ) {
2015-08-10 16:52:08 +08:00
ints := make ( [ ] int64 , len ( strs ) )
for i := range strs {
2016-12-22 03:58:04 -05:00
n , err := com . StrTo ( strs [ i ] ) . Int64 ( )
if err != nil {
return ints , err
}
ints [ i ] = n
2015-08-10 16:52:08 +08:00
}
2016-12-22 03:58:04 -05:00
return ints , nil
2015-08-10 16:52:08 +08:00
}
2015-08-25 23:22:05 +08:00
// Int64sToStrings converts a slice of int64 to a slice of string.
func Int64sToStrings ( ints [ ] int64 ) [ ] string {
strs := make ( [ ] string , len ( ints ) )
for i := range ints {
2016-11-07 21:49:50 +01:00
strs [ i ] = strconv . FormatInt ( ints [ i ] , 10 )
2015-08-25 23:22:05 +08:00
}
return strs
}
2015-08-10 16:52:08 +08:00
// Int64sToMap converts a slice of int64 to a int64 map.
func Int64sToMap ( ints [ ] int64 ) map [ int64 ] bool {
m := make ( map [ int64 ] bool )
for _ , i := range ints {
m [ i ] = true
}
return m
}
2016-02-20 17:10:05 -05:00
// IsLetter reports whether the rune is a letter (category L).
// https://github.com/golang/go/blob/master/src/go/scanner/scanner.go#L257
func IsLetter ( ch rune ) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode . IsLetter ( ch )
}
2016-08-31 13:59:23 -07:00
// IsTextFile returns true if file content format is plain text or empty.
2016-08-30 02:08:38 -07:00
func IsTextFile ( data [ ] byte ) bool {
2016-08-31 13:59:23 -07:00
if len ( data ) == 0 {
return true
}
2016-08-30 02:08:38 -07:00
return strings . Index ( http . DetectContentType ( data ) , "text/" ) != - 1
2016-02-20 17:10:05 -05:00
}
2017-02-28 12:56:15 +08:00
// IsImageFile detects if data is an image format
2016-08-30 02:08:38 -07:00
func IsImageFile ( data [ ] byte ) bool {
return strings . Index ( http . DetectContentType ( data ) , "image/" ) != - 1
2016-02-20 17:10:05 -05:00
}
2016-04-27 03:48:44 +02:00
2017-02-28 12:56:15 +08:00
// IsPDFFile detects if data is a pdf format
2016-08-30 02:08:38 -07:00
func IsPDFFile ( data [ ] byte ) bool {
return strings . Index ( http . DetectContentType ( data ) , "application/pdf" ) != - 1
2016-04-27 03:48:44 +02:00
}
2016-12-20 09:09:11 +01:00
2017-02-28 12:56:15 +08:00
// IsVideoFile detects if data is an video format
2016-12-20 09:09:11 +01:00
func IsVideoFile ( data [ ] byte ) bool {
return strings . Index ( http . DetectContentType ( data ) , "video/" ) != - 1
}