@@ -23,7 +23,7 @@ typedef struct query_param {
2323 * @param ctx The Varnish context.
2424 * @param result The array of query parameters.
2525 * @param query_str The query string to tokenize.
26- * @return The number of query parameters.
26+ * @return The number of query parameters or -1 on error .
2727 */
2828static int tokenize_querystring (VRT_CTX , query_param_t * * result ,
2929 char * query_str ) {
@@ -72,6 +72,131 @@ static int tokenize_querystring(VRT_CTX, query_param_t **result,
7272 return no_param ;
7373}
7474
75+ /**
76+ * Tokenize and parse the filter parameters from params_in into filter_params
77+ * array.
78+ * @param ctx Varnish context
79+ * @param params_in Comma-separated filter parameter names
80+ * @param filter_params Output array of parameter names
81+ * @param num_filter_params Output number of parsed filter parameters
82+ * @return 0 on success, -1 on error
83+ */
84+ static int parse_filter_params (VRT_CTX , const char * params_in ,
85+ char * * filter_params ,
86+ size_t * num_filter_params ) {
87+ char * saveptr ;
88+ char * params_copy ;
89+ size_t count = 0 ;
90+
91+ if (params_in == NULL || * params_in == '\0' ) {
92+ * num_filter_params = 0 ;
93+ return 0 ;
94+ }
95+
96+ params_copy = WS_Copy (ctx -> ws , params_in , strlen (params_in ) + 1 );
97+ if (!params_copy ) {
98+ VRT_fail (ctx , "WS_Copy: params_copy: out of workspace" );
99+ return -1 ;
100+ }
101+
102+ for (char * filter_name = strtok_r (params_copy , "," , & saveptr ); filter_name ;
103+ filter_name = strtok_r (NULL , "," , & saveptr )) {
104+
105+ if (count >= MAX_FILTER_PARAMS ) {
106+ VRT_fail (ctx , "Exceeded maximum number of filter parameters" );
107+ return -1 ;
108+ }
109+ filter_params [count ++ ] = filter_name ;
110+ }
111+
112+ * num_filter_params = count ;
113+ return 0 ;
114+ }
115+
116+ /**
117+ * Determine if a given parameter should be included based on the exclude_params
118+ * flag and the list of filtered parameters.
119+ * @param param_name The query parameter name to check
120+ * @param filter_params Array of filter parameter names
121+ * @param num_filter_params Number of filter parameters
122+ * @param exclude_params If true, parameters in filter_params are excluded; else
123+ * included
124+ * @return 1 if parameter should be included, 0 otherwise
125+ */
126+ static int should_include_param (const char * param_name , char * * filter_params ,
127+ size_t num_filter_params ,
128+ VCL_BOOL exclude_params ) {
129+ int match = 0 ;
130+
131+ for (size_t i = 0 ; i < num_filter_params ; i ++ ) {
132+ if (strcmp (param_name , filter_params [i ]) == 0 ) {
133+ match = 1 ;
134+ break ;
135+ }
136+ }
137+
138+ return exclude_params ? !match : match ;
139+ }
140+
141+ /**
142+ * Rebuild the query string by including or excluding parameters as per filters.
143+ * @param ctx Varnish context
144+ * @param uri_base The portion of the URI before the query string
145+ * @param params The array of tokenized query parameters
146+ * @param param_count The number of query parameters
147+ * @param filter_params The array of filter parameter names
148+ * @param num_filter_params The number of filter parameters
149+ * @param exclude_params Whether to exclude or include params_in
150+ * @return A pointer to the rebuilt URI from workspace or NULL on error
151+ */
152+ static char * rebuild_query_string (VRT_CTX , const char * uri_base ,
153+ query_param_t * params , size_t param_count ,
154+ char * * filter_params ,
155+ size_t num_filter_params ,
156+ VCL_BOOL exclude_params ) {
157+ struct vsb * vsb = VSB_new_auto ();
158+ char sep = '?' ;
159+
160+ if (vsb == NULL ) {
161+ VRT_fail (ctx , "VSB_new_auto failed" );
162+ return NULL ;
163+ }
164+
165+ VSB_cat (vsb , uri_base );
166+
167+ for (size_t i = 0 ; i < param_count ; i ++ ) {
168+ query_param_t * current = & params [i ];
169+ if (should_include_param (current -> name , filter_params ,
170+ num_filter_params , exclude_params )) {
171+ if (current -> value && (* current -> value ) != '\0' ) {
172+ VSB_printf (vsb , "%c%s=%s" , sep , current -> name , current -> value );
173+ } else {
174+ // Parameter with no value
175+ VSB_printf (vsb , "%c%s" , sep , current -> name );
176+ }
177+ sep = '&' ;
178+ }
179+ }
180+
181+ if (VSB_finish (vsb ) != 0 ) {
182+ VRT_fail (ctx , "VSB_finish failed" );
183+ VSB_destroy (& vsb );
184+ return NULL ;
185+ }
186+
187+ const char * final_uri = VSB_data (vsb );
188+ size_t final_len = VSB_len (vsb );
189+ char * ws_uri = WS_Copy (ctx -> ws , final_uri , final_len + 1 );
190+ VSB_destroy (& vsb );
191+
192+ if (ws_uri == NULL ) {
193+ VRT_fail (ctx , "WS_Copy: out of workspace" );
194+ return NULL ;
195+ }
196+
197+ return ws_uri ;
198+ }
199+
75200/**
76201 * This function modifies the query string of a URL by including or excluding
77202 * query parameters based on the input parameters.
@@ -81,31 +206,19 @@ static int tokenize_querystring(VRT_CTX, query_param_t **result,
81206 * @param exclude_params If true, exclude the parameters in params_in. If false,
82207 * include the parameters in params_in.
83208 */
84- VCL_STRING vmod_modifyparams (VRT_CTX , VCL_STRING uri , VCL_STRING params_in ,
85- VCL_BOOL exclude_params ) {
86- char * saveptr ;
87- char * new_uri ;
88- char * new_uri_end ;
89- char * query_str ;
90- char * params ;
91- query_param_t * head ;
92- query_param_t * current ;
93- char * filter_params [MAX_FILTER_PARAMS ];
94- int num_filter_params = 0 ;
95- int i ;
96- int no_param ;
97- char sep = '?' ;
98-
209+ VCL_STRING
210+ vmod_modifyparams (VRT_CTX , VCL_STRING uri , VCL_STRING params_in ,
211+ VCL_BOOL exclude_params ) {
99212 CHECK_OBJ_NOTNULL (ctx , VRT_CTX_MAGIC );
100213
101- // Return if the URI is NULL.
214+ // Return if the URI is NULL
102215 if (uri == NULL ) {
103216 VRT_fail (ctx , "uri is NULL" );
104217 return NULL ;
105218 }
106219
107- // Check if there is a query string.
108- query_str = strchr (uri , '?' );
220+ // Check for existing query string
221+ char * query_str = strchr (uri , '?' );
109222 if (query_str == NULL ) {
110223 char * ws_uri = WS_Copy (ctx -> ws , uri , strlen (uri ) + 1 );
111224 if (ws_uri == NULL ) {
@@ -117,117 +230,65 @@ VCL_STRING vmod_modifyparams(VRT_CTX, VCL_STRING uri, VCL_STRING params_in,
117230 }
118231
119232 size_t base_uri_len = query_str - uri ;
120- size_t query_str_len = strlen (query_str + 1 ); // +1 to skip '?'
121- size_t new_uri_max_len =
122- base_uri_len + query_str_len + 2 ; // +2 for '?' and '\0'
123-
124- new_uri = WS_Alloc (ctx -> ws , new_uri_max_len );
125- if (new_uri == NULL ) {
126- VRT_fail (ctx , "WS_Alloc: new_uri: out of workspace" );
127- return NULL ;
128- }
233+ char base_uri [base_uri_len + 1 ];
234+ memcpy (base_uri , uri , base_uri_len );
235+ base_uri [base_uri_len ] = '\0' ;
129236
130- memcpy (new_uri , uri , base_uri_len );
131- new_uri [base_uri_len ] = '\0' ;
132- new_uri_end = new_uri + base_uri_len ;
133-
134- // Skip past the '?' to get the query string.
237+ // Move past the '?'
135238 query_str = query_str + 1 ;
136239
137- // If there are no query params, return the base URI from workspace.
240+ // If no query params, return base_uri
138241 if (* query_str == '\0' ) {
139- return new_uri ;
242+ char * ws_uri = WS_Copy (ctx -> ws , base_uri , base_uri_len + 1 );
243+ if (ws_uri == NULL ) {
244+ VRT_fail (ctx , "WS_Copy: out of workspace" );
245+ return NULL ;
246+ }
247+ return ws_uri ;
140248 }
141249
142- // If params_in is NULL or empty, remove all query params.
143250 if (params_in == NULL || * params_in == '\0' ) {
144- return new_uri ;
251+ char * ws_uri = WS_Copy (ctx -> ws , base_uri , base_uri_len + 1 );
252+ if (!ws_uri ) {
253+ VRT_fail (ctx , "WS_Copy: out of workspace" );
254+ return NULL ;
255+ }
256+ return ws_uri ;
145257 }
146258
147- // Copy the query string to the workspace.
148259 char * query_str_copy = WS_Copy (ctx -> ws , query_str , strlen (query_str ) + 1 );
149260 if (!query_str_copy ) {
150261 VRT_fail (ctx , "WS_Copy: query_str_copy: out of workspace" );
151262 return NULL ;
152263 }
153264
154- // Copy the params_in to the workspace.
155- params = WS_Copy (ctx -> ws , params_in , strlen (params_in ) + 1 );
156- if (!params ) {
157- VRT_fail (ctx , "WS_Copy: params: out of workspace" );
265+ // Parse filter parameters
266+ char * filter_params [MAX_FILTER_PARAMS ];
267+ size_t num_filter_params = 0 ;
268+ if (parse_filter_params (ctx , params_in , filter_params , & num_filter_params ) <
269+ 0 ) {
158270 return NULL ;
159271 }
160272
161- // Tokenize params_in into filter_params array.
162- num_filter_params = 0 ;
163- for (char * filter_name = strtok_r (params , "," , & saveptr ); filter_name ;
164- filter_name = strtok_r (NULL , "," , & saveptr )) {
165- if (num_filter_params >= MAX_FILTER_PARAMS ) {
166- VRT_fail (ctx , "Exceeded maximum number of filter parameters" );
167- return NULL ;
168- }
169- filter_params [num_filter_params ++ ] = filter_name ;
170- }
171-
172- // Tokenize the query string into parameters.
173- no_param = tokenize_querystring (ctx , & head , query_str_copy );
273+ query_param_t * head ;
274+ int no_param = tokenize_querystring (ctx , & head , query_str_copy );
174275 if (no_param < 0 ) {
175276 VRT_fail (ctx , "tokenize_querystring failed" );
176277 return NULL ;
177278 }
178279
179280 if (no_param == 0 ) {
180- return new_uri ;
181- }
182-
183- struct vsb * vsb = VSB_new_auto ();
184- if (vsb == NULL ) {
185- VRT_fail (ctx , "VSB_new_auto failed" );
186- return NULL ;
187- }
188-
189- VSB_bcat (vsb , uri , base_uri_len );
190-
191- // Iterate through the query parameters.
192- for (i = 0 , current = head ; i < no_param ; ++ i , ++ current ) {
193- int match = 0 ;
194- for (int j = 0 ; j < num_filter_params ; ++ j ) {
195- if (strcmp (current -> name , filter_params [j ]) == 0 ) {
196- match = 1 ;
197- break ;
198- }
199- }
200-
201- // Include or exclude parameters based upon the argument.
202- int include = exclude_params ? !match : match ;
203- if (include ) {
204- if (current -> value && (* current -> value ) != '\0' ) {
205- VSB_printf (vsb , "%c%s=%s" , sep , current -> name , current -> value );
206- } else {
207- VSB_printf (vsb , "%c%s" , sep , current -> name );
208- }
209- sep = '&' ;
281+ char * ws_uri = WS_Copy (ctx -> ws , base_uri , base_uri_len + 1 );
282+ if (!ws_uri ) {
283+ VRT_fail (ctx , "WS_Copy: out of workspace" );
284+ return NULL ;
210285 }
286+ return ws_uri ;
211287 }
212288
213- if (VSB_finish (vsb ) != 0 ) {
214- VRT_fail (ctx , "VSB_finish failed" );
215- VSB_destroy (& vsb );
216- return NULL ;
217- }
218-
219- // Copy the final URI from the VSB into the workspace
220- const char * final_uri = VSB_data (vsb );
221- size_t final_len = VSB_len (vsb );
222- char * ws_uri = WS_Copy (ctx -> ws , final_uri , final_len + 1 );
223- VSB_destroy (& vsb );
224-
225- if (ws_uri == NULL ) {
226- VRT_fail (ctx , "WS_Copy: out of workspace" );
227- return NULL ;
228- }
229-
230- return ws_uri ;
289+ return rebuild_query_string (ctx , base_uri , head , (size_t )no_param ,
290+ filter_params , num_filter_params ,
291+ exclude_params );
231292}
232293
233294/**
@@ -237,7 +298,8 @@ VCL_STRING vmod_modifyparams(VRT_CTX, VCL_STRING uri, VCL_STRING params_in,
237298 * @param params The query parameters to include.
238299 * @return The modified URL.
239300 */
240- VCL_STRING vmod_includeparams (VRT_CTX , VCL_STRING uri , VCL_STRING params ) {
301+ VCL_STRING
302+ vmod_includeparams (VRT_CTX , VCL_STRING uri , VCL_STRING params ) {
241303 return vmod_modifyparams (ctx , uri , params , 0 );
242304}
243305
@@ -248,6 +310,7 @@ VCL_STRING vmod_includeparams(VRT_CTX, VCL_STRING uri, VCL_STRING params) {
248310 * @param params The query parameters to exclude.
249311 * @return The modified URL.
250312 */
251- VCL_STRING vmod_excludeparams (VRT_CTX , VCL_STRING uri , VCL_STRING params ) {
313+ VCL_STRING
314+ vmod_excludeparams (VRT_CTX , VCL_STRING uri , VCL_STRING params ) {
252315 return vmod_modifyparams (ctx , uri , params , 1 );
253316}
0 commit comments