File: request_compression.go

package info (click to toggle)
golang-github-aws-smithy-go 1.19.0-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 2,680 kB
  • sloc: java: 15,917; xml: 166; sh: 131; makefile: 66
file content (103 lines) | stat: -rw-r--r-- 3,330 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Package requestcompression implements runtime support for smithy-modeled
// request compression.
//
// This package is designated as private and is intended for use only by the
// smithy client runtime. The exported API therein is not considered stable and
// is subject to breaking changes without notice.
package requestcompression

import (
	"bytes"
	"context"
	"fmt"
	"github.com/aws/smithy-go/middleware"
	"github.com/aws/smithy-go/transport/http"
	"io"
)

const MaxRequestMinCompressSizeBytes = 10485760

// Enumeration values for supported compress Algorithms.
const (
	GZIP = "gzip"
)

type compressFunc func(io.Reader) ([]byte, error)

var allowedAlgorithms = map[string]compressFunc{
	GZIP: gzipCompress,
}

// AddRequestCompression add requestCompression middleware to op stack
func AddRequestCompression(stack *middleware.Stack, disabled bool, minBytes int64, algorithms []string) error {
	return stack.Serialize.Add(&requestCompression{
		disableRequestCompression:   disabled,
		requestMinCompressSizeBytes: minBytes,
		compressAlgorithms:          algorithms,
	}, middleware.After)
}

type requestCompression struct {
	disableRequestCompression   bool
	requestMinCompressSizeBytes int64
	compressAlgorithms          []string
}

// ID returns the ID of the middleware
func (m requestCompression) ID() string {
	return "RequestCompression"
}

// HandleSerialize gzip compress the request's stream/body if enabled by config fields
func (m requestCompression) HandleSerialize(
	ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler,
) (
	out middleware.SerializeOutput, metadata middleware.Metadata, err error,
) {
	if m.disableRequestCompression {
		return next.HandleSerialize(ctx, in)
	}
	// still need to check requestMinCompressSizeBytes in case it is out of range after service client config
	if m.requestMinCompressSizeBytes < 0 || m.requestMinCompressSizeBytes > MaxRequestMinCompressSizeBytes {
		return out, metadata, fmt.Errorf("invalid range for min request compression size bytes %d, must be within 0 and 10485760 inclusively", m.requestMinCompressSizeBytes)
	}

	req, ok := in.Request.(*http.Request)
	if !ok {
		return out, metadata, fmt.Errorf("unknown request type %T", req)
	}

	for _, algorithm := range m.compressAlgorithms {
		compressFunc := allowedAlgorithms[algorithm]
		if compressFunc != nil {
			if stream := req.GetStream(); stream != nil {
				size, found, err := req.StreamLength()
				if err != nil {
					return out, metadata, fmt.Errorf("error while finding request stream length, %v", err)
				} else if !found || size < m.requestMinCompressSizeBytes {
					return next.HandleSerialize(ctx, in)
				}

				compressedBytes, err := compressFunc(stream)
				if err != nil {
					return out, metadata, fmt.Errorf("failed to compress request stream, %v", err)
				}

				var newReq *http.Request
				if newReq, err = req.SetStream(bytes.NewReader(compressedBytes)); err != nil {
					return out, metadata, fmt.Errorf("failed to set request stream, %v", err)
				}
				*req = *newReq

				if val := req.Header.Get("Content-Encoding"); val != "" {
					req.Header.Set("Content-Encoding", fmt.Sprintf("%s, %s", val, algorithm))
				} else {
					req.Header.Set("Content-Encoding", algorithm)
				}
			}
			break
		}
	}

	return next.HandleSerialize(ctx, in)
}