-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
service/cloudwatch: Add helper for GZIP request payload (#4425)
Adds a new helper, `WithGzipRequest` to compress the request payload before it is sent. May not be supported by all API operations. See service's API Reference docs for details about operations that are supported.
- Loading branch information
Showing
5 changed files
with
156 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
### SDK Features | ||
|
||
### SDK Enhancements | ||
|
||
* `service/cloudwatch`: Add helper to send request payload as GZIP content encoding | ||
* Adds a new helper, `WithGzipRequest` to the `cloudwatch` package. The helper will configure the payload to be sent as `content-encoding: gzip`. It is supported by operations like `PutMetricData`. See the service's API Reference documentation for other operations supported. | ||
### SDK Bugs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package gzip | ||
|
||
import ( | ||
"bytes" | ||
"compress/gzip" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"strconv" | ||
|
||
"github.com/aws/aws-sdk-go/aws/request" | ||
) | ||
|
||
// NewGzipRequestHandler provides a named request handler that compresses the | ||
// request payload. Add this to enable GZIP compression for a client. | ||
// | ||
// Known to work with Amazon CloudWatch's PutMetricData operation. | ||
// https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html | ||
func NewGzipRequestHandler() request.NamedHandler { | ||
return request.NamedHandler{ | ||
Name: "GzipRequestHandler", | ||
Fn: gzipRequestHandler, | ||
} | ||
} | ||
|
||
func gzipRequestHandler(req *request.Request) { | ||
compressedBytes, err := compress(req.Body) | ||
if err != nil { | ||
req.Error = fmt.Errorf("failed to compress request payload, %v", err) | ||
return | ||
} | ||
|
||
req.HTTPRequest.Header.Set("Content-Encoding", "gzip") | ||
req.HTTPRequest.Header.Set("Content-Length", strconv.Itoa(len(compressedBytes))) | ||
|
||
req.SetBufferBody(compressedBytes) | ||
} | ||
|
||
func compress(input io.Reader) ([]byte, error) { | ||
var b bytes.Buffer | ||
w, err := gzip.NewWriterLevel(&b, gzip.BestCompression) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create gzip writer, %v", err) | ||
} | ||
|
||
inBytes, err := ioutil.ReadAll(input) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed read payload to compress, %v", err) | ||
} | ||
|
||
if _, err = w.Write(inBytes); err != nil { | ||
return nil, fmt.Errorf("failed to write payload to be compressed, %v", err) | ||
} | ||
if err = w.Close(); err != nil { | ||
return nil, fmt.Errorf("failed to flush payload being compressed, %v", err) | ||
} | ||
|
||
return b.Bytes(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package gzip | ||
|
||
import ( | ||
"bytes" | ||
"io/ioutil" | ||
"net/http" | ||
"strconv" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws/request" | ||
) | ||
|
||
func TestGzipRequestHandler(t *testing.T) { | ||
handler := NewGzipRequestHandler() | ||
|
||
req := &request.Request{} | ||
uncompressed := "asdfasdfasdf" | ||
req.Body = strings.NewReader(uncompressed) | ||
httpReq, err := http.NewRequest("POST", "http://localhost", strings.NewReader(uncompressed)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
req.HTTPRequest = httpReq | ||
|
||
expectCompressed, err := compress(strings.NewReader(uncompressed)) | ||
if err != nil { | ||
t.Fatalf("expect no error, got %v", err) | ||
} | ||
|
||
handler.Fn(req) | ||
if req.Error != nil { | ||
t.Fatalf("expect no error, got %v", req.Error) | ||
} | ||
|
||
if e, a := "gzip", req.HTTPRequest.Header.Get("Content-Encoding"); e != a { | ||
t.Errorf("expect %v content-encoding, got %v", e, a) | ||
} | ||
if e, a := strconv.Itoa(len(expectCompressed)), req.HTTPRequest.Header.Get("Content-Length"); e != a { | ||
t.Errorf("expect %v content-length, got %v", e, a) | ||
} | ||
|
||
actualCompressed, err := ioutil.ReadAll(req.Body) | ||
if err != nil { | ||
t.Fatalf("ReadAll request body failed, %v", err) | ||
} | ||
if !bytes.Equal(expectCompressed, actualCompressed) { | ||
t.Errorf("expect new body to equal expectCompressed") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package cloudwatch | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/aws/request" | ||
"github.com/aws/aws-sdk-go/internal/encoding/gzip" | ||
) | ||
|
||
// WithGzipRequest is a request.Option that adds a request handler to the Build | ||
// stage of the operation's pipeline that will content-encoding GZIP the | ||
// request payload before sending it to the API. This will buffer the request | ||
// payload in memory, GZIP it, and reassign the GZIP'ed payload as the new | ||
// request payload. | ||
// | ||
// GZIP may not be supported by all API operations. See API's documentation for | ||
// the operation your using to see if GZIP request payload is supported. | ||
// https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html | ||
func WithGzipRequest(r *request.Request) { | ||
r.Handlers.Build.PushBackNamed(gzip.NewGzipRequestHandler()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//go:build go1.7 | ||
// +build go1.7 | ||
|
||
package cloudwatch_test | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/aws/aws-sdk-go/aws/session" | ||
"github.com/aws/aws-sdk-go/awstesting/unit" | ||
"github.com/aws/aws-sdk-go/service/cloudwatch" | ||
) | ||
|
||
func ExampleCloudWatch_PutMetricDataWithContext_withGzipRequest() { | ||
client := cloudwatch.New(sess) | ||
|
||
// The WithContext form of the operation methods accept request options. | ||
// The WithGzipRequest option will gzip the request payload before it is | ||
// sent. | ||
result, err := client.PutMetricDataWithContext(context.TODO(), params, cloudwatch.WithGzipRequest) | ||
|
||
_, _ = result, err | ||
} | ||
|
||
var params *cloudwatch.PutMetricDataInput | ||
var sess *session.Session = unit.Session |