OSDN Git Service

Module bug fix.
[ultramonkey-l7/ultramonkey-l7-v2.git] / module / protocol / protomod_url.c
1 /*
2  * @file  protomod_url.c
3  * @brief protocol module of HTTP.
4  * @brief this module provide session persistence by URL.
5  *
6  * L7VSD: Linux Virtual Server for Layer7 Load Balancing
7  * Copyright (C) 2008  NTT COMWARE Corporation.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  *
24  **********************************************************************/
25
26 #define __STDC_LIMIT_MACROS
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <getopt.h>
32 #include "l7vs_service.h"
33 #include "l7vs_conn.h"
34 #include "l7vs_dest.h"
35 #include "l7vs_module.h"
36 #include "module_http.h"
37 #include <fnmatch.h>
38
39 #include <iostream>
40 #ifdef USE_BOOST_XPRESSIVE
41     #include <boost/xpressive/xpressive.hpp>
42 #else
43     #include <boost/regex.hpp>
44 #endif
45
46 #define SERVICE_ARG_MAXSIZE          (512)
47 #define PATTERN_MATCH_MAXSIZE        (128)
48 #define REGEX_PATTERN_MATCH_MAXSIZE  (32)
49 #define URL_SERVICE_NUMBER           (128)
50 #define X_FORWARDED_FOR_LENGTH       (48)
51
52 struct l7vs_url_service {
53         handle_t service_handle;
54         char pattern_match[PATTERN_MATCH_MAXSIZE];
55         char uri_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
56         char host_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
57         int forwarded_for;
58 #ifdef USE_BOOST_XPRESSIVE
59         boost::xpressive::sregex uri_regex;
60         boost::xpressive::sregex host_regex;
61 #else
62         boost::regex uri_regex;
63         boost::regex host_regex;
64 #endif
65         int reschedule;
66 };
67
68 struct  l7vs_url_service_arg {
69         char pattern_match[PATTERN_MATCH_MAXSIZE];
70         char uri_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
71         char host_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
72         int forwarded_for;
73         int reschedule;
74 };
75
76 static void  fini(void);
77 static int   create(void*, handle_t);
78 static void* create_sa(struct l7vs_service_arg*);
79 static int   compare(handle_t, handle_t);
80 static int   select_dest(struct l7vs_service*, struct l7vs_conn*,
81         char*, size_t*, struct l7vs_dest**);
82 static int   analyze_cldata(struct l7vs_service*, struct l7vs_conn*,
83         char*, size_t*);
84 static int   analyze_rsdata(struct l7vs_service*, struct l7vs_conn*,
85         char*, size_t*);
86 static int   destroy(handle_t);
87 static void  destroy_sa(void**);
88 static int   service_arg(struct l7vs_service_arg_multi*, handle_t);
89 static int   parse(void*, int, char**);
90
91 static struct l7vs_url_service *l7vs_protomod_url_search_service(handle_t);
92 static struct l7vs_url_service *l7vs_protomod_url_create_service();
93 static struct l7vs_url_service *l7vs_protomod_url_create_temp_service();
94
95 static void l7vs_url_service_c_str(char*, struct l7vs_url_service*);
96 static void l7vs_url_service_arg_c_str(char*, struct l7vs_url_service_arg*);
97
98 struct l7vs_url_service *url_service_list[URL_SERVICE_NUMBER];
99
100 static struct l7vs_protomod url_protomod = {
101         NULL,           /* handle */
102         "url",          /* modname */
103         0,              /* refcnt */
104         0,              /* fast schedule */
105         create,         /* create function */
106         compare,        /* compare function */
107         select_dest,    /* select_dest function */
108         analyze_cldata, /* analyze_cldata function */
109         analyze_rsdata, /* analyze_rsdata function */
110         destroy,        /* destroy function */
111         fini,           /* fini function */
112         create_sa,      /* create_sa function */
113         service_arg,    /* service_arg function */
114         parse,          /* parse function */
115         destroy_sa,     /* destroy_sa function */
116         NULL,           /* initialize function */
117         NULL,           /* finalize function */
118         NULL,           /* get_log_level function */
119         NULL,           /* put_log_debug function */
120         NULL,           /* put_log_info function */
121         NULL,           /* put_log_warn function */
122         NULL,           /* put_log_error function */
123         NULL            /* put_log_fatal function */
124 };
125
126 /*!
127  * Protocol module initialize function. This function run when dlopen and dlsym at first time.
128  * @param[in] handle dlopen's handle
129  * @return l7vs_protomod struct
130  */
131 extern "C" struct l7vs_protomod *
132 init(void *handle)
133 {
134         struct l7vs_protomod* return_value = NULL;
135
136         /*-------- DEBUG LOG --------*/
137         if (url_protomod.get_log_level != NULL &&
138             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
139                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,135,
140                     "in_function: struct l7vs_protomod* init(void* handle): handle=%p", handle);
141         }
142         /*------ DEBUG LOG END ------*/
143
144         /* check null */
145         if (handle == NULL) {
146                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,117, "Arg(handle) is NULL pointer.");
147                 goto init_out;
148         }
149
150         /* initialize url service list */
151         memset(url_service_list, 0, sizeof(struct l7vs_url_service *) * URL_SERVICE_NUMBER);
152         /* set dlopen's handle */
153         url_protomod.handle = handle;
154
155         return_value = &url_protomod;
156
157 init_out:
158         /*-------- DEBUG LOG --------*/
159         if (url_protomod.get_log_level != NULL &&
160             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
161                 char protomod_str[DEBUG_STR_LEN] = {0};
162                 l7vs_protomod_c_str(protomod_str, &url_protomod);
163                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,136,
164                     "out_function: struct l7vs_protomod* init(void* handle): return=&(%s)", protomod_str);
165         }
166         /*------ DEBUG LOG END ------*/
167         return return_value;
168 }
169
170 /*!
171  * Protocol module finalize function. free all url service list just in case.
172  * @param   void
173  * @return  void
174  */
175 static void
176 fini(void)
177 {
178         /* url service list counter */
179         int service_number = 0;
180
181         /*-------- DEBUG LOG --------*/
182         if (url_protomod.get_log_level != NULL &&
183             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
184                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,137, "in_function: void fini(void)");
185         }
186         /*------ DEBUG LOG END ------*/
187
188         /* check all url service list */
189         for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
190                 /* if pointer that does not point NULL exists ... */
191                 if (url_service_list[service_number] != NULL) {
192
193                         /*-------- DEBUG LOG --------*/
194                         if (url_protomod.get_log_level != NULL &&
195                             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
196                                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,34, "free: %p",
197                                     url_service_list[service_number]);
198                         }
199                         /*------ DEBUG LOG END ------*/
200
201                         /* free and points NULL */
202                         free(url_service_list[service_number]);
203                         url_service_list[service_number] = NULL;
204                 }
205         }
206         /*-------- DEBUG LOG --------*/
207         if (url_protomod.get_log_level != NULL &&
208             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
209                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,138, "out_function: void fini(void)");
210         }
211         /*------ DEBUG LOG END ------*/
212 }
213
214 /*!
215  * Create url service struct.
216  * @param  url_arg    url service argument struct
217  * @param  service_handle a unique service ID
218  * @retval 0  successfully create url service.
219  * @retval -1 some errors occur.
220  */
221 static int
222 create(void *url_arg, handle_t service_handle)
223 {
224         struct l7vs_url_service *url_service;
225         struct l7vs_url_service_arg *url_service_arg;
226         int return_value = 0;
227
228         /*-------- DEBUG LOG --------*/
229         if (url_protomod.get_log_level != NULL &&
230             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
231                 char url_arg_str[DEBUG_STR_LEN] = {0};
232                 l7vs_url_service_arg_c_str(url_arg_str, (struct l7vs_url_service_arg*) url_arg);
233                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,139,
234                     "in_function: int create(void* url_arg, handle_t service_handle):url_arg=&(%s), "
235                     "service_handle=%d", url_arg_str, service_handle);
236         }
237         /*------ DEBUG LOG END ------*/
238
239         /* check null */
240         if (url_arg == NULL) {
241                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,118, "Arg(url_arg) is NULL pointer.");
242                 return_value = -1;
243                 goto create_out;
244         }
245
246         if (service_handle != TEMP_SERVICEHANDLE) {
247                 /* search empty url service list and create url service */
248                 url_service = l7vs_protomod_url_create_service();
249         } else {
250                 /* create temporary url service */
251                 url_service = l7vs_protomod_url_create_temp_service();
252         }
253
254         /*-------- DEBUG LOG --------*/
255         if (url_protomod.get_log_level != NULL &&
256             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
257                 char url_str[DEBUG_STR_LEN] = {0};
258                 l7vs_url_service_c_str(url_str, url_service);
259                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,140, "pointer assign: url_service=&(%s)",
260                     url_str);
261         }
262         /*------ DEBUG LOG END ------*/
263
264         if (url_service == NULL) {
265                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,119, "Could not make url service.");
266                 return_value = -1;
267                 goto create_out;
268         }
269
270         url_service_arg = (struct l7vs_url_service_arg *) url_arg;
271
272         /* set service handle, pattern match and reschedule flag */
273         url_service->service_handle = service_handle;
274         strncpy(url_service->pattern_match, url_service_arg->pattern_match, PATTERN_MATCH_MAXSIZE);
275         strncpy(url_service->uri_pattern_match, url_service_arg->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
276         strncpy(url_service->host_pattern_match, url_service_arg->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
277         url_service->forwarded_for = url_service_arg->forwarded_for;
278         if ( strnlen(url_service_arg->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
279                 try {
280 #ifdef USE_BOOST_XPRESSIVE
281                         url_service->uri_regex = boost::xpressive::sregex::compile(url_service_arg->uri_pattern_match);
282 #else
283                         url_service->uri_regex.assign(url_service_arg->uri_pattern_match);
284 #endif
285                 }
286                 catch (...) {
287                         PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,284, "Regex pattern error of uri_pattern_match");
288                         return_value = -1;
289                         goto create_out;
290                 }
291         }
292         if ( strnlen(url_service_arg->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
293                 try {
294 #ifdef USE_BOOST_XPRESSIVE
295                         url_service->host_regex = boost::xpressive::sregex::compile(url_service_arg->host_pattern_match);
296 #else
297                         url_service->host_regex.assign(url_service_arg->host_pattern_match);
298 #endif
299                 }
300                 catch (...) {
301                         PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,285, "Regex pattern error of host_pattern_match.");
302                         return_value = -1;
303                         goto create_out;
304                 }
305         }
306         url_service->reschedule = url_service_arg->reschedule;
307
308 create_out:
309         /*-------- DEBUG LOG --------*/
310         if (url_protomod.get_log_level != NULL &&
311             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
312                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,141,
313                     "out_function: int create(void* url_arg, handle_t service_handle):return_value=%d",
314                     return_value);
315         }
316         /*------ DEBUG LOG END ------*/
317
318         return return_value;
319 }
320
321 /*!
322  * Create url service argument struct.
323  * @param[out] srv_arg service argument struct
324  * @return url service argument struct
325  */
326 static void *
327 create_sa(struct l7vs_service_arg *srv_arg)
328 {
329         struct l7vs_url_service_arg *url_service_arg;
330
331         /*-------- DEBUG LOG --------*/
332         if (url_protomod.get_log_level != NULL &&
333             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
334                 char service_arg_str[DEBUG_STR_LEN] = {0};
335                 l7vs_service_arg_c_str(service_arg_str, srv_arg);
336                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,142,
337                     "in_function: void* create_sa(struct l7vs_service_arg* srv_arg):srv_arg=&(%s)",
338                     service_arg_str);
339         }
340         /*------ DEBUG LOG END ------*/
341
342         /* check null */
343         if (srv_arg == NULL) {
344                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,120, "Arg(srv_arg) is NULL pointer.");
345                 url_service_arg = NULL;
346                 goto create_sa_out;
347         }
348
349         /* create url service argument struct */
350         url_service_arg = (struct l7vs_url_service_arg *) calloc(1, sizeof(struct l7vs_url_service_arg));
351
352         /*-------- DEBUG LOG --------*/
353         if (url_protomod.get_log_level != NULL &&
354             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
355                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,35, "calloc: addr=%p, size=%ld",
356                     url_service_arg, (unsigned long int) sizeof(struct l7vs_url_service_arg));
357         }
358         /*------ DEBUG LOG END ------*/
359
360         if (url_service_arg == NULL) {
361                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,27, "Could not allocate memory.");
362                 goto create_sa_out;
363         }
364
365         /* set url service argument size and protomod name "url" */
366         srv_arg->len = sizeof(struct l7vs_url_service_arg);
367         strcpy(srv_arg->protomod, url_protomod.modname);
368
369 create_sa_out:
370         /*-------- DEBUG LOG --------*/
371         if (url_protomod.get_log_level != NULL &&
372             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
373                 char url_service_arg_str[DEBUG_STR_LEN] = {0};
374                 l7vs_url_service_arg_c_str(url_service_arg_str, url_service_arg);
375                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,143,
376                     "out_function: void* create_sa(struct l7vs_service_arg* srv_arg):return_value=&(%s)",
377                     url_service_arg_str);
378         }
379         /*------ DEBUG LOG END ------*/
380
381         return (void*) url_service_arg;
382 }
383
384 /*!
385  * Compare two service.
386  * @param[in] srv_handle1 one of a unique service ID
387  * @param[in] srv_handle2 one of a unique service ID
388  * @retval 0  they matched perfectly.
389  * @retval -1 they are different.
390  */
391 static int
392 compare(handle_t srv_handle1, handle_t srv_handle2)
393 {
394         struct l7vs_url_service *url_srv1, *url_srv2;
395         int return_value = 0;
396
397         /*-------- DEBUG LOG --------*/
398         if (url_protomod.get_log_level != NULL &&
399             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
400                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,144,
401                     "in_function: int compare(handle_t srv_handle1, handle_t srv_handle2):"
402                     "srv_handle1=%u, srv_handle2=%u", srv_handle1, srv_handle2);
403         }
404         /*------ DEBUG LOG END ------*/
405
406         /* search service that has such a service ID(1) */
407         url_srv1 = l7vs_protomod_url_search_service(srv_handle1);
408
409         /*-------- DEBUG LOG --------*/
410         if (url_protomod.get_log_level != NULL &&
411             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
412                 char url_str[DEBUG_STR_LEN] = {0};
413                 l7vs_url_service_c_str(url_str, url_srv1);
414                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,145, "pointer assign: url_srv1=&(%s)",
415                     url_str);
416         }
417         /*------ DEBUG LOG END ------*/
418
419         if (url_srv1 == NULL) {
420                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,121,
421                     "Could not find such service handle's url service.");
422                 return_value = -1;
423                 goto compare_out;
424         }
425
426         /* search service that has such a service ID(2) */
427         url_srv2 = l7vs_protomod_url_search_service(srv_handle2);
428
429         /*-------- DEBUG LOG --------*/
430         if (url_protomod.get_log_level != NULL &&
431             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
432                 char url_str[DEBUG_STR_LEN] = {0};
433                 l7vs_url_service_c_str(url_str, url_srv2);
434                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,146, "pointer assign: url_srv2=&(%s)",
435                     url_str);
436         }
437         /*------ DEBUG LOG END ------*/
438
439         if (url_srv2 == NULL) {
440                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,122,
441                     "Could not find such service handle's url service.");
442                 return_value = -1;
443                 goto compare_out;
444         }
445
446         /* compare two pattern match */
447         if (strncmp(url_srv1->pattern_match, url_srv2->pattern_match, PATTERN_MATCH_MAXSIZE) != 0) {
448                 return_value = -1;
449                 goto compare_out;
450         }
451         if (strncmp(url_srv1->uri_pattern_match, url_srv2->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) != 0) {
452                 return_value = -1;
453                 goto compare_out;
454         }
455         if (strncmp(url_srv1->host_pattern_match, url_srv2->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) != 0) {
456                 return_value = -1;
457                 goto compare_out;
458         }
459
460 compare_out:
461         /*-------- DEBUG LOG --------*/
462         if (url_protomod.get_log_level != NULL &&
463             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
464                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,147,
465                     "out_function: int compare(handle_t srv_handle1, handle_t srv_handle2):return_value=%d",
466                     return_value);
467         }
468         /*------ DEBUG LOG END ------*/
469
470         return return_value;
471 }
472
473 /*!
474  * Check the client packet and determine a real server.
475  * @param[in]  srv service struct include service handle, protocol module and schedule module.
476  * @param[in]  conn connection data.
477  * @param[in]  request packet data from client
478  * @param[in]  len length of packet data
479  * @param[out] dest destination (real server) list
480  * @retval 0  successfully check packet data
481  * @retval -1 some errors occur.
482  */
483 static int
484 select_dest(struct l7vs_service *srv, struct l7vs_conn *conn,
485       char *request, size_t *len, struct l7vs_dest **dest)
486 {
487         struct l7vs_url_service *url_service;
488         int ret;
489         int i;
490         int asterisk_num = 0;
491         size_t pattern_len;
492         size_t uri_len;
493         char *uri, *host, pattern[PATTERN_MATCH_MAXSIZE + 2];
494         int offset_length;
495         char *x_forwarded_value;
496         char *next_line = NULL;
497         char x_forwarded_for_header[X_FORWARDED_FOR_LENGTH];
498         char backup_char;
499         int return_value = 0;
500
501         std::string packet_data;
502
503         /*-------- DEBUG LOG --------*/
504         if (url_protomod.get_log_level != NULL &&
505             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
506                 char srv_str[DEBUG_STR_LEN] = {0};
507                 char conn_str[DEBUG_STR_LEN] = {0};
508                 char dest_str[DEBUG_STR_LEN] = {0};
509                 char len_str[DEBUG_STR_LEN] = {0};
510                 char tcps_str[DEBUG_STR_LEN] = {0};
511                 l7vs_service_c_str(srv_str, srv);
512                 l7vs_conn_c_str(conn_str, conn);
513                 if (dest != NULL) {
514                         l7vs_dest_c_str(dest_str, *dest);
515                 }
516                 else {
517                         strncpy(dest_str, "NULL", DEBUG_STR_LEN);
518                 }
519                 if (len != NULL) {
520                         snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
521                 }
522                 else {
523                         strncpy(len_str, "NULL", DEBUG_STR_LEN);
524                 }
525                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,148,
526                     "in_function: int select_dest(struct l7vs_service* srv, struct l7vs_conn* conn, "
527                     "char* request, size_t* len, struct l7vs_dest** dest):srv=&(%s), conn=&(%s), "
528                     "request=\"%s\", len=&(%s), dest=&(&(%s))",
529                     srv_str, conn_str, request, len_str, dest_str);
530         }
531         /*------ DEBUG LOG END ------*/
532
533         /* check null */
534         if (srv == NULL) {
535                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,123, "Arg(srv) is NULL pointer.");
536                 return_value = -1;
537                 goto select_dest_out;
538         }
539         if (srv->pm == NULL) {
540                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,124, "Arg(srv->pm) is NULL pointer.");
541                 return_value = -1;
542                 goto select_dest_out;
543         }
544         if (request == NULL) {
545                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,125, "Arg(request) is NULL pointer.");
546                 return_value = -1;
547                 goto select_dest_out;
548         }
549         if (len == NULL) {
550                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,126, "Arg(len) is NULL pointer.");
551                 return_value = -1;
552                 goto select_dest_out;
553         }
554         if (dest == NULL) {
555                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,127, "Arg(dest) is NULL pointer.");
556                 return_value = -1;
557                 goto select_dest_out;
558         }
559
560         /* search service that has such a service ID */
561         url_service = l7vs_protomod_url_search_service(srv->handle);
562
563         /*-------- DEBUG LOG --------*/
564         if (url_protomod.get_log_level != NULL &&
565             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
566                 char url_str[DEBUG_STR_LEN] = {0};
567                 l7vs_url_service_c_str(url_str, url_service);
568                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,149, "pointer assign: url_service=&(%s)",
569                     url_str);
570         }
571         /*------ DEBUG LOG END ------*/
572
573         if (url_service == NULL) {
574                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,129, "Could not find such service handle's url service.");
575                 return_value = -1;
576                 goto select_dest_out;
577         }
578
579         /* initialize protocol module ... clear destination list */
580         ret = srv->pm->initialize(srv, conn, request, *len, dest);
581         if (ret != 0) {
582                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,130, "Could not initialize protomod.");
583                 return_value = -1;
584                 goto select_dest_out;
585         }
586
587         /* check pattern_match length */
588         if (url_service->pattern_match[0] != '\0') {
589                 /* check the size of request data */
590                 pattern_len = strnlen(url_service->pattern_match, PATTERN_MATCH_MAXSIZE);
591                 /* When '*' is included in pattern_match, number of '*' is decreased from pattern_len */ 
592                 for (i = 0; i < (int)pattern_len; i++) {
593                         if (url_service->pattern_match[i] == '*') {
594                                 asterisk_num++;
595                         }
596                 }
597                 pattern_len -= (size_t)asterisk_num;
598                 if (*len < (15 + pattern_len) ) {
599                         PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,6, "Request data is too short.");
600                         return_value = 1;
601                         goto select_dest_out;
602                 }
603         }
604         
605         /* check the HTTP method in HTTP request header */
606         uri_len = *len;
607         uri = http_check_request_method(request, &uri_len);
608         if (uri == NULL) {
609                 PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,7, "Client message is not HTTP request.");
610                 return_value = 1;
611                 goto select_dest_out;
612         }
613         
614         /* check keyword (URI/--uri-pattern-match)*/
615         if (url_service->uri_pattern_match[0] != '\0') {
616                 packet_data = std::string(uri, uri_len);
617 #ifdef USE_BOOST_XPRESSIVE
618                 if ( !boost::xpressive::regex_search(packet_data, url_service->uri_regex) ) {
619 #else
620                 if ( !boost::regex_search(packet_data, url_service->uri_regex) ) {
621 #endif
622                         return_value = -1;
623                         goto select_dest_out;
624                 }
625         }
626         /* check keyword (URI/--pattern-match)*/
627         if (url_service->pattern_match[0] != '\0') {
628                 backup_char = uri[uri_len];
629                 uri[uri_len] = '\0';
630                 snprintf(pattern, pattern_len + 3, "*%s*", url_service->pattern_match);
631                 ret = fnmatch(pattern, uri, 0);
632                 uri[uri_len] = backup_char;
633         }
634         if ( (url_service->pattern_match[0] != '\0' && ret != 0) ||
635                  (url_service->host_pattern_match[0] != '\0') ) {
636
637                 /* search Host field in HTTP request header */
638                 host = http_search_header_field(request, "Host");
639                 if (host == NULL) {
640                         PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,8, "Could not find Host field.");
641                         return_value = 1;
642                         goto select_dest_out;
643                 }
644                 else {  
645                         next_line = http_skip_header_line(host);
646                         if (next_line) {
647                                 next_line--; // *next_line == '\n'
648                                 if (*(next_line - 1) == '\r') {
649                                         next_line--;
650                                 }
651                                 /* check keyword (HOST/--host-pattern-match) */
652                                 if (url_service->host_pattern_match[0] != '\0') {
653                                         packet_data = std::string(host, next_line - host);
654 #ifdef USE_BOOST_XPRESSIVE
655                                         if ( !boost::xpressive::regex_search(packet_data, url_service->host_regex) ) {
656 #else
657                                         if ( !boost::regex_search(packet_data, url_service->host_regex) ) {
658 #endif
659                                                 return_value = -1;
660                                                 goto select_dest_out;
661                                         }
662                                 }
663                                 /* check keyword (HOST/--pattern-match) */
664                                 if (url_service->pattern_match[0] != '\0' && ret != 0) {
665                                         backup_char = *next_line;
666                                         *next_line = '\0';
667                                         ret = fnmatch(pattern, host, 0);
668                                         *next_line = backup_char;
669                                         if ( ret != 0 ) {
670                                                 return_value = 1;
671                                                 goto select_dest_out;
672                                         }
673                                 }
674                         }
675                         next_line = NULL;
676                 }
677         }
678
679         /* finalize */
680         ret = srv->pm->finalize(srv, conn, request, *len, dest, url_service->reschedule);
681         if (ret != 0) {
682                 PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,12, "Could not finalize protomod. (Realserver decision failure)");
683                 return_value = -1;
684                 goto select_dest_out;
685         }
686
687 select_dest_out:
688         /*-------- DEBUG LOG --------*/
689         if (url_protomod.get_log_level != NULL &&
690             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
691                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,150,
692                     "out_function: int select_dest(struct l7vs_service* srv, struct l7vs_conn* conn, "
693                     "char* request, size_t* len, struct l7vs_dest** dest, int* tcps):return_value=%d",
694                     return_value);
695         }
696         /*------ DEBUG LOG END ------*/
697
698         return return_value;
699 }
700
701 /*!
702  * Analyze and modify client packet
703  * @param[in]  srv service struct include service handle, protocol module and schedule module.
704  * @param[in]  conn connection data.
705  * @param[in]  request packet data from client
706  * @param[in]  len length of packet data
707  * @retval 0  successfully check packet data
708  * @retval -1 some errors occur.
709  */
710 static int
711 analyze_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
712       char *request, size_t *len)
713 {
714         struct l7vs_url_service *url_service;
715         int ret;
716         int i;
717         int asterisk_num = 0;
718         size_t pattern_len;
719         size_t uri_len;
720         char *uri, *host, pattern[PATTERN_MATCH_MAXSIZE + 2];
721         int offset_length;
722         char *x_forwarded_value;
723         char *next_line = NULL;
724         char x_forwarded_for_header[X_FORWARDED_FOR_LENGTH];
725         char backup_char;
726         int return_value = 0;
727
728         std::string packet_data;
729
730         /*-------- DEBUG LOG --------*/
731         if (url_protomod.get_log_level != NULL &&
732             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
733                 char srv_str[DEBUG_STR_LEN] = {0};
734                 char conn_str[DEBUG_STR_LEN] = {0};
735                 char len_str[DEBUG_STR_LEN] = {0};
736                 l7vs_service_c_str(srv_str, srv);
737                 l7vs_conn_c_str(conn_str, conn);
738                 if (len != NULL) {
739                         snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
740                 }
741                 else {
742                         strncpy(len_str, "NULL", DEBUG_STR_LEN);
743                 }
744                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,148,
745                     "in_function: int analyze_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
746                     "char* request, size_t* len):srv=&(%s), conn=&(%s), "
747                     "request=\"%s\", len=&(%s)",
748                     srv_str, conn_str, request, len_str);
749         }
750         /*------ DEBUG LOG END ------*/
751
752         /* check null */
753         if (srv == NULL) {
754                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,123, "Arg(srv) is NULL pointer.");
755                 return_value = -1;
756                 goto analyze_cldata_out;
757         }
758         if (srv->pm == NULL) {
759                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,124, "Arg(srv->pm) is NULL pointer.");
760                 return_value = -1;
761                 goto analyze_cldata_out;
762         }
763         if (request == NULL) {
764                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,125, "Arg(request) is NULL pointer.");
765                 return_value = -1;
766                 goto analyze_cldata_out;
767         }
768         if (len == NULL) {
769                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,126, "Arg(len) is NULL pointer.");
770                 return_value = -1;
771                 goto analyze_cldata_out;
772         }
773
774         /* search service that has such a service ID */
775         url_service = l7vs_protomod_url_search_service(srv->handle);
776
777         /*-------- DEBUG LOG --------*/
778         if (url_protomod.get_log_level != NULL &&
779             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
780                 char url_str[DEBUG_STR_LEN] = {0};
781                 l7vs_url_service_c_str(url_str, url_service);
782                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,149, "pointer assign: url_service=&(%s)",
783                     url_str);
784         }
785         /*------ DEBUG LOG END ------*/
786
787         if (url_service == NULL) {
788                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,129, "Could not find such service handle's url service.");
789                 return_value = -1;
790                 goto analyze_cldata_out;
791         }
792
793         /* add X-Forwarded-For field */
794         if (url_service->forwarded_for) {
795                 x_forwarded_value = http_search_header_field(request, "X-Forwarded-For");
796
797                 /* already exists X-Forwarded-For field */
798                 if (x_forwarded_value) {
799                         next_line = http_skip_header_line(x_forwarded_value);
800                         /* backtrack to look up insert point */
801                         if (next_line) {
802                                 next_line--; // *next_line == '\n'
803                                 if (*(next_line - 1) == '\r') {
804                                         next_line--;
805                                 }
806                                 /* append client IP address */
807                                 snprintf(x_forwarded_for_header, X_FORWARDED_FOR_LENGTH, ", %s", inet_ntoa(conn->caddr.sin_addr));
808                         }
809                 }
810
811                 /* not exists X-Forwarded-For field */
812                 if (!next_line) {
813                         /* construct new X-Forwarded-For header item */
814                         snprintf(x_forwarded_for_header, X_FORWARDED_FOR_LENGTH, "X-Forwarded-For: %s\r\n", inet_ntoa(conn->caddr.sin_addr));
815         
816                         next_line = http_skip_header_line(request);
817                 }
818
819                 /* when insert point exist */
820                 if (next_line != NULL) {
821                         offset_length = (int) (next_line - request);
822         
823                         /* insert X-Forwarded-For header field */
824                         http_insert_field(request, offset_length, x_forwarded_for_header, *len);
825                 
826                         /* add header length */
827                         *len += strlen(x_forwarded_for_header);
828                 }
829         }
830
831 analyze_cldata_out:
832         /*-------- DEBUG LOG --------*/
833         if (url_protomod.get_log_level != NULL &&
834             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
835                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,150,
836                     "out_function: int analyze_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
837                     "char* request, size_t* len, struct l7vs_dest** dest, int* tcps):return_value=%d",
838                     return_value);
839         }
840         /*------ DEBUG LOG END ------*/
841
842         return return_value;
843 }
844
845 /*!
846  * Check the real server packet and insert a Set-Cookie field.
847  * @param[in] srv service struct include service handle, protocol module and schedule module.
848  * @param[in] conn connection data.
849  * @param[in] response packet data from real server
850  * @param[in] len length of packet data. it will be lengthened.
851  * @retval 0  successfully check packet data.
852  * @retval -1 some errors occur.
853  */
854 static int
855 analyze_rsdata(struct l7vs_service *srv, struct l7vs_conn *conn,
856         char *response, size_t *len)
857 {
858         int return_value = 0;
859
860         /*-------- DEBUG LOG --------*/
861         if (url_protomod.get_log_level != NULL &&
862             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
863                 char srv_str[DEBUG_STR_LEN] = {0};
864                 char conn_str[DEBUG_STR_LEN] = {0};
865                 char len_str[DEBUG_STR_LEN] = {0};
866                 l7vs_service_c_str(srv_str, srv);
867                 l7vs_conn_c_str(conn_str, conn);
868                 if (len != NULL) {
869                         snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
870                 }
871                 else {
872                         strncpy(len_str, "NULL", DEBUG_STR_LEN);
873                 }
874                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,151,
875                     "in_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
876                     "char* response, size_t* len):srv=&(%s), conn=&(%s), response=\"%s\", len=&(%s)",
877                     srv_str, conn_str, response, len_str);
878         }
879         /*------ DEBUG LOG END ------*/
880
881         /* check null */
882         if (srv == NULL) {
883                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,133, "Arg(srv) is NULL pointer.");
884                 return_value = -1;
885                 goto analyze_rsdata_out;
886         }
887         if (conn == NULL) {
888                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,134, "Arg(conn) is NULL pointer.");
889                 return_value = -1;
890                 goto analyze_rsdata_out;
891         }
892         if (conn->dest == NULL) {
893                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,135, "Arg(conn->dest) is NULL pointer.");
894                 return_value = -1;
895                 goto analyze_rsdata_out;
896         }
897         if (response == NULL) {
898                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,136, "Arg(response) is NULL pointer.");
899                 return_value = -1;
900                 goto analyze_rsdata_out;
901         }
902         if (len == NULL) {
903                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,137, "Arg(len) is NULL pointer.");
904                 return_value = -1;
905                 goto analyze_rsdata_out;
906         }
907
908         /* sorry flag check */
909         if (conn->sorry_conn_flag == 1) {
910                 /*-------- DEBUG LOG --------*/
911                 if (url_protomod.get_log_level != NULL &&
912                     LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
913                         PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,152, "Response from sorry server.");
914                 }
915                 /*------ DEBUG LOG END ------*/
916                 goto analyze_rsdata_out;
917         }
918
919 analyze_rsdata_out:
920         /*-------- DEBUG LOG --------*/
921         if (url_protomod.get_log_level != NULL &&
922             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
923                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,153,
924                     "out_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
925                     "char* response, size_t* len):return_value=%d", return_value);
926         }
927         /*------ DEBUG LOG END ------*/
928
929         return return_value;
930 }
931
932 /*!
933  * Destroy url service
934  * @param[in] srv_handle a unique service ID
935  * @retval 0  successfully check packet data.
936  * @retval -1 some errors occur.
937  */
938 static int
939 destroy(handle_t srv_handle)
940 {
941         /* url service list counter */
942         int service_number = 0;
943         int free_flag = 0;
944         int return_value = 0;
945
946         /*-------- DEBUG LOG --------*/
947         if (url_protomod.get_log_level != NULL &&
948             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
949                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,154,
950                     "in_function: int destroy(handle_t srv_handle):srv_handle=%u",
951                     srv_handle);
952         }
953         /*------ DEBUG LOG END ------*/
954
955         /* check all url service list */
956         for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
957                 /* found url service that has srv_handle */
958                 if (url_service_list[service_number] != NULL && 
959                     url_service_list[service_number]->service_handle == srv_handle) {
960
961                         /*-------- DEBUG LOG --------*/
962                         if (url_protomod.get_log_level != NULL &&
963                             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
964                                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,36, "free: %p",
965                                     url_service_list[service_number]);
966                         }
967                         /*------ DEBUG LOG END ------*/
968
969                         /* free and NULL */
970                         free(url_service_list[service_number]);
971                         url_service_list[service_number] = NULL;
972
973                         free_flag = 1;
974                         break;
975                 }
976         }
977         
978         /* url service was not found */
979         if (free_flag == 0) {
980                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,138, "Could not find such service handle's url service.");
981                 return_value = -1;
982                 goto destroy_out;
983         }
984
985 destroy_out:
986         /*-------- DEBUG LOG --------*/
987         if (url_protomod.get_log_level != NULL &&
988             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
989                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,155,
990                     "out_function: int destroy(handle_t srv_handle):return_value=%d",
991                     srv_handle);
992         }
993         /*------ DEBUG LOG END ------*/
994
995         return return_value;
996 }
997
998 /*!
999  * Destroy url service argument
1000  * @param[in] url_arg url service argument
1001  * @return void
1002  */
1003 static void
1004 destroy_sa(void **url_arg)
1005 {
1006         /*-------- DEBUG LOG --------*/
1007         if (url_protomod.get_log_level != NULL &&
1008             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1009                 char url_arg_str[DEBUG_STR_LEN] = {0};
1010                 if (url_arg != NULL) {
1011                         l7vs_url_service_arg_c_str(url_arg_str, (struct l7vs_url_service_arg*) *url_arg);
1012                 }
1013                 else {
1014                         strncpy(url_arg_str, "NULL", DEBUG_STR_LEN);
1015                 }
1016                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,156,
1017                     "in_function: void destroy_sa(void** url_arg):url_arg=&(&(%s))",
1018                     url_arg_str);
1019         }
1020         /*------ DEBUG LOG END ------*/
1021
1022         /* check null */
1023         if (url_arg == NULL) {
1024                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,139, "Arg(url_arg) is NULL pointer.");
1025         }
1026         else if (*url_arg == NULL) {
1027                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,140, "Arg(*url_arg) is NULL pointer.");
1028         }
1029         else {
1030                 /*-------- DEBUG LOG --------*/
1031                 if (url_protomod.get_log_level != NULL &&
1032                     LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
1033                         PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,37, "free: %p",
1034                             *url_arg);
1035                 }
1036                 /*------ DEBUG LOG END ------*/
1037
1038                 /* free and NULL */
1039                 free((struct l7vs_url_service_arg*) *url_arg);
1040                 *url_arg = NULL;
1041         }
1042
1043         /*-------- DEBUG LOG --------*/
1044         if (url_protomod.get_log_level != NULL &&
1045             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1046                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,157,
1047                     "out_function: void destroy_sa(void** url_arg)");
1048         }
1049         /*------ DEBUG LOG END ------*/
1050 }
1051
1052 /*!
1053  * Create strings for service list of l7vsadm
1054  * @param  srv_arg service argument struct
1055  * @param  srv_handle a unique service ID
1056  * @retval 0  successfully create strings
1057  * @retval -1 some errors occur.
1058  */
1059 static int
1060 service_arg(struct l7vs_service_arg_multi *srv_arg_mt, handle_t srv_handle)
1061 {
1062         struct l7vs_url_service *url_service;
1063         struct l7vs_url_service_arg c_sarg;
1064         char url_argument[SERVICE_ARG_MAXSIZE];
1065         int return_value = 0;
1066
1067         /*-------- DEBUG LOG --------*/
1068         if (url_protomod.get_log_level != NULL &&
1069             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1070                 char srv_arg_mt_str[DEBUG_STR_LEN] = {0};
1071                 l7vs_service_arg_multi_c_str(srv_arg_mt_str, srv_arg_mt);
1072                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,158,
1073                     "in_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
1074                     "handle_t srv_handle):srv_arg_mt=&(%s), srv_handle=%u",
1075                     srv_arg_mt_str, srv_handle);
1076         }
1077         /*------ DEBUG LOG END ------*/
1078
1079         /* check null */
1080         if (srv_arg_mt == NULL) {
1081                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,141, "Arg(srv_arg_mt) is NULL pointer.");
1082                 return_value = -1;
1083                 goto service_arg_out;
1084         }
1085
1086         /* search service that has such a service ID */
1087         url_service = l7vs_protomod_url_search_service(srv_handle);
1088
1089         /*-------- DEBUG LOG --------*/
1090         if (url_protomod.get_log_level != NULL &&
1091             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1092                 char url_str[DEBUG_STR_LEN] = {0};
1093                 l7vs_url_service_c_str(url_str, url_service);
1094                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,159, "pointer assign: url_service=&(%s)",
1095                     url_str);
1096         }
1097         /*------ DEBUG LOG END ------*/
1098
1099         if (url_service == NULL) {
1100                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,142, "Could not find such service handle's url service.");
1101                 return_value = -1;
1102                 goto service_arg_out;
1103         }
1104
1105         /* initialize argument strings */
1106         memset(url_argument, 0, SERVICE_ARG_MAXSIZE);
1107
1108         /* set url args to service argument struct */
1109         srv_arg_mt->srv_arg.reschedule = url_service->reschedule;
1110
1111         /* create long argument (l7vsadm option -L/-l) */
1112         if ( strnlen(url_service->pattern_match, PATTERN_MATCH_MAXSIZE) ) {
1113                 snprintf(url_argument, SERVICE_ARG_MAXSIZE, "--pattern-match %s", url_service->pattern_match);
1114         }
1115         if ( strnlen(url_service->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
1116                 snprintf(url_argument + strlen(url_argument), SERVICE_ARG_MAXSIZE - strlen(url_argument),
1117                     " --uri-pattern-match %s", url_service->uri_pattern_match);
1118         }
1119         if ( strnlen(url_service->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
1120                 snprintf(url_argument + strlen(url_argument), SERVICE_ARG_MAXSIZE - strlen(url_argument),
1121                     " --host-pattern-match %s", url_service->host_pattern_match);
1122         }
1123         strncpy(srv_arg_mt->srv_arg.protomod_key_string, url_argument, 256);
1124
1125         /* create verbose argument (l7vsadm option -V/-v) */
1126         if (url_service->forwarded_for) {
1127                 snprintf(url_argument + strlen(url_argument), SERVICE_ARG_MAXSIZE - strlen(url_argument),
1128                     " --forwarded-for");
1129         }
1130         strncpy(srv_arg_mt->srv_arg.protomod_opt_string, url_argument, 512);
1131
1132         strncpy(c_sarg.pattern_match, url_service->pattern_match, PATTERN_MATCH_MAXSIZE);
1133         strncpy(c_sarg.uri_pattern_match, url_service->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
1134         strncpy(c_sarg.host_pattern_match, url_service->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
1135         c_sarg.reschedule = url_service->reschedule;
1136
1137         memcpy(srv_arg_mt->protomod_arg, &c_sarg, sizeof(struct l7vs_url_service_arg));
1138
1139         /*-------- DEBUG LOG --------*/
1140         if (url_protomod.get_log_level != NULL &&
1141             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1142                 char url_arg_str[DEBUG_STR_LEN] = {0};
1143                 l7vs_url_service_arg_c_str(url_arg_str, &c_sarg);
1144                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,160,
1145                     "pointer assign: srv_arg_mt->protomod_arg=&(%s)", url_arg_str);
1146         }
1147         /*------ DEBUG LOG END ------*/
1148
1149 service_arg_out:
1150         /*-------- DEBUG LOG --------*/
1151         if (url_protomod.get_log_level != NULL &&
1152             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1153                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,161,
1154                     "out_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
1155                     "handle_t srv_handle):return_value=%d", return_value);
1156         }
1157         /*------ DEBUG LOG END ------*/
1158
1159         return return_value;
1160 }
1161
1162 /*!
1163  * Parse l7vsadm options to url argument
1164  * @param[out] url_arg url service argument struct
1165  * @param[int] argc number of l7vsadm argument
1166  * @param[int] argv l7vsadm argument list
1167  * @retval 0  successfully parse argument
1168  * @retval -1 some errors occur.
1169  */
1170 static int
1171 parse(void *url_arg, int argc, char *argv[])
1172 {
1173         struct l7vs_url_service_arg *url_service_arg;
1174         static struct option opt[] = {
1175                 {"pattern-match",      required_argument, NULL, 'P'},
1176                 {"uri-pattern-match",  required_argument, NULL, 'U'},
1177                 {"host-pattern-match", required_argument, NULL, 'H'},
1178                 {"forwarded-for",      no_argument,       NULL, 'F'},
1179                 {NULL,                 0,                 NULL, 0  }
1180         };
1181         int c;
1182         int pattern_match_flag = 0;
1183         int uri_pattern_match_flag = 0;
1184         int host_pattern_match_flag = 0;
1185         int forwarded_for_flag = 0;
1186         int return_value = 0;
1187 #ifndef USE_BOOST_XPRESSIVE
1188     boost::regex regex;
1189 #endif
1190
1191         /*-------- DEBUG LOG --------*/
1192         if (url_protomod.get_log_level != NULL &&
1193             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1194                 int i;
1195                 char argv_str[DEBUG_STR_LEN] = {0};
1196                 char url_arg_str[DEBUG_STR_LEN] = {0};
1197                 l7vs_url_service_arg_c_str(url_arg_str, (struct l7vs_url_service_arg*) url_arg);
1198                 argv_str[0] = '\0';
1199                 if (argv == NULL)
1200                         snprintf(argv_str, DEBUG_STR_LEN, "NULL");
1201                 else {
1202                         for (i = 0; i < argc; i++) {
1203                                 snprintf(argv_str, DEBUG_STR_LEN, "%sargv[%d]=\"%s\", ", argv_str, i, argv[i]);
1204                         }
1205                         i = strnlen(argv_str, DEBUG_STR_LEN);
1206                         if (i > 1)
1207                                 argv_str[i - 2] = '\0';
1208                 }
1209                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,162,
1210                     "in_function: int parse(void* url_arg, int argc, char* argv[]):url_arg=&(%s), "
1211                     "argc=%d, %s", url_arg_str, argc, argv_str);
1212         }
1213         /*------ DEBUG LOG END ------*/
1214
1215         /* check null */
1216         if (url_arg == NULL) {
1217                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,143, "Arg(url_arg) is NULL pointer.");
1218                 return_value = -1;
1219                 goto parse_out;
1220         }
1221         if (argv == NULL) {
1222                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,144, "Arg(argv) is NULL pointer.");
1223                 return_value = -1;
1224                 goto parse_out;
1225         }
1226
1227         url_service_arg = (struct l7vs_url_service_arg *) url_arg;
1228         optind = 0;
1229
1230         /* check all argument */
1231         while ((c = getopt_long(argc, argv, "P:U:H:F", opt, NULL)) != -1) {
1232                 switch (c) {
1233                 /* --pattern-match / -P */
1234                 case 'P':
1235                         /* check maximum length */
1236                         if (strnlen(optarg, PATTERN_MATCH_MAXSIZE) >= PATTERN_MATCH_MAXSIZE) {
1237                                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,145,
1238                                     "-P/--pattern-match option value '%s' too long", optarg);
1239                                 return_value = -1;
1240                                 goto parse_out;
1241                         }
1242                         /* check minimum length */
1243                         if (strnlen(optarg, PATTERN_MATCH_MAXSIZE) <= 0 ) {
1244                                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,146,
1245                                     "-P/--pattern-match option value '%s' invalid", optarg);
1246                                 return_value = -1;
1247                                 goto parse_out;
1248                         }
1249                         strncpy(url_service_arg->pattern_match, optarg, PATTERN_MATCH_MAXSIZE);
1250                         pattern_match_flag++;
1251                         break;
1252
1253                 /* --uri-pattern-match / -U */
1254                 case 'U':
1255                         /* check maximum length */
1256                         if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) >= REGEX_PATTERN_MATCH_MAXSIZE) {
1257                                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,286,
1258                                     "-U/--uri-pattern-match option value '%s' too long", optarg);
1259                                 return_value = -1;
1260                                 goto parse_out;
1261                         }
1262                         /* check minimum length */
1263                         if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) <= 0 ) {
1264                                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,287,
1265                                     "-U/--uri-pattern-match option value '%s' invalid", optarg);
1266                                 return_value = -1;
1267                                 goto parse_out;
1268                         }
1269                         strncpy(url_service_arg->uri_pattern_match, optarg, REGEX_PATTERN_MATCH_MAXSIZE);
1270                         uri_pattern_match_flag++;
1271                         break;
1272
1273                 /* --host-pattern-match / -H */
1274                 case 'H':
1275                         /* check maximum length */
1276                         if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) >= REGEX_PATTERN_MATCH_MAXSIZE) {
1277                                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,288,
1278                                     "-H/--host-pattern-match option value '%s' too long", optarg);
1279                                 return_value = -1;
1280                                 goto parse_out;
1281                         }
1282                         /* check minimum length */
1283                         if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) <= 0 ) {
1284                                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,289,
1285                                     "-H/--host-pattern-match option value '%s' invalid", optarg);
1286                                 return_value = -1;
1287                                 goto parse_out;
1288                         }
1289                         strncpy(url_service_arg->host_pattern_match, optarg, REGEX_PATTERN_MATCH_MAXSIZE);
1290                         host_pattern_match_flag++;
1291                         break;
1292
1293                 /* --forwarded-for / -F */
1294                 case 'F':
1295                         /* x-forwarded-for on */
1296                         url_service_arg->forwarded_for = 1;
1297                         forwarded_for_flag++;
1298                         break;
1299
1300                 /* else error */
1301                 default:
1302                         PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,147, "Option error.");
1303                         return_value = -1;
1304                         goto parse_out;
1305                 }
1306         }
1307
1308         /* set default no forwarded_for */
1309         if (forwarded_for_flag == 0) {
1310                 url_service_arg->forwarded_for = 0;
1311         }
1312
1313         /* set default no reschedule */
1314         url_service_arg->reschedule = 0;
1315
1316         /* no pattern-match value */
1317         if (pattern_match_flag == 0 && uri_pattern_match_flag == 0 && host_pattern_match_flag ==0) {
1318                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,148,
1319                     "You have to set any of '--pattern-match', '--uri-pattern-match' or '--host-pattern-match' option.");
1320                 return_value = -1;
1321                 goto parse_out;
1322         }
1323         /* same option */
1324         if (pattern_match_flag > 1) {
1325                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,149,
1326                     "Cannot set multiple option '--pattern-match/-P'.");
1327                 return_value = -1;
1328                 goto parse_out;
1329         }
1330         if (uri_pattern_match_flag > 1) {
1331                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,290,
1332                     "Cannot set multiple option '--uri-pattern-match/-U'.");
1333                 return_value = -1;
1334                 goto parse_out;
1335         }
1336         if (host_pattern_match_flag > 1) {
1337                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,291,
1338                     "Cannot set multiple option '--host-pattern-match/-H'.");
1339                 return_value = -1;
1340                 goto parse_out;
1341         }
1342         /* compile regex */
1343         if (uri_pattern_match_flag) {
1344             try {
1345 #ifdef USE_BOOST_XPRESSIVE
1346                 boost::xpressive::sregex::compile(url_service_arg->uri_pattern_match);
1347 #else
1348                 regex.assign(url_service_arg->uri_pattern_match);
1349 #endif
1350             }
1351             catch (...) {
1352                         PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,292,
1353                           "Regex pattern error of option '--uri-pattern-match/-U'.");
1354                         return_value = -1;
1355                         goto parse_out;
1356             }
1357         }
1358         if (host_pattern_match_flag) {
1359             try {
1360 #ifdef USE_BOOST_XPRESSIVE
1361                 boost::xpressive::sregex::compile(url_service_arg->host_pattern_match);
1362 #else
1363                 regex.assign(url_service_arg->host_pattern_match);
1364 #endif
1365             }
1366             catch (...) {
1367                         PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,293,
1368                           "Regex pattern error of option '--host-pattern-match/-H'.");
1369                         return_value = -1;
1370                         goto parse_out;
1371             }
1372         }
1373
1374 parse_out:
1375         /*-------- DEBUG LOG --------*/
1376         if (url_protomod.get_log_level != NULL &&
1377             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1378                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,163,
1379                     "out_function: int parse(void* url_arg, int argc, char* argv[]):return_value=%d",
1380                     return_value);
1381         }
1382         /*------ DEBUG LOG END ------*/
1383
1384         return return_value;
1385 }
1386
1387 /*!
1388  * Search url service from url service list using service handle
1389  * @param[in]  service_handle a unique service ID
1390  * @return url service struct when service was found. NULL when service was not found.
1391  */
1392 static struct l7vs_url_service *
1393 l7vs_protomod_url_search_service(handle_t service_handle)
1394 {
1395         /* url service list counter */
1396         int service_number = 0;
1397         struct l7vs_url_service* return_value = NULL;
1398
1399         /*-------- DEBUG LOG --------*/
1400         if (url_protomod.get_log_level != NULL &&
1401             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1402                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,164,
1403                     "in_function: struct l7vs_url_service* l7vs_protomod_url_search_service(handle_t service_handle):"
1404                     "service_handle=%d", service_handle);
1405         }
1406         /*------ DEBUG LOG END ------*/
1407
1408         /* check all url service list */
1409         for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
1410                 /* found the service has same service handle */
1411                 if (url_service_list[service_number] != NULL && 
1412                     url_service_list[service_number]->service_handle == service_handle) {
1413                         return_value = url_service_list[service_number];
1414                         break;
1415                 }
1416         }
1417         
1418         /*-------- DEBUG LOG --------*/
1419         if (url_protomod.get_log_level != NULL &&
1420             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1421                 char ssl_str[DEBUG_STR_LEN] = {0};
1422                 l7vs_url_service_c_str(ssl_str, return_value);
1423                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,165,
1424                     "out_function: struct l7vs_url_service* l7vs_protomod_url_search_service(handle_t service_handle):"
1425                     "return_value=&(%s)", ssl_str);
1426         }
1427         /*------ DEBUG LOG END ------*/
1428
1429         return return_value;
1430 }
1431
1432 /*!
1433  * Create url service.
1434  * @param  void
1435  * @return url service struct when create a service. NULL when cannot create service.
1436  */
1437 static struct l7vs_url_service *
1438 l7vs_protomod_url_create_service()
1439 {
1440         struct l7vs_url_service* return_value = NULL;
1441         int service_number = 0;
1442
1443         /*-------- DEBUG LOG --------*/
1444         if (url_protomod.get_log_level != NULL &&
1445             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1446                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,166,
1447                     "in_function: struct l7vs_url_service* l7vs_protomod_url_create_service()");
1448         }
1449         /*------ DEBUG LOG END ------*/
1450
1451         /* check all url service list */
1452         for (service_number = 0; service_number < URL_SERVICE_NUMBER - 1; ++service_number) {
1453                 /* if pointer that does not point NULL exists ... */
1454                 if (url_service_list[service_number] == NULL) {
1455                         /* create a service at empty pointer */
1456                         url_service_list[service_number] = (struct l7vs_url_service *) calloc(1, sizeof(struct l7vs_url_service));
1457
1458                         /*-------- DEBUG LOG --------*/
1459                         if (url_protomod.get_log_level != NULL &&
1460                             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
1461                                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,38, "calloc: addr=%p, size=%ld",
1462                                     url_service_list[service_number], (unsigned long int) sizeof(struct l7vs_url_service));
1463                         }
1464                         /*------ DEBUG LOG END ------*/
1465
1466                         if (url_service_list[service_number] == NULL) {
1467                                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,28, "Could not allocate memory.");
1468                                 goto create_service_out;
1469                         }
1470                         return_value = url_service_list[service_number];
1471                         goto create_service_out;
1472                 }
1473         }
1474         
1475         /* all service list is full */
1476         PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,150, "url service list is full.");
1477
1478 create_service_out:
1479         /*-------- DEBUG LOG --------*/
1480         if (url_protomod.get_log_level != NULL &&
1481             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1482                 char ssl_str[DEBUG_STR_LEN] = {0};
1483                 l7vs_url_service_c_str(ssl_str, return_value);
1484                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,167,
1485                     "out_function: struct l7vs_url_service* l7vs_protomod_url_create_service():"
1486                     "return_value=&(%s)", ssl_str);
1487         }
1488         /*------ DEBUG LOG END ------*/
1489
1490         return return_value;
1491 }
1492
1493 /*!
1494  * Create temporary url service.
1495  * @param  void
1496  * @return url service struct when create a service. NULL when cannot create service.
1497  */
1498 static struct l7vs_url_service *
1499 l7vs_protomod_url_create_temp_service()
1500 {
1501         struct l7vs_url_service* return_value = NULL;
1502
1503         /*-------- DEBUG LOG --------*/
1504         if (url_protomod.get_log_level != NULL &&
1505             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1506                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,168,
1507                     "in_function: struct l7vs_url_service* l7vs_protomod_url_create_temp_service()");
1508         }
1509         /*------ DEBUG LOG END ------*/
1510
1511         /* if pointer that does not point NULL exists ... */
1512         if (url_service_list[URL_SERVICE_NUMBER - 1] != NULL) {
1513                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,151, "Temporary url service is being used by other process.");
1514                 goto create_temp_service_out;
1515         }
1516
1517         /* create temp service */
1518         url_service_list[URL_SERVICE_NUMBER - 1] = (struct l7vs_url_service *) calloc(1, sizeof(struct l7vs_url_service));
1519
1520         /*-------- DEBUG LOG --------*/
1521         if (url_protomod.get_log_level != NULL &&
1522             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
1523                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,39, "calloc: addr=%p, size=%ld",
1524                     url_service_list[URL_SERVICE_NUMBER - 1], (unsigned long int) sizeof(struct l7vs_url_service));
1525         }
1526         /*------ DEBUG LOG END ------*/
1527
1528         if (url_service_list[URL_SERVICE_NUMBER - 1] == NULL) {
1529                 PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,29, "Could not allocate memory");
1530                 goto create_temp_service_out;
1531         }
1532
1533         return_value = url_service_list[URL_SERVICE_NUMBER - 1];
1534
1535 create_temp_service_out:
1536         /*-------- DEBUG LOG --------*/
1537         if (url_protomod.get_log_level != NULL &&
1538             LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
1539                 char ssl_str[DEBUG_STR_LEN] = {0};
1540                 l7vs_url_service_c_str(ssl_str, return_value);
1541                 PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,169,
1542                     "out_function: struct l7vs_url_service* l7vs_protomod_url_create_service():"
1543                     "return_value=&(%s)", ssl_str);
1544         }
1545         /*------ DEBUG LOG END ------*/
1546
1547         return return_value;
1548 }
1549
1550 /*!
1551  * Serialize struct l7vs_url_service for debug log.
1552  * @param[out] buf   serialized string
1553  * @param[in]  url l7vs_url_service struct
1554  */
1555 static void l7vs_url_service_c_str(char* buf, struct l7vs_url_service* url) {
1556         if (url == NULL) {
1557                 snprintf(buf, DEBUG_STR_LEN, "NULL");
1558         }
1559         else {
1560                 snprintf(buf, DEBUG_STR_LEN, "service_handle=%d, pattern_match=\"%s\", uri_pattern_match=\"%s\", host_pattern_match=\"%s\", "
1561                     "forwarded_for=%d, reschedule=%d", url->service_handle, url->pattern_match, url->uri_pattern_match, url->host_pattern_match,
1562                     url->forwarded_for, url->reschedule);
1563         }
1564 }
1565
1566 /*!
1567  * Serialize struct l7vs_url_service_arg for debug log.
1568  * @param[out] buf       serialized string
1569  * @param[in]  url_arg l7vs_url_service_arg struct
1570  */
1571 void l7vs_url_service_arg_c_str(char* buf, struct l7vs_url_service_arg* url_arg) {
1572         if (url_arg == NULL) {
1573                 snprintf(buf, DEBUG_STR_LEN, "NULL");
1574         }
1575         else {
1576                 snprintf(buf, DEBUG_STR_LEN, "pattern_match=\"%s\", uri_pattern_match=\"%s\", host_pattern_match=\"%s\", forwarded_for=%d, reschedule=%d",
1577                     url_arg->pattern_match, url_arg->uri_pattern_match, url_arg->host_pattern_match, url_arg->forwarded_for, url_arg->reschedule);
1578         }
1579 }