66
77#include "example.gen.h"
88
9+ #ifndef SMOKE_NO_CURL_TRANSPORT
910#include <curl/curl.h>
11+ #endif
1012#include <cjson/cJSON.h>
1113#include <limits.h>
1214#include <math.h>
1315#include <stdio.h>
1416
17+ #ifndef SMOKE_NO_CURL_TRANSPORT
1518typedef struct {
1619 char * data ;
1720 size_t len ;
1821 size_t cap ;
22+ size_t max_response_bytes ;
1923} smoke_buffer ;
24+ #endif
2025
2126#if defined(__GNUC__ ) || defined(__clang__ )
2227#define SMOKE_JSON_UNUSED __attribute__((unused))
@@ -133,8 +138,16 @@ static void smoke_set_error(
133138 error -> cause = cause ? smoke_strdup (cause ) : NULL ;
134139}
135140
136- static int smoke_buffer_grow (smoke_buffer * buf , size_t need ) {
141+ #ifndef SMOKE_NO_CURL_TRANSPORT
142+ static size_t smoke_default_max_response_bytes (void ) {
143+ return (size_t )1024 * 1024 ;
144+ }
145+
146+ static int smoke_buffer_grow (smoke_buffer * buf , size_t need , size_t max_response_bytes ) {
147+ size_t max_cap ;
137148 if (!buf ) return 0 ;
149+ max_cap = max_response_bytes == SIZE_MAX ? SIZE_MAX : max_response_bytes + 1 ;
150+ if (need > max_cap ) return 0 ;
138151 if (buf -> cap >= need ) return 1 ;
139152 size_t new_cap = buf -> cap ? buf -> cap : 1024 ;
140153 while (new_cap < need ) {
@@ -144,6 +157,9 @@ static int smoke_buffer_grow(smoke_buffer *buf, size_t need) {
144157 }
145158 new_cap *= 2 ;
146159 }
160+ if (new_cap > max_cap ) {
161+ new_cap = max_cap ;
162+ }
147163 char * next = (char * )realloc (buf -> data , new_cap );
148164 if (!next ) return 0 ;
149165 buf -> data = next ;
@@ -154,12 +170,18 @@ static int smoke_buffer_grow(smoke_buffer *buf, size_t need) {
154170static size_t smoke_write_cb (char * ptr , size_t size , size_t nmemb , void * userdata ) {
155171 smoke_buffer * buf = (smoke_buffer * )userdata ;
156172 size_t n ;
173+ size_t need ;
174+ size_t max_response_bytes ;
157175
158176 if (!buf ) return 0 ;
159177 if (size != 0 && nmemb > SIZE_MAX / size ) return 0 ;
160178 n = size * nmemb ;
179+ if (n > SIZE_MAX - 1 ) return 0 ;
161180 if (buf -> len > SIZE_MAX - n - 1 ) return 0 ;
162- if (!smoke_buffer_grow (buf , buf -> len + n + 1 )) return 0 ;
181+ need = buf -> len + n + 1 ;
182+ max_response_bytes = buf -> max_response_bytes > 0 ? buf -> max_response_bytes : smoke_default_max_response_bytes ();
183+ if (need - 1 > max_response_bytes ) return 0 ;
184+ if (!smoke_buffer_grow (buf , need , max_response_bytes )) return 0 ;
163185 memcpy (buf -> data + buf -> len , ptr , n );
164186 buf -> len += n ;
165187 buf -> data [buf -> len ] = '\0' ;
@@ -378,6 +400,7 @@ static int smoke_http_send_request(
378400 const char * bearer_token ,
379401 const struct curl_slist * default_headers ,
380402 long timeout_ms ,
403+ size_t max_response_bytes ,
381404 smoke_http_response * response ,
382405 smoke_error * error
383406) {
@@ -396,6 +419,7 @@ static int smoke_http_send_request(
396419 }
397420 smoke_http_response_init (& result );
398421 memset (& buf , 0 , sizeof (buf ));
422+ buf .max_response_bytes = max_response_bytes > 0 ? max_response_bytes : smoke_default_max_response_bytes ();
399423
400424 curl = curl_easy_init ();
401425 if (!curl ) {
@@ -458,6 +482,15 @@ static int smoke_http_send_request(
458482 }
459483 return rc ;
460484}
485+ #else
486+ int smoke_runtime_init (smoke_error * error ) {
487+ (void )error ;
488+ return 0 ;
489+ }
490+
491+ void smoke_runtime_cleanup (void ) {
492+ }
493+ #endif
461494
462495static void smoke_parse_rpc_error (const char * body , long http_status , smoke_error * error ) {
463496 cJSON * error_name = NULL ;
@@ -931,11 +964,13 @@ int smoke_smoke_echo_parse_response(
931964 return rc ;
932965}
933966
967+ #ifndef SMOKE_NO_CURL_TRANSPORT
934968struct smoke_smoke_client {
935969 char * base_url ;
936970 char * bearer_token ;
937971 struct curl_slist * default_headers ;
938972 long timeout_ms ;
973+ size_t max_response_bytes ;
939974};
940975
941976static void smoke_smoke_client_free_config_parts (char * * bearer_token , struct curl_slist * * default_headers ) {
@@ -953,23 +988,29 @@ static void smoke_smoke_client_reset_config(smoke_smoke_client *client) {
953988 if (!client ) return ;
954989 smoke_smoke_client_free_config_parts (& client -> bearer_token , & client -> default_headers );
955990 client -> timeout_ms = 10000L ;
991+ client -> max_response_bytes = (size_t )1024 * 1024 ;
956992}
957993
958994static int smoke_smoke_client_build_config (
959995 const smoke_client_options * options ,
960996 char * * bearer_token ,
961997 struct curl_slist * * default_headers ,
962- long * timeout_ms
998+ long * timeout_ms ,
999+ size_t * max_response_bytes
9631000) {
964- if (!bearer_token || !default_headers || !timeout_ms ) return 0 ;
1001+ if (!bearer_token || !default_headers || !timeout_ms || ! max_response_bytes ) return 0 ;
9651002 * bearer_token = NULL ;
9661003 * default_headers = NULL ;
9671004 * timeout_ms = 10000L ;
1005+ * max_response_bytes = (size_t )1024 * 1024 ;
9681006 if (!options ) return 1 ;
9691007
9701008 if (options -> timeout_ms > 0 ) {
9711009 * timeout_ms = options -> timeout_ms ;
9721010 }
1011+ if (options -> max_response_bytes > 0 ) {
1012+ * max_response_bytes = options -> max_response_bytes ;
1013+ }
9731014
9741015 if (options -> bearer_token ) {
9751016 * bearer_token = smoke_strdup (options -> bearer_token );
@@ -991,23 +1032,26 @@ static int smoke_smoke_client_build_config(
9911032fail :
9921033 smoke_smoke_client_free_config_parts (bearer_token , default_headers );
9931034 * timeout_ms = 10000L ;
1035+ * max_response_bytes = (size_t )1024 * 1024 ;
9941036 return 0 ;
9951037}
9961038
9971039int smoke_smoke_client_configure (smoke_smoke_client * client , const smoke_client_options * options ) {
9981040 char * next_bearer_token = NULL ;
9991041 struct curl_slist * next_default_headers = NULL ;
10001042 long next_timeout_ms = 10000L ;
1043+ size_t next_max_response_bytes = (size_t )1024 * 1024 ;
10011044
10021045 if (!client ) return 0 ;
1003- if (!smoke_smoke_client_build_config (options , & next_bearer_token , & next_default_headers , & next_timeout_ms )) {
1046+ if (!smoke_smoke_client_build_config (options , & next_bearer_token , & next_default_headers , & next_timeout_ms , & next_max_response_bytes )) {
10041047 return 0 ;
10051048 }
10061049
10071050 smoke_smoke_client_reset_config (client );
10081051 client -> bearer_token = next_bearer_token ;
10091052 client -> default_headers = next_default_headers ;
10101053 client -> timeout_ms = next_timeout_ms ;
1054+ client -> max_response_bytes = next_max_response_bytes ;
10111055 return 1 ;
10121056}
10131057
@@ -1056,10 +1100,47 @@ int smoke_smoke_client_send_prepared_request(
10561100 client -> bearer_token ,
10571101 client -> default_headers ,
10581102 client -> timeout_ms ,
1103+ client -> max_response_bytes ,
10591104 response ,
10601105 error
10611106 );
10621107}
1108+ #else
1109+ struct smoke_smoke_client {
1110+ int placeholder ;
1111+ };
1112+
1113+ smoke_smoke_client * smoke_smoke_client_create (const char * base_url , const smoke_client_options * options ) {
1114+ smoke_smoke_client * client ;
1115+ (void )base_url ;
1116+ (void )options ;
1117+ client = (smoke_smoke_client * )calloc (1 , sizeof (* client ));
1118+ return client ;
1119+ }
1120+
1121+ void smoke_smoke_client_destroy (smoke_smoke_client * client ) {
1122+ free (client );
1123+ }
1124+
1125+ int smoke_smoke_client_configure (smoke_smoke_client * client , const smoke_client_options * options ) {
1126+ (void )options ;
1127+ return client ? 1 : 0 ;
1128+ }
1129+
1130+ int smoke_smoke_client_send_prepared_request (
1131+ smoke_smoke_client * client ,
1132+ const smoke_prepared_request * request ,
1133+ smoke_http_response * response ,
1134+ smoke_error * error
1135+ ) {
1136+ if (!client || !request || !response ) {
1137+ smoke_set_error (error , 0 , 0 , "ClientError" , "client, request, and response must be non-NULL" , NULL );
1138+ return -1 ;
1139+ }
1140+ smoke_set_error (error , 0 , 0 , "TransportError" , "built-in curl transport is disabled" , NULL );
1141+ return -1 ;
1142+ }
1143+ #endif
10631144int smoke_smoke_echo (
10641145 smoke_smoke_client * client ,
10651146 const smoke_smoke_echo_request * request ,
0 commit comments