1package oss
2
3import (
4	"bytes"
5	"crypto/hmac"
6	"crypto/sha1"
7	"encoding/base64"
8	"hash"
9	"io"
10	"net/http"
11	"sort"
12	"strings"
13)
14
15// headerSorter defines the key-value structure for storing the sorted data in signHeader.
16type headerSorter struct {
17	Keys []string
18	Vals []string
19}
20
21// signHeader signs the header and sets it as the authorization header.
22func (conn Conn) signHeader(req *http.Request, canonicalizedResource string) {
23	// Get the final authorization string
24	authorizationStr := "OSS " + conn.config.AccessKeyID + ":" + conn.getSignedStr(req, canonicalizedResource)
25
26	// Give the parameter "Authorization" value
27	req.Header.Set(HTTPHeaderAuthorization, authorizationStr)
28}
29
30func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string) string {
31	// Find out the "x-oss-"'s address in header of the request
32	temp := make(map[string]string)
33
34	for k, v := range req.Header {
35		if strings.HasPrefix(strings.ToLower(k), "x-oss-") {
36			temp[strings.ToLower(k)] = v[0]
37		}
38	}
39	hs := newHeaderSorter(temp)
40
41	// Sort the temp by the ascending order
42	hs.Sort()
43
44	// Get the canonicalizedOSSHeaders
45	canonicalizedOSSHeaders := ""
46	for i := range hs.Keys {
47		canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
48	}
49
50	// Give other parameters values
51	// when sign URL, date is expires
52	date := req.Header.Get(HTTPHeaderDate)
53	contentType := req.Header.Get(HTTPHeaderContentType)
54	contentMd5 := req.Header.Get(HTTPHeaderContentMD5)
55
56	signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
57	h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(conn.config.AccessKeySecret))
58	io.WriteString(h, signStr)
59	signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
60
61	return signedStr
62}
63
64// newHeaderSorter is an additional function for function SignHeader.
65func newHeaderSorter(m map[string]string) *headerSorter {
66	hs := &headerSorter{
67		Keys: make([]string, 0, len(m)),
68		Vals: make([]string, 0, len(m)),
69	}
70
71	for k, v := range m {
72		hs.Keys = append(hs.Keys, k)
73		hs.Vals = append(hs.Vals, v)
74	}
75	return hs
76}
77
78// Sort is an additional function for function SignHeader.
79func (hs *headerSorter) Sort() {
80	sort.Sort(hs)
81}
82
83// Len is an additional function for function SignHeader.
84func (hs *headerSorter) Len() int {
85	return len(hs.Vals)
86}
87
88// Less is an additional function for function SignHeader.
89func (hs *headerSorter) Less(i, j int) bool {
90	return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0
91}
92
93// Swap is an additional function for function SignHeader.
94func (hs *headerSorter) Swap(i, j int) {
95	hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i]
96	hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i]
97}
98