@@ -372,7 +372,9 @@ int parse_logformat_tag_args(char *args, struct logformat_node *node, char **err
372372 * ignored when arg_len is 0. Neither <tag> nor <tag_len> may be null.
373373 * Returns false in error case and err is filled, otherwise returns true.
374374 */
375- int parse_logformat_tag (char * arg , int arg_len , char * name , int name_len , int typecast , char * tag , int tag_len , struct proxy * curproxy , struct lf_expr * lf_expr , int * defoptions , char * * err )
375+ static int parse_logformat_tag (char * arg , int arg_len , char * name , int name_len , int typecast ,
376+ char * tag , int tag_len , struct lf_expr * lf_expr ,
377+ int * defoptions , char * * err )
376378{
377379 int j ;
378380 struct list * list_format = & lf_expr -> nodes ;
@@ -465,7 +467,9 @@ int add_to_logformat_list(char *start, char *end, int type, struct lf_expr *lf_e
465467 *
466468 * In error case, the function returns 0, otherwise it returns 1.
467469 */
468- int add_sample_to_logformat_list (char * text , char * name , int name_len , int typecast , char * arg , int arg_len , struct proxy * curpx , struct lf_expr * lf_expr , int options , int cap , char * * err , char * * endptr )
470+ static int add_sample_to_logformat_list (char * text , char * name , int name_len , int typecast ,
471+ char * arg , int arg_len , struct lf_expr * lf_expr ,
472+ struct arg_list * al , int options , int cap , char * * err , char * * endptr )
469473{
470474 char * cmd [2 ];
471475 struct list * list_format = & lf_expr -> nodes ;
@@ -477,8 +481,8 @@ int add_sample_to_logformat_list(char *text, char *name, int name_len, int typec
477481 cmd [1 ] = "" ;
478482 cmd_arg = 0 ;
479483
480- expr = sample_parse_expr (cmd , & cmd_arg , curpx -> conf .args . file , curpx -> conf . args .line , err ,
481- & curpx -> conf . args , endptr );
484+ expr = sample_parse_expr (cmd , & cmd_arg , lf_expr -> conf .file , lf_expr -> conf .line , err ,
485+ al , endptr );
482486 if (!expr ) {
483487 memprintf (err , "failed to parse sample expression <%s> : %s" , text , * err );
484488 goto error_free ;
@@ -515,7 +519,7 @@ int add_sample_to_logformat_list(char *text, char *name, int name_len, int typec
515519
516520 if ((options & LOG_OPT_HTTP ) && (expr -> fetch -> use & (SMP_USE_L6REQ |SMP_USE_L6RES ))) {
517521 ha_warning ("parsing [%s:%d] : L6 sample fetch <%s> ignored in HTTP log-format string.\n" ,
518- curpx -> conf .args . file , curpx -> conf . args .line , text );
522+ lf_expr -> conf .file , lf_expr -> conf .line , text );
519523 }
520524
521525 LIST_APPEND (list_format , & node -> list );
@@ -527,24 +531,25 @@ int add_sample_to_logformat_list(char *text, char *name, int name_len, int typec
527531}
528532
529533/*
530- * Parse the log_format string and fill a logformat expression. The logformat
531- * expression will be scheduled for postcheck on the proxy unless the proxy was
532- * already checked, in which case all checks will be performed right away.
534+ * Compile logformat expression (from string to list of logformat nodes)
533535 *
534536 * Tag name are preceded by % and composed by characters [a-zA-Z0-9]* : %tagname
535537 * You can set arguments using { } : %{many arguments}tagname.
536- * The curproxy->conf.args.ctx must be set by the caller.
537538 *
538- * fmt: the string to parse
539- * curproxy: the proxy affected
540539 * lf_expr: the destination logformat expression (logformat_node list)
540+ * which is supposed to be configured (str and conf set) but
541+ * shouldn't be compiled (shoudn't contain any nodes)
542+ * al: arg list where sample expr should store arg dependency (if the logformat
543+ * expression involves sample expressions), may be NULL
541544 * options: LOG_OPT_* to force on every node
542545 * cap: all SMP_VAL_* flags supported by the consumer
543546 *
544547 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
545548 */
546- int parse_logformat_string (const char * fmt , struct proxy * curproxy , struct lf_expr * lf_expr , int options , int cap , char * * err )
549+ int lf_expr_compile (struct lf_expr * lf_expr ,
550+ struct arg_list * al , int options , int cap , char * * err )
547551{
552+ char * fmt = lf_expr -> str ; /* will be freed */
548553 char * sp , * str , * backfmt ; /* start pointer for text parts */
549554 char * arg = NULL ; /* start pointer for args */
550555 char * tag = NULL ; /* start pointer for tags */
@@ -557,22 +562,25 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct lf_ex
557562 int cformat ; /* current token format */
558563 int pformat ; /* previous token format */
559564
565+ BUG_ON ((lf_expr -> flags & LF_FL_COMPILED ));
566+
567+ if (!fmt )
568+ return 1 ; // nothing to do
569+
560570 sp = str = backfmt = strdup (fmt );
561571 if (!str ) {
562572 memprintf (err , "out of memory error" );
563573 return 0 ;
564574 }
565575
566- /* reset the old expr first (if previously defined) */
567- lf_expr_deinit (lf_expr );
568-
569- /* Save some parsing infos to raise relevant error messages during
570- * postparsing if needed.
576+ /* Prepare lf_expr nodes, past this lf_expr doesn't know about ->str
577+ * anymore as ->str and ->nodes are part of the same union. ->str has
578+ * been saved as local 'fmt' string pointer, so we must free it before
579+ * returning.
571580 */
572- if (curproxy -> conf .args .file ) {
573- lf_expr -> conf .file = strdup (curproxy -> conf .args .file );
574- lf_expr -> conf .line = curproxy -> conf .args .line ;
575- }
581+ LIST_INIT (& lf_expr -> nodes );
582+ /* we must set the compiled flag now for proper deinit in case of failure */
583+ lf_expr -> flags |= LF_FL_COMPILED ;
576584
577585 for (cformat = LF_INIT ; cformat != LF_END ; str ++ ) {
578586 pformat = cformat ;
@@ -687,7 +695,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct lf_ex
687695 * part of the expression, which MUST be the trailing
688696 * angle bracket.
689697 */
690- if (!add_sample_to_logformat_list (tag , name , name_len , typecast , arg , arg_len , curproxy , lf_expr , options , cap , err , & str ))
698+ if (!add_sample_to_logformat_list (tag , name , name_len , typecast , arg , arg_len , lf_expr , al , options , cap , err , & str ))
691699 goto fail ;
692700
693701 if (* str == ']' ) {
@@ -733,7 +741,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct lf_ex
733741 if (cformat != pformat || pformat == LF_SEPARATOR ) {
734742 switch (pformat ) {
735743 case LF_TAG :
736- if (!parse_logformat_tag (arg , arg_len , name , name_len , typecast , tag , tag_len , curproxy , lf_expr , & options , err ))
744+ if (!parse_logformat_tag (arg , arg_len , name , name_len , typecast , tag , tag_len , lf_expr , & options , err ))
737745 goto fail ;
738746 break ;
739747 case LF_TEXT :
@@ -750,8 +758,57 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct lf_ex
750758 memprintf (err , "truncated line after '%s'" , tag ? tag : arg ? arg : "%" );
751759 goto fail ;
752760 }
761+ ha_free (& fmt );
753762 ha_free (& backfmt );
754763
764+ return 1 ;
765+ fail :
766+ ha_free (& fmt );
767+ ha_free (& backfmt );
768+ return 0 ;
769+ }
770+
771+ /* lf_expr_compile() helper: uses <curproxy> to deduce settings and
772+ * simplify function usage, mostly for legacy purpose
773+ *
774+ * curproxy->conf.args.ctx must be set by the caller.
775+ *
776+ * The logformat expression will be scheduled for postcheck on the proxy unless
777+ * the proxy was already checked, in which case all checks will be performed right
778+ * away.
779+ *
780+ * Returns 1 on success and 0 on failure. On failure: <lf_expr> will be cleaned
781+ * up and <err> will be set.
782+ */
783+ int parse_logformat_string (const char * fmt , struct proxy * curproxy ,
784+ struct lf_expr * lf_expr ,
785+ int options , int cap , char * * err )
786+ {
787+ int ret ;
788+
789+
790+ /* reinit lf_expr (if previously set) */
791+ lf_expr_deinit (lf_expr );
792+
793+ lf_expr -> str = strdup (fmt );
794+ if (!lf_expr -> str ) {
795+ memprintf (err , "out of memory error" );
796+ goto fail ;
797+ }
798+
799+ /* Save some parsing infos to raise relevant error messages during
800+ * postparsing if needed
801+ */
802+ if (curproxy -> conf .args .file ) {
803+ lf_expr -> conf .file = strdup (curproxy -> conf .args .file );
804+ lf_expr -> conf .line = curproxy -> conf .args .line ;
805+ }
806+
807+ ret = lf_expr_compile (lf_expr , & curproxy -> conf .args , options , cap , err );
808+
809+ if (!ret )
810+ goto fail ;
811+
755812 if (!(curproxy -> flags & PR_FL_CHECKED )) {
756813 /* add the lf_expr to the proxy checks to delay postparsing
757814 * since config-related proxy properties are not stable yet
@@ -765,10 +822,10 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct lf_ex
765822 if (!lf_expr_postcheck (lf_expr , curproxy , err ))
766823 goto fail ;
767824 }
768-
769825 return 1 ;
826+
770827 fail :
771- ha_free ( & backfmt );
828+ lf_expr_deinit ( lf_expr );
772829 return 0 ;
773830}
774831
@@ -848,6 +905,7 @@ static int postcheck_logformat_proxy(struct proxy *px)
848905 int err_code = ERR_NONE ;
849906
850907 list_for_each_entry_safe (lf_expr , back_lf , & px -> conf .lf_checks , list ) {
908+ BUG_ON (!(lf_expr -> flags & LF_FL_COMPILED ));
851909 if (!lf_expr_postcheck (lf_expr , px , & err ))
852910 err_code |= ERR_FATAL | ERR_ALERT ;
853911 /* check performed, ensure it doesn't get checked twice */
@@ -2697,24 +2755,28 @@ void free_logformat_list(struct list *fmt)
26972755/* Prepares log-format expression struct */
26982756void lf_expr_init (struct lf_expr * expr )
26992757{
2700- LIST_INIT (& expr -> nodes );
27012758 LIST_INIT (& expr -> list );
2759+ expr -> flags = LF_FL_NONE ;
2760+ expr -> str = NULL ;
27022761 expr -> conf .file = NULL ;
27032762 expr -> conf .line = 0 ;
27042763}
27052764
27062765/* Releases and resets a log-format expression */
27072766void lf_expr_deinit (struct lf_expr * expr )
27082767{
2709- free_logformat_list (& expr -> nodes );
2768+ if ((expr -> flags & LF_FL_COMPILED ))
2769+ free_logformat_list (& expr -> nodes );
2770+ else
2771+ free (expr -> str );
27102772 free (expr -> conf .file );
27112773 /* remove from parent list (if any) */
27122774 LIST_DEL_INIT (& expr -> list );
27132775
27142776 lf_expr_init (expr );
27152777}
27162778
2717- /* Transfer log-format expression from <src> to <dst>
2779+ /* Transfer a compiled log-format expression from <src> to <dst>
27182780 * at the end of the operation, <src> is reset
27192781 */
27202782void lf_expr_xfer (struct lf_expr * src , struct lf_expr * dst )
@@ -2724,9 +2786,15 @@ void lf_expr_xfer(struct lf_expr *src, struct lf_expr *dst)
27242786 /* first, reset any existing expr */
27252787 lf_expr_deinit (dst );
27262788
2789+ BUG_ON (!(src -> flags & LF_FL_COMPILED ));
2790+
27272791 /* then proceed with transfer between <src> and <dst> */
27282792 dst -> conf .file = src -> conf .file ;
27292793 dst -> conf .line = src -> conf .line ;
2794+
2795+ dst -> flags |= LF_FL_COMPILED ;
2796+ LIST_INIT (& dst -> nodes );
2797+
27302798 list_for_each_entry_safe (lf , lfb , & src -> nodes , list ) {
27312799 LIST_DELETE (& lf -> list );
27322800 LIST_APPEND (& dst -> nodes , & lf -> list );
@@ -2742,6 +2810,33 @@ void lf_expr_xfer(struct lf_expr *src, struct lf_expr *dst)
27422810 lf_expr_init (src );
27432811}
27442812
2813+ /* tries to duplicate an uncompiled logformat expression from <orig> to <dest>
2814+ *
2815+ * Returns 1 on success and 0 on failure.
2816+ */
2817+ int lf_expr_dup (const struct lf_expr * orig , struct lf_expr * dest )
2818+ {
2819+ BUG_ON ((orig -> flags & LF_FL_COMPILED ));
2820+ lf_expr_deinit (dest );
2821+ if (orig -> str ) {
2822+ dest -> str = strdup (orig -> str );
2823+ if (!dest -> str )
2824+ goto error ;
2825+ }
2826+ if (orig -> conf .file ) {
2827+ dest -> conf .file = strdup (orig -> conf .file );
2828+ if (!dest -> conf .file )
2829+ goto error ;
2830+ }
2831+ dest -> conf .line = orig -> conf .line ;
2832+
2833+ return 1 ;
2834+
2835+ error :
2836+ lf_expr_deinit (dest );
2837+ return 0 ;
2838+ }
2839+
27452840/* Builds a log line in <dst> based on <lf_expr>, and stops before reaching
27462841 * <maxsize> characters. Returns the size of the output string in characters,
27472842 * not counting the trailing zero which is always added if the resulting size
0 commit comments