string.go raw
1 /*
2 * Copyright 2017 Baidu, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11 * either express or implied. See the License for the specific language governing permissions
12 * and limitations under the License.
13 */
14
15 // string.go - define the string util function
16
17 // Package util defines the common utilities including string and time.
18 package util
19
20 import (
21 "bytes"
22 "crypto/hmac"
23 "crypto/md5"
24 "crypto/rand"
25 "crypto/sha256"
26 "encoding/base64"
27 "encoding/hex"
28 "fmt"
29 "hash/crc32"
30 "io"
31 "os"
32 "strconv"
33 )
34
35 func HmacSha256Hex(key, str_to_sign string) string {
36 hasher := hmac.New(sha256.New, []byte(key))
37 hasher.Write([]byte(str_to_sign))
38 return hex.EncodeToString(hasher.Sum(nil))
39 }
40
41 func CalculateContentMD5(data io.Reader, size int64) (string, error) {
42 hasher := md5.New()
43 n, err := io.CopyN(hasher, data, size)
44 if err != nil {
45 return "", fmt.Errorf("calculate content-md5 occurs error: %v", err)
46 }
47 if n != size {
48 return "", fmt.Errorf("calculate content-md5 writing size %d != size %d", n, size)
49 }
50 return base64.StdEncoding.EncodeToString(hasher.Sum(nil)), nil
51 }
52
53 func CalculateContentCrc32c(data io.Reader, size int64) (string, error) {
54 castagnoliTable := crc32.MakeTable(crc32.Castagnoli)
55 hashCrc32c := crc32.New(castagnoliTable)
56 n, err := io.CopyN(hashCrc32c, data, size)
57 if err != nil {
58 return "", fmt.Errorf("calculate content-crc32c occurs error: %w", err)
59 }
60 if n != size {
61 return "", fmt.Errorf("calculate content-crc32c writing size %d != size %d", n, size)
62 }
63 return strconv.FormatUint(uint64(hashCrc32c.Sum32()), 10), nil
64 }
65
66 func CalculateContentCrc32cFromStream(reader io.Reader) (string, error) {
67 var buf bytes.Buffer
68 rdLen, err := io.Copy(&buf, reader)
69 if err != nil {
70 return "", err
71 }
72 if rdLen != int64(buf.Len()) {
73 return "", fmt.Errorf("unexpected reader")
74 }
75 return CalculateContentCrc32c(bytes.NewBuffer(buf.Bytes()), rdLen)
76 }
77
78 func CalculateContentCrc32cFromFile(fileName string) (string, error) {
79 file, err := os.Open(fileName)
80 if err != nil {
81 return "", err
82 }
83 defer file.Close()
84 fileInfo, infoErr := file.Stat()
85 if infoErr != nil {
86 return "", infoErr
87 }
88 return CalculateContentCrc32c(file, fileInfo.Size())
89 }
90
91 func UriEncode(uri string, encodeSlash bool) string {
92 var byte_buf bytes.Buffer
93 for _, b := range []byte(uri) {
94 if (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') || (b >= '0' && b <= '9') ||
95 b == '-' || b == '_' || b == '.' || b == '~' || (b == '/' && !encodeSlash) {
96 byte_buf.WriteByte(b)
97 } else {
98 byte_buf.WriteString(fmt.Sprintf("%%%02X", b))
99 }
100 }
101 return byte_buf.String()
102 }
103
104 func NewUUID() string {
105 var buf [16]byte
106 for {
107 if _, err := rand.Read(buf[:]); err == nil {
108 break
109 }
110 }
111 buf[6] = (buf[6] & 0x0f) | (4 << 4)
112 buf[8] = (buf[8] & 0xbf) | 0x80
113
114 res := make([]byte, 36)
115 hex.Encode(res[0:8], buf[0:4])
116 res[8] = '-'
117 hex.Encode(res[9:13], buf[4:6])
118 res[13] = '-'
119 hex.Encode(res[14:18], buf[6:8])
120 res[18] = '-'
121 hex.Encode(res[19:23], buf[8:10])
122 res[23] = '-'
123 hex.Encode(res[24:], buf[10:])
124 return string(res)
125 }
126
127 func NewRequestId() string {
128 return NewUUID()
129 }
130