From 3000824ac5c77bee60afc4c3967f857517760571 Mon Sep 17 00:00:00 2001 From: css521 <42376488+css521@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:19:46 +0800 Subject: [PATCH] Update Request Header Prefixes and Upgrade API Version to 0.6.0 (#5772) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update Request Header Prefixes and Upgrade API Version to 0.6.0 - Changed all HTTP request header prefixes from `x-sls-` to `x-log-` to comply with the latest API specifications. - Adjusted header prefix validation in `signature.go` to support `x-log-` and `x-acs-`. - Replaced `x-sls-bodyrawsize` with `x-log-bodyrawsize` in multiple files (`log_project.go`, `request.go`, etc.). - Updated header fields for compression type and signing method (e.g., `x-sls-compresstype` to `x-log-compresstype`). - Modified authorization logic to replace `SLS` with `LOG`. * Refactor signature generation logic for improved readability and maintainability Split the signature generation logic into several independent functions, including header extraction, standardized header construction, and resource string generation. This modular design enhances code clarity, reduces redundant logic, and improves error handling mechanisms. Additionally, comments and code structure have been optimized to ensure easier extension and debugging. --------- Co-authored-by: 优胜 --- core/logs/alils/config.go | 2 +- core/logs/alils/log_project.go | 559 +++++-------------------------- core/logs/alils/log_store.go | 22 +- core/logs/alils/machine_group.go | 2 +- core/logs/alils/request.go | 14 +- core/logs/alils/signature.go | 187 +++++++---- 6 files changed, 217 insertions(+), 569 deletions(-) diff --git a/core/logs/alils/config.go b/core/logs/alils/config.go index 558db6a8..0b1d4256 100755 --- a/core/logs/alils/config.go +++ b/core/logs/alils/config.go @@ -1,7 +1,7 @@ package alils const ( - version = "0.5.0" // SDK version + version = "0.6.0" // SDK version signatureMethod = "hmac-sha1" // Signature method // OffsetNewest is the log head offset, i.e. the offset that will be diff --git a/core/logs/alils/log_project.go b/core/logs/alils/log_project.go index 700b50c7..91d08938 100755 --- a/core/logs/alils/log_project.go +++ b/core/logs/alils/log_project.go @@ -39,33 +39,62 @@ func NewLogProject(name, endpoint, AccessKeyID, accessKeySecret string) (p *LogP return p, nil } -// ListLogStore returns all logstore names of project p. -func (p *LogProject) ListLogStore() (storeNames []string, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - uri := "/logstores" - r, err := request(p, "GET", uri, h, nil) +// handleResponse is a helper function to process HTTP response and handle common error cases +// Returns response body as []byte and error if any +func handleResponse(r *http.Response, actionDesc string) ([]byte, error) { + body, err := io.ReadAll(r.Body) if err != nil { - return - } - - buf, err := io.ReadAll(r.Body) - if err != nil { - return + return nil, err } if r.StatusCode != http.StatusOK { errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) + err = json.Unmarshal(body, errMsg) if err != nil { - err = fmt.Errorf("failed to list logstore") + err = fmt.Errorf("failed to %s", actionDesc) dump, _ := httputil.DumpResponse(r, true) fmt.Printf("%s\n", dump) - return + return nil, err } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) + return nil, fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) + } + + return body, nil +} + +// sendRequest is a helper function to send HTTP request with specified method, uri, headers and body +// Returns response body as []byte and error if any +func (p *LogProject) sendRequest(method, uri string, headers map[string]string, body []byte) ([]byte, error) { + r, err := request(p, method, uri, headers, body) + if err != nil { + return nil, err + } + + return handleResponse(r, "process request "+method+" "+uri) +} + +// createStandardHeaders creates a map with standard headers for requests +func createStandardHeaders(bodyLen int) map[string]string { + if bodyLen <= 0 { + return map[string]string{ + "x-log-bodyrawsize": "0", + } + } + + return map[string]string{ + "x-log-bodyrawsize": fmt.Sprintf("%v", bodyLen), + "Content-Type": "application/json", + "Accept-Encoding": "deflate", // TODO: support lz4 + } +} + +// ListLogStore returns all logstore names of project p. +func (p *LogProject) ListLogStore() (storeNames []string, err error) { + h := createStandardHeaders(0) + uri := "/logstores" + + buf, err := p.sendRequest("GET", uri, h, nil) + if err != nil { return } @@ -81,39 +110,18 @@ func (p *LogProject) ListLogStore() (storeNames []string, err error) { } storeNames = body.LogStores - return } // GetLogStore returns logstore according by logstore name. func (p *LogProject) GetLogStore(name string) (s *LogStore, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) - r, err := request(p, "GET", "/logstores/"+name, h, nil) + buf, err := p.sendRequest("GET", "/logstores/"+name, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to get logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - s = &LogStore{} err = json.Unmarshal(buf, s) if err != nil { @@ -145,66 +153,15 @@ func (p *LogProject) CreateLogStore(name string, ttl, shardCnt int) (err error) return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "POST", "/logstores", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to create logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("POST", "/logstores", h, body) return } // DeleteLogStore deletes a logstore according by logstore name. func (p *LogProject) DeleteLogStore(name string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - r, err := request(p, "DELETE", "/logstores/"+name, h, nil) - if err != nil { - return - } - - body, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + h := createStandardHeaders(0) + _, err = p.sendRequest("DELETE", "/logstores/"+name, h, nil) return } @@ -228,73 +185,26 @@ func (p *LogProject) UpdateLogStore(name string, ttl, shardCnt int) (err error) return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "PUT", "/logstores", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update logstore") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("PUT", "/logstores", h, body) return } // ListMachineGroup returns machine group name list and the total number of machine groups. // The offset starts from 0 and the size is the max number of machine groups could be returned. func (p *LogProject) ListMachineGroup(offset, size int) (m []string, total int, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) if size <= 0 { size = 500 } uri := fmt.Sprintf("/machinegroups?offset=%v&size=%v", offset, size) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to list machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Body struct { MachineGroups []string Count int @@ -309,39 +219,18 @@ func (p *LogProject) ListMachineGroup(offset, size int) (m []string, total int, m = body.MachineGroups total = body.Total - return } // GetMachineGroup retruns machine group according by machine group name. func (p *LogProject) GetMachineGroup(name string) (m *MachineGroup, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) - r, err := request(p, "GET", "/machinegroups/"+name, h, nil) + buf, err := p.sendRequest("GET", "/machinegroups/"+name, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to get machine group:%v", name) - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - m = &MachineGroup{} err = json.Unmarshal(buf, m) if err != nil { @@ -358,35 +247,8 @@ func (p *LogProject) CreateMachineGroup(m *MachineGroup) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "POST", "/machinegroups", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to create machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("POST", "/machinegroups", h, body) return } @@ -397,104 +259,33 @@ func (p *LogProject) UpdateMachineGroup(m *MachineGroup) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "PUT", "/machinegroups/"+m.Name, h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("PUT", "/machinegroups/"+m.Name, h, body) return } // DeleteMachineGroup deletes machine group according machine group name. func (p *LogProject) DeleteMachineGroup(name string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - r, err := request(p, "DELETE", "/machinegroups/"+name, h, nil) - if err != nil { - return - } - - body, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + h := createStandardHeaders(0) + _, err = p.sendRequest("DELETE", "/machinegroups/"+name, h, nil) return } // ListConfig returns config names list and the total number of configs. // The offset starts from 0 and the size is the max number of configs could be returned. func (p *LogProject) ListConfig(offset, size int) (cfgNames []string, total int, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) if size <= 0 { size = 100 } uri := fmt.Sprintf("/configs?offset=%v&size=%v", offset, size) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Body struct { Total int Configs []string @@ -513,33 +304,13 @@ func (p *LogProject) ListConfig(offset, size int) (cfgNames []string, total int, // GetConfig returns config according by config name. func (p *LogProject) GetConfig(name string) (c *LogConfig, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) - r, err := request(p, "GET", "/configs/"+name, h, nil) + buf, err := p.sendRequest("GET", "/configs/"+name, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - c = &LogConfig{} err = json.Unmarshal(buf, c) if err != nil { @@ -556,35 +327,8 @@ func (p *LogProject) UpdateConfig(c *LogConfig) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "PUT", "/configs/"+c.Name, h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("PUT", "/configs/"+c.Name, h, body) return } @@ -595,99 +339,28 @@ func (p *LogProject) CreateConfig(c *LogConfig) (err error) { return } - h := map[string]string{ - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), - "Content-Type": "application/json", - "Accept-Encoding": "deflate", // TODO: support lz4 - } - - r, err := request(p, "POST", "/configs", h, body) - if err != nil { - return - } - - body, err = io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to update config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - + h := createStandardHeaders(len(body)) + _, err = p.sendRequest("POST", "/configs", h, body) return } // DeleteConfig deletes a config according by config name. func (p *LogProject) DeleteConfig(name string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } - - r, err := request(p, "DELETE", "/configs/"+name, h, nil) - if err != nil { - return - } - - body, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(body, errMsg) - if err != nil { - err = fmt.Errorf("failed to delete config") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + h := createStandardHeaders(0) + _, err = p.sendRequest("DELETE", "/configs/"+name, h, nil) return } // GetAppliedMachineGroups returns applied machine group names list according config name. func (p *LogProject) GetAppliedMachineGroups(confName string) (groupNames []string, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/configs/%v/machinegroups", confName) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to get applied machine groups") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Body struct { Count int Machinegroups []string @@ -705,34 +378,14 @@ func (p *LogProject) GetAppliedMachineGroups(confName string) (groupNames []stri // GetAppliedConfigs returns applied config names list according machine group name groupName. func (p *LogProject) GetAppliedConfigs(groupName string) (confNames []string, err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/machinegroups/%v/configs", groupName) - r, err := request(p, "GET", uri, h, nil) + buf, err := p.sendRequest("GET", uri, h, nil) if err != nil { return } - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to applied configs") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } - type Cfg struct { Count int `json:"count"` Configs []string `json:"configs"` @@ -750,64 +403,18 @@ func (p *LogProject) GetAppliedConfigs(groupName string) (confNames []string, er // ApplyConfigToMachineGroup applies config to machine group. func (p *LogProject) ApplyConfigToMachineGroup(confName, groupName string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName) - r, err := request(p, "PUT", uri, h, nil) - if err != nil { - return - } - - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to apply config to machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + _, err = p.sendRequest("PUT", uri, h, nil) return } // RemoveConfigFromMachineGroup removes config from machine group. func (p *LogProject) RemoveConfigFromMachineGroup(confName, groupName string) (err error) { - h := map[string]string{ - "x-sls-bodyrawsize": "0", - } + h := createStandardHeaders(0) uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName) - r, err := request(p, "DELETE", uri, h, nil) - if err != nil { - return - } - - buf, err := io.ReadAll(r.Body) - if err != nil { - return - } - - if r.StatusCode != http.StatusOK { - errMsg := &errorMessage{} - err = json.Unmarshal(buf, errMsg) - if err != nil { - err = fmt.Errorf("failed to remove config from machine group") - dump, _ := httputil.DumpResponse(r, true) - fmt.Printf("%s\n", dump) - return - } - err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) - return - } + _, err = p.sendRequest("DELETE", uri, h, nil) return } diff --git a/core/logs/alils/log_store.go b/core/logs/alils/log_store.go index e699b832..ac19b6ed 100755 --- a/core/logs/alils/log_store.go +++ b/core/logs/alils/log_store.go @@ -32,7 +32,7 @@ type Shard struct { // ListShards returns shard id list of this logstore. func (s *LogStore) ListShards() (shardIDs []int, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", } uri := fmt.Sprintf("/logstores/%v/shards", s.Name) @@ -87,8 +87,8 @@ func (s *LogStore) PutLogs(lg *LogGroup) (err error) { } h := map[string]string{ - "x-sls-compresstype": "lz4", - "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), + "x-log-compresstype": "lz4", + "x-log-bodyrawsize": fmt.Sprintf("%v", len(body)), "Content-Type": "application/x-protobuf", } @@ -123,7 +123,7 @@ func (s *LogStore) PutLogs(lg *LogGroup) (err error) { // For more detail please read: http://gitlab.alibaba-inc.com/sls/doc/blob/master/api/shard.md#logstore func (s *LogStore) GetCursor(shardID int, from string) (cursor string, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", } uri := fmt.Sprintf("/logstores/%v/shards/%v?type=cursor&from=%v", @@ -172,7 +172,7 @@ func (s *LogStore) GetLogsBytes(shardID int, cursor string, logGroupMaxCount int) (out []byte, nextCursor string, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", "Accept": "application/x-protobuf", "Accept-Encoding": "lz4", } @@ -203,9 +203,9 @@ func (s *LogStore) GetLogsBytes(shardID int, cursor string, return } - v, ok := r.Header["X-Sls-Compresstype"] + v, ok := r.Header["X-Log-Compresstype"] if !ok || len(v) == 0 { - err = fmt.Errorf("can't find 'x-sls-compresstype' header") + err = fmt.Errorf("can't find 'x-log-compresstype' header") return } if v[0] != "lz4" { @@ -213,16 +213,16 @@ func (s *LogStore) GetLogsBytes(shardID int, cursor string, return } - v, ok = r.Header["X-Sls-Cursor"] + v, ok = r.Header["X-Log-Cursor"] if !ok || len(v) == 0 { - err = fmt.Errorf("can't find 'x-sls-cursor' header") + err = fmt.Errorf("can't find 'x-log-cursor' header") return } nextCursor = v[0] - v, ok = r.Header["X-Sls-Bodyrawsize"] + v, ok = r.Header["X-Log-Bodyrawsize"] if !ok || len(v) == 0 { - err = fmt.Errorf("can't find 'x-sls-bodyrawsize' header") + err = fmt.Errorf("can't find 'x-log-bodyrawsize' header") return } bodyRawSize, err := strconv.Atoi(v[0]) diff --git a/core/logs/alils/machine_group.go b/core/logs/alils/machine_group.go index b00c480e..d47bd985 100755 --- a/core/logs/alils/machine_group.go +++ b/core/logs/alils/machine_group.go @@ -45,7 +45,7 @@ type MachineList struct { // ListMachines returns the machine list of this machine group. func (m *MachineGroup) ListMachines() (ms []*Machine, total int, err error) { h := map[string]string{ - "x-sls-bodyrawsize": "0", + "x-log-bodyrawsize": "0", } uri := fmt.Sprintf("/machinegroups/%v/machines", m.Name) diff --git a/core/logs/alils/request.go b/core/logs/alils/request.go index dce4dccd..b557c6dc 100755 --- a/core/logs/alils/request.go +++ b/core/logs/alils/request.go @@ -11,17 +11,17 @@ import ( func request(project *LogProject, method, uri string, headers map[string]string, body []byte) (resp *http.Response, err error) { - // The caller should provide 'x-sls-bodyrawsize' header - if _, ok := headers["x-sls-bodyrawsize"]; !ok { - err = fmt.Errorf("can't find 'x-sls-bodyrawsize' header") + // The caller should provide 'x-log-bodyrawsize' header + if _, ok := headers["x-log-bodyrawsize"]; !ok { + err = fmt.Errorf("can't find 'x-log-bodyrawsize' header") return } // SLS public request headers headers["Host"] = project.Name + "." + project.Endpoint headers["Date"] = nowRFC1123() - headers["x-sls-apiversion"] = version - headers["x-sls-signaturemethod"] = signatureMethod + headers["x-log-apiversion"] = version + headers["x-log-signaturemethod"] = signatureMethod if body != nil { bodyMD5 := fmt.Sprintf("%X", md5.Sum(body)) headers["Content-MD5"] = bodyMD5 @@ -33,12 +33,12 @@ func request(project *LogProject, method, uri string, headers map[string]string, } // Calc Authorization - // Authorization = "SLS :" + // Authorization = "LOG :" digest, err := signature(project, method, uri, headers) if err != nil { return } - auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyID, digest) + auth := fmt.Sprintf("LOG %v:%v", project.AccessKeyID, digest) headers["Authorization"] = auth // Initialize http request diff --git a/core/logs/alils/signature.go b/core/logs/alils/signature.go index 2d611307..1d0bb7d5 100755 --- a/core/logs/alils/signature.go +++ b/core/logs/alils/signature.go @@ -20,92 +20,133 @@ func nowRFC1123() string { return time.Now().In(gmtLoc).Format(time.RFC1123) } -// signature calculates a request's signature digest. +// signature calculates a request's signature digest func signature(project *LogProject, method, uri string, headers map[string]string) (digest string, err error) { - var contentMD5, contentType, date, canoHeaders, canoResource string + + // 1. Extract basic header information + contentMD5 := getHeaderSafe(headers, "Content-MD5") + contentType := getHeaderSafe(headers, "Content-Type") + + date, ok := headers["Date"] + if !ok { + return "", fmt.Errorf("Can't find 'Date' header") + } + + // 2. Calculate CanonicalizedSLSHeaders + canoHeaders := buildCanonicalHeaders(headers) + + // 3. Calculate CanonicalizedResource + canoResource, err := buildCanonicalResource(uri) + if err != nil { + return "", err + } + + // 4. Build the signature string + signStr := buildSignString(method, contentMD5, contentType, date, canoHeaders, canoResource) + + // 5. Calculate HMAC-SHA1 signature and encode with Base64 + // Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret)) + return calculateHmacSha1(signStr, project.AccessKeySecret) +} + +// getHeaderSafe safely retrieves a header value, returns empty string if not exists +func getHeaderSafe(headers map[string]string, key string) string { + if val, ok := headers[key]; ok { + return val + } + return "" +} + +// buildCanonicalHeaders constructs normalized SLS headers +func buildCanonicalHeaders(headers map[string]string) string { + slsHeaders := make(map[string]string) var slsHeaderKeys sort.StringSlice + // Extract headers prefixed with x-log- and x-acs- + for k, v := range headers { + l := strings.TrimSpace(strings.ToLower(k)) + if strings.HasPrefix(l, "x-log-") || strings.HasPrefix(l, "x-acs-") { + slsHeaders[l] = strings.TrimSpace(v) + slsHeaderKeys = append(slsHeaderKeys, l) + } + } + + // Sort headers alphabetically + sort.Sort(slsHeaderKeys) + + // Build the canonical header string + var result strings.Builder + for i, k := range slsHeaderKeys { + result.WriteString(k) + result.WriteString(":") + result.WriteString(slsHeaders[k]) + if i+1 < len(slsHeaderKeys) { + result.WriteString("\n") + } + } + + return result.String() +} + +// buildCanonicalResource constructs a normalized resource string +func buildCanonicalResource(uri string) (string, error) { + u, err := url.Parse(uri) + if err != nil { + return "", err + } + + result := u.Path + + // Process query parameters + if u.RawQuery != "" { + var keys sort.StringSlice + vals := u.Query() + + for k := range vals { + keys = append(keys, k) + } + + sort.Sort(keys) + result += "?" + + for i, k := range keys { + if i > 0 { + result += "&" + } + + for _, v := range vals[k] { + result += k + "=" + v + } + } + } + + return result, nil +} + +// buildSignString constructs the complete signature string +func buildSignString(method, contentMD5, contentType, date, canoHeaders, canoResource string) string { // SignString = VERB + "\n" // + CONTENT-MD5 + "\n" // + CONTENT-TYPE + "\n" // + DATE + "\n" // + CanonicalizedSLSHeaders + "\n" // + CanonicalizedResource - - if val, ok := headers["Content-MD5"]; ok { - contentMD5 = val - } - - if val, ok := headers["Content-Type"]; ok { - contentType = val - } - - date, ok := headers["Date"] - if !ok { - err = fmt.Errorf("Can't find 'Date' header") - return - } - - // Calc CanonicalizedSLSHeaders - slsHeaders := make(map[string]string, len(headers)) - for k, v := range headers { - l := strings.TrimSpace(strings.ToLower(k)) - if strings.HasPrefix(l, "x-sls-") { - slsHeaders[l] = strings.TrimSpace(v) - slsHeaderKeys = append(slsHeaderKeys, l) - } - } - - sort.Sort(slsHeaderKeys) - for i, k := range slsHeaderKeys { - canoHeaders += k + ":" + slsHeaders[k] - if i+1 < len(slsHeaderKeys) { - canoHeaders += "\n" - } - } - - // Calc CanonicalizedResource - u, err := url.Parse(uri) - if err != nil { - return - } - - canoResource += url.QueryEscape(u.Path) - if u.RawQuery != "" { - var keys sort.StringSlice - - vals := u.Query() - for k := range vals { - keys = append(keys, k) - } - - sort.Sort(keys) - canoResource += "?" - for i, k := range keys { - if i > 0 { - canoResource += "&" - } - - for _, v := range vals[k] { - canoResource += k + "=" + v - } - } - } - - signStr := method + "\n" + + return method + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n" + canoHeaders + "\n" + canoResource - - // Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret)) - mac := hmac.New(sha1.New, []byte(project.AccessKeySecret)) - _, err = mac.Write([]byte(signStr)) - if err != nil { - return - } - digest = base64.StdEncoding.EncodeToString(mac.Sum(nil)) - return +} + +// calculateHmacSha1 calculates the HMAC-SHA1 signature and encodes it with Base64 +func calculateHmacSha1(signStr, secret string) (string, error) { + mac := hmac.New(sha1.New, []byte(secret)) + _, err := mac.Write([]byte(signStr)) + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil }