@@ -2,6 +2,7 @@ package gateway
22
33import (
44 "bytes"
5+ "compress/gzip"
56 "context"
67 "encoding/json"
78 "errors"
3940 InvalidProof ErrorCode = "StarknetErrorCode.INVALID_PROOF"
4041)
4142
43+ // Payload size threshold for Gzip compression. 1KB
44+ const gzipMinSize = 1024
45+
4246type Client struct {
4347 url string
4448 client * http.Client
@@ -79,13 +83,31 @@ func newTestServer(t *testing.T) *httptest.Server {
7983 assert .Equal (t , []string {"API_KEY" }, r .Header ["X-Throttling-Bypass" ])
8084 assert .Equal (t , []string {"Juno/v0.0.1-test Starknet Implementation" }, r .Header ["User-Agent" ])
8185
82- b , err := io .ReadAll (r .Body )
86+ var bodyReader io.Reader = r .Body
87+ isGzip := r .Header .Get ("Content-Encoding" ) == "gzip"
88+ if isGzip {
89+ gzReader , gzErr := gzip .NewReader (r .Body )
90+ if gzErr != nil {
91+ w .WriteHeader (http .StatusBadRequest )
92+ w .Write ([]byte (gzErr .Error ())) //nolint:errcheck // That's fine for the test server
93+ return
94+ }
95+ defer gzReader .Close ()
96+ bodyReader = gzReader
97+ }
98+
99+ b , err := io .ReadAll (bodyReader )
83100 if err != nil {
84101 w .WriteHeader (http .StatusBadRequest )
85102 w .Write ([]byte (err .Error ())) //nolint:errcheck
86103 return
87104 }
88105
106+ // Assert that large payloads are gzip-compressed
107+ if len (b ) >= gzipMinSize {
108+ assert .True (t , isGzip , "expected Content-Encoding: gzip for payload of size %d" , len (b ))
109+ }
110+
89111 // empty request: "{}"
90112 emptyReqLen := 4
91113 if string (b ) == "null" {
@@ -97,7 +119,8 @@ func newTestServer(t *testing.T) *httptest.Server {
97119 return
98120 }
99121
100- hash := new (felt.Felt ).SetBytes ([]byte ("random" ))
122+ // todo(rdr): consider using a random generator here
123+ hash := felt.FromBytes [felt.Felt ]([]byte ("random" ))
101124 resp := fmt .Sprintf ("{\" code\" : \" TRANSACTION_RECEIVED\" , \" transaction_hash\" : %q, \" address\" : %q}" , hash .String (), hash .String ())
102125 w .Write ([]byte (resp )) //nolint:errcheck
103126 }))
@@ -147,17 +170,25 @@ func (c *Client) post(ctx context.Context, url string, data any) ([]byte, error)
147170// doPost performs a "POST" http request with the given URL and a JSON payload derived from the provided data
148171// it returns response without additional error handling
149172func (c * Client ) doPost (ctx context.Context , url string , data any ) (* http.Response , error ) {
150- body , err := json .Marshal (data )
173+ jsonBody , err := json .Marshal (data )
174+ if err != nil {
175+ return nil , err
176+ }
177+
178+ bodyReader , compressed , err := prepareRequestBody (jsonBody )
151179 if err != nil {
152180 return nil , err
153181 }
154182
155- req , err := http .NewRequestWithContext (ctx , http .MethodPost , url , bytes . NewReader ( body ) )
183+ req , err := http .NewRequestWithContext (ctx , http .MethodPost , url , bodyReader )
156184 if err != nil {
157185 return nil , err
158186 }
159187
160188 req .Header .Set ("Content-Type" , "application/json" )
189+ if compressed {
190+ req .Header .Set ("Content-Encoding" , "gzip" )
191+ }
161192 if c .userAgent != "" {
162193 req .Header .Set ("User-Agent" , c .userAgent )
163194 }
@@ -173,6 +204,23 @@ func (c *Client) doPost(ctx context.Context, url string, data any) (*http.Respon
173204 return resp , nil
174205}
175206
207+ func prepareRequestBody (jsonBody []byte ) (io.Reader , bool , error ) {
208+ if len (jsonBody ) <= gzipMinSize {
209+ return bytes .NewReader (jsonBody ), false , nil
210+ }
211+
212+ var buf bytes.Buffer
213+ gzWriter := gzip .NewWriter (& buf )
214+ if _ , err := gzWriter .Write (jsonBody ); err != nil {
215+ return nil , false , fmt .Errorf ("writing gzip content: %w" , err )
216+ }
217+ if err := gzWriter .Close (); err != nil {
218+ return nil , false , fmt .Errorf ("closing gzip writer: %w" , err )
219+ }
220+
221+ return & buf , true , nil
222+ }
223+
176224type ErrorCode string
177225
178226type Error struct {
0 commit comments