Skip to content

Commit e061d80

Browse files
authoredDec 20, 2024··
Refactor into smaller functions (#7)
1 parent 522faa1 commit e061d80

File tree

1 file changed

+168
-105
lines changed

1 file changed

+168
-105
lines changed
 

‎src/vmod_querymodifier.c

+168-105
Original file line numberDiff line numberDiff line change
@@ -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
*/
2828
static 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

Comments
 (0)
Please sign in to comment.