]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: regex: replace all standard regex function by own functions
authorThierry FOURNIER <tfournier@exceliance.fr>
Wed, 18 Jun 2014 09:35:54 +0000 (11:35 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 18 Jun 2014 13:07:57 +0000 (15:07 +0200)
This patch remove all references of standard regex in haproxy. The last
remaining references are only in the regex.[ch] files.

In the file src/checks.c, the original function uses a "pmatch" array.
In fact this array is unused. This patch remove it.

include/common/regex.h
include/types/checks.h
include/types/proto_http.h
include/types/proxy.h
src/cfgparse.c
src/checks.c
src/haproxy.c
src/proto_http.c
src/regex.c

index cec68c8858b012207586b8417d54537195de65b6..29a6ace8181b5ff756302f289b2b395c068202d2 100644 (file)
@@ -60,7 +60,7 @@ struct my_regex {
 
 struct hdr_exp {
     struct hdr_exp *next;
-    const regex_t *preg;               /* expression to look for */
+    struct my_regex *preg;             /* expression to look for */
     int action;                                /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
     const char *replace;               /* expression to set instead */
     void *cond;                                /* a possible condition or NULL */
@@ -81,7 +81,7 @@ extern regmatch_t pmatch[MAX_MATCH];
 int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err);
 int exp_replace(char *dst, unsigned int dst_size, char *src, const char *str, const regmatch_t *matches);
 const char *check_replace_string(const char *str);
-const char *chain_regex(struct hdr_exp **head, const regex_t *preg,
+const char *chain_regex(struct hdr_exp **head, struct my_regex *preg,
                        int action, const char *replace, void *cond);
 
 /* If the function doesn't match, it returns false, else it returns true.
index d5038ebc816c24bf6c139360c5e4dab9793ff4be..a50043bb68f360ca6ab8da537b1873ab573a2f2f 100644 (file)
@@ -177,7 +177,7 @@ struct tcpcheck_rule {
        /* sent string is string */
        char *string;                           /* sent or expected string */
        int string_len;                         /* string lenght */
-       regex_t *expect_regex;                  /* expected */
+       struct my_regex *expect_regex;          /* expected */
        int inverse;                            /* 0 = regular match, 1 = inverse match */
        unsigned short port;                    /* port to connect to */
        unsigned short conn_opts;               /* options when setting up a new connection */
index ff196a0cd644fb42e50dca72b22886fb5a92e39a..affc231619f3a68fb8dc4bda69dd1f49f2f29e17 100644 (file)
@@ -419,7 +419,7 @@ struct http_req_rule {
                        char *name;            /* header name */
                        int name_len;          /* header name's length */
                        struct list fmt;       /* log-format compatible expression */
-                       regex_t* re;           /* used by replace-header and replace-value */
+                       struct my_regex re;    /* used by replace-header and replace-value */
                } hdr_add;                     /* args used by "add-header" and "set-header" */
                struct redirect_rule *redir;   /* redirect rule or "http-request redirect" */
                int nice;                      /* nice value for HTTP_REQ_ACT_SET_NICE */
@@ -445,7 +445,7 @@ struct http_res_rule {
                        char *name;            /* header name */
                        int name_len;          /* header name's length */
                        struct list fmt;       /* log-format compatible expression */
-                       regex_t* re;           /* used by replace-header and replace-value */
+                       struct my_regex re;    /* used by replace-header and replace-value */
                } hdr_add;                     /* args used by "add-header" and "set-header" */
                int nice;                      /* nice value for HTTP_RES_ACT_SET_NICE */
                int loglevel;                  /* log-level value for HTTP_RES_ACT_SET_LOGL */
index 33524f3351586ad8ef92a981c53e3712c08fb626..b33b63411c9913d93aaa0a400bcd073e5c135514 100644 (file)
@@ -343,7 +343,7 @@ struct proxy {
        char *check_req;                        /* HTTP or SSL request to use for PR_O_HTTP_CHK|PR_O_SSL3_CHK */
        int check_len;                          /* Length of the HTTP or SSL3 request */
        char *expect_str;                       /* http-check expected content : string or text version of the regex */
-       regex_t *expect_regex;                  /* http-check expected content */
+       struct my_regex *expect_regex;          /* http-check expected content */
        struct chunk errmsg[HTTP_ERR_SIZE];     /* default or customized error messages for known errors */
        int uuid;                               /* universally unique proxy ID, used for SNMP */
        unsigned int backlog;                   /* force the frontend's listen backlog */
index eb4083374253bb9a9b1287c0d09fc1f0a1af57c3..762978a6ccbfc6d58126fb09e7c87da838b8754d 100644 (file)
@@ -1527,11 +1527,14 @@ static int create_cond_regex_rule(const char *file, int line,
                                  const char *cmd, const char *reg, const char *repl,
                                  const char **cond_start)
 {
-       regex_t *preg = NULL;
+       struct my_regex *preg = NULL;
        char *errmsg = NULL;
        const char *err;
+       char *error;
        int ret_code = 0;
        struct acl_cond *cond = NULL;
+       int cs;
+       int cap;
 
        if (px == &defproxy) {
                Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, line, cmd);
@@ -1570,15 +1573,19 @@ static int create_cond_regex_rule(const char *file, int line,
                                          ((px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR),
                                          file, line);
 
-       preg = calloc(1, sizeof(regex_t));
+       preg = calloc(1, sizeof(*preg));
        if (!preg) {
                Alert("parsing [%s:%d] : '%s' : not enough memory to build regex.\n", file, line, cmd);
                ret_code = ERR_ALERT | ERR_FATAL;
                goto err;
        }
 
-       if (regcomp(preg, reg, REG_EXTENDED | flags) != 0) {
-               Alert("parsing [%s:%d] : '%s' : bad regular expression '%s'.\n", file, line, cmd, reg);
+       cs = !(flags & REG_ICASE);
+       cap = !(flags & REG_NOSUB);
+       error = NULL;
+       if (!regex_comp(reg, preg, cs, cap, &error)) {
+               Alert("parsing [%s:%d] : '%s' : regular expression '%s' : %s\n", file, line, cmd, reg, error);
+               free(error);
                ret_code = ERR_ALERT | ERR_FATAL;
                goto err;
        }
@@ -1598,7 +1605,7 @@ static int create_cond_regex_rule(const char *file, int line,
        return ret_code;
 
  err_free:
-       regfree(preg);
+       regex_free(preg);
  err:
        free(preg);
        free(errmsg);
@@ -1811,6 +1818,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
 {
        static struct proxy *curproxy = NULL;
        const char *err;
+       char *error;
        int rc;
        unsigned val;
        int err_code = 0;
@@ -1971,8 +1979,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                curproxy->expect_str = strdup(defproxy.expect_str);
                                if (defproxy.expect_regex) {
                                        /* note: this regex is known to be valid */
-                                       curproxy->expect_regex = calloc(1, sizeof(regex_t));
-                                       regcomp(curproxy->expect_regex, defproxy.expect_str, REG_EXTENDED);
+                                       curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
+                                       regex_comp(defproxy.expect_str, curproxy->expect_regex, 1, 1, NULL);
                                }
                        }
 
@@ -2119,7 +2127,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                defproxy.server_id_hdr_len = 0;
                free(defproxy.expect_str);
                if (defproxy.expect_regex) {
-                       regfree(defproxy.expect_regex);
+                       regex_free(defproxy.expect_regex);
                        free(defproxy.expect_regex);
                        defproxy.expect_regex = NULL;
                }
@@ -4213,15 +4221,17 @@ stats_error_parsing:
                                curproxy->options2 |= PR_O2_EXP_RSTS;
                                free(curproxy->expect_str);
                                if (curproxy->expect_regex) {
-                                       regfree(curproxy->expect_regex);
+                                       regex_free(curproxy->expect_regex);
                                        free(curproxy->expect_regex);
                                        curproxy->expect_regex = NULL;
                                }
                                curproxy->expect_str = strdup(args[cur_arg + 1]);
-                               curproxy->expect_regex = calloc(1, sizeof(regex_t));
-                               if (regcomp(curproxy->expect_regex, args[cur_arg + 1], REG_EXTENDED) != 0) {
-                                       Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s'.\n",
-                                             file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1]);
+                               curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
+                               error = NULL;
+                               if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
+                                       Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
+                                             file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
+                                       free(error);
                                        err_code |= ERR_ALERT | ERR_FATAL;
                                        goto out;
                                }
@@ -4236,15 +4246,17 @@ stats_error_parsing:
                                curproxy->options2 |= PR_O2_EXP_RSTR;
                                free(curproxy->expect_str);
                                if (curproxy->expect_regex) {
-                                       regfree(curproxy->expect_regex);
+                                       regex_free(curproxy->expect_regex);
                                        free(curproxy->expect_regex);
                                        curproxy->expect_regex = NULL;
                                }
                                curproxy->expect_str = strdup(args[cur_arg + 1]);
-                               curproxy->expect_regex = calloc(1, sizeof(regex_t));
-                               if (regcomp(curproxy->expect_regex, args[cur_arg + 1], REG_EXTENDED) != 0) {
-                                       Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s'.\n",
-                                             file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1]);
+                               curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
+                               error = NULL;
+                               if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
+                                       Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
+                                             file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
+                                       free(error);
                                        err_code |= ERR_ALERT | ERR_FATAL;
                                        goto out;
                                }
@@ -4456,10 +4468,12 @@ stats_error_parsing:
                                tcpcheck->action = TCPCHK_ACT_EXPECT;
                                tcpcheck->string_len = 0;
                                tcpcheck->string = NULL;
-                               tcpcheck->expect_regex = calloc(1, sizeof(regex_t));
-                               if (regcomp(tcpcheck->expect_regex, args[cur_arg + 1], REG_EXTENDED) != 0) {
-                                       Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s'.\n",
-                                             file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1]);
+                               tcpcheck->expect_regex = calloc(1, sizeof(*tcpcheck->expect_regex));
+                               error = NULL;
+                               if (!regex_comp(args[cur_arg + 1], tcpcheck->expect_regex, 1, 1, &error)) {
+                                       Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
+                                             file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
+                                       free(error);
                                        err_code |= ERR_ALERT | ERR_FATAL;
                                        goto out;
                                }
index 6b501defa9517571e517cac27ca370d70034b5b0..cba00187304478577badbbb4dc95499003d53f1e 100644 (file)
@@ -1730,7 +1730,7 @@ static int httpchk_expect(struct server *s, int done)
                if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STS)
                        ret = strncmp(s->proxy->expect_str, status_code, 3) == 0;
                else
-                       ret = regexec(s->proxy->expect_regex, status_code, MAX_MATCH, pmatch, 0) == 0;
+                       ret = regex_exec(s->proxy->expect_regex, status_code);
 
                /* we necessarily have the response, so there are no partial failures */
                if (s->proxy->options2 & PR_O2_EXP_INV)
@@ -1782,7 +1782,7 @@ static int httpchk_expect(struct server *s, int done)
                if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STR)
                        ret = strstr(contentptr, s->proxy->expect_str) != NULL;
                else
-                       ret = regexec(s->proxy->expect_regex, contentptr, MAX_MATCH, pmatch, 0) == 0;
+                       ret = regex_exec(s->proxy->expect_regex, contentptr);
 
                /* if we don't match, we may need to wait more */
                if (!ret && !done)
@@ -2135,7 +2135,7 @@ static void tcpcheck_main(struct connection *conn)
                        if (cur->string != NULL)
                                ret = my_memmem(contentptr, check->bi->i, cur->string, cur->string_len) != NULL;
                        else if (cur->expect_regex != NULL)
-                               ret = regexec(cur->expect_regex, contentptr, MAX_MATCH, pmatch, 0) == 0;
+                               ret = regex_exec(cur->expect_regex, contentptr);
 
                        if (!ret && !done)
                                continue; /* try to read more */
index cd42b348af0d387571ad325aac4e9a45358e3016..9f742c75b1bfb039ee57b700cc89b9e5703e7c5c 100644 (file)
@@ -1034,8 +1034,8 @@ void deinit(void)
 
                for (exp = p->req_exp; exp != NULL; ) {
                        if (exp->preg) {
-                               regfree((regex_t *)exp->preg);
-                               free((regex_t *)exp->preg);
+                               regex_free(exp->preg);
+                               free(exp->preg);
                        }
 
                        if (exp->replace && exp->action != ACT_SETBE)
@@ -1047,8 +1047,8 @@ void deinit(void)
 
                for (exp = p->rsp_exp; exp != NULL; ) {
                        if (exp->preg) {
-                               regfree((regex_t *)exp->preg);
-                               free((regex_t *)exp->preg);
+                               regex_free(exp->preg);
+                               free(exp->preg);
                        }
 
                        if (exp->replace && exp->action != ACT_SETBE)
index 572739db4c5cb0873036816a80a1960c12110854..e61f51274e4bdeaead02ed1e0c9799a5e55a4b20 100644 (file)
@@ -3179,10 +3179,10 @@ static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
 /* Returns the number of characters written to destination,
  * -1 on internal error and -2 if no replacement took place.
  */
-static int http_replace_header(regex_t* re, char* dst, uint dst_size, char* val,
-                               const charrep_str)
+static int http_replace_header(struct my_regex *re, char *dst, uint dst_size, char *val,
+                               const char *rep_str)
 {
-       if (regexec(re, val, MAX_MATCH, pmatch, 0))
+       if (!regex_exec_match(re, val, MAX_MATCH, pmatch))
                return -2;
 
        return exp_replace(dst, dst_size, val, rep_str, pmatch);
@@ -3191,8 +3191,8 @@ static int http_replace_header(regex_t* re, char* dst, uint dst_size, char* val,
 /* Returns the number of characters written to destination,
  * -1 on internal error and -2 if no replacement took place.
  */
-static int http_replace_value(regex_t* re, char* dst, uint dst_size, char* val, char delim,
-                              const charrep_str)
+static int http_replace_value(struct my_regex *re, char *dst, uint dst_size, char *val, char delim,
+                              const char *rep_str)
 {
        char* p = val;
        char* dst_end = dst + dst_size;
@@ -3209,7 +3209,7 @@ static int http_replace_value(regex_t* re, char* dst, uint dst_size, char* val,
                        tok_end = p + strlen(p);
                }
 
-               if (regexec(re, p, MAX_MATCH, pmatch, 0) == 0) {
+               if (regex_exec_match(re, p, MAX_MATCH, pmatch)) {
                        int replace_n = exp_replace(dst_p, dst_end - dst_p, p, rep_str, pmatch);
 
                        if (replace_n < 0)
@@ -3243,7 +3243,7 @@ static int http_replace_value(regex_t* re, char* dst, uint dst_size, char* val,
 }
 
 static int http_transform_header(struct session* s, struct http_msg *msg, const char* name, uint name_len,
-                                 char* buf, struct hdr_idx* idx, struct list *fmt, regex_t* re,
+                                 char* buf, struct hdr_idx* idx, struct list *fmt, struct my_regex *re,
                                  struct hdr_ctx* ctx, int action)
 {
        ctx->idx = 0;
@@ -3389,7 +3389,7 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
                case HTTP_REQ_ACT_REPLACE_VAL:
                        if (http_transform_header(s, &txn->req, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
                                                  txn->req.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt,
-                                                 rule->arg.hdr_add.re, &ctx, rule->action))
+                                                 &rule->arg.hdr_add.re, &ctx, rule->action))
                                return HTTP_RULE_RES_BADREQ;
                        break;
 
@@ -3578,7 +3578,7 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
                case HTTP_RES_ACT_REPLACE_VAL:
                        if (http_transform_header(s, &txn->rsp, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
                                                  txn->rsp.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt,
-                                                 rule->arg.hdr_add.re, &ctx, rule->action))
+                                                 &rule->arg.hdr_add.re, &ctx, rule->action))
                                return NULL; /* note: we should report an error here */
                        break;
 
@@ -6924,7 +6924,7 @@ int apply_filter_to_req_headers(struct session *s, struct channel *req, struct h
                term = *cur_end;
                *cur_end = '\0';
 
-               if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+               if (regex_exec_match(exp->preg, cur_ptr, MAX_MATCH, pmatch)) {
                        switch (exp->action) {
                        case ACT_SETBE:
                                /* It is not possible to jump a second time.
@@ -7036,7 +7036,7 @@ int apply_filter_to_req_line(struct session *s, struct channel *req, struct hdr_
        term = *cur_end;
        *cur_end = '\0';
 
-       if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+       if (regex_exec_match(exp->preg, cur_ptr, MAX_MATCH, pmatch)) {
                switch (exp->action) {
                case ACT_SETBE:
                        /* It is not possible to jump a second time.
@@ -7807,7 +7807,7 @@ int apply_filter_to_resp_headers(struct session *s, struct channel *rtr, struct
                term = *cur_end;
                *cur_end = '\0';
 
-               if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+               if (regex_exec_match(exp->preg, cur_ptr, MAX_MATCH, pmatch)) {
                        switch (exp->action) {
                        case ACT_ALLOW:
                                txn->flags |= TX_SVALLOW;
@@ -7899,7 +7899,7 @@ int apply_filter_to_sts_line(struct session *s, struct channel *rtr, struct hdr_
        term = *cur_end;
        *cur_end = '\0';
 
-       if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+       if (regex_exec_match(exp->preg, cur_ptr, MAX_MATCH, pmatch)) {
                switch (exp->action) {
                case ACT_ALLOW:
                        txn->flags |= TX_SVALLOW;
@@ -8895,21 +8895,13 @@ void http_reset_txn(struct session *s)
        s->rep->analyse_exp = TICK_ETERNITY;
 }
 
-static inline void free_regex(regex_t* re)
-{
-       if (re) {
-               regfree(re);
-               free(re);
-       }
-}
-
 void free_http_res_rules(struct list *r)
 {
        struct http_res_rule *tr, *pr;
 
        list_for_each_entry_safe(pr, tr, r, list) {
                LIST_DEL(&pr->list);
-               free_regex(pr->arg.hdr_add.re);
+               regex_free(&pr->arg.hdr_add.re);
                free(pr);
        }
 }
@@ -8923,7 +8915,7 @@ void free_http_req_rules(struct list *r)
                if (pr->action == HTTP_REQ_ACT_AUTH)
                        free(pr->arg.auth.realm);
 
-               free_regex(pr->arg.hdr_add.re);
+               regex_free(&pr->arg.hdr_add.re);
                free(pr);
        }
 }
@@ -8934,6 +8926,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
        struct http_req_rule *rule;
        struct http_req_action_kw *custom = NULL;
        int cur_arg;
+       char *error;
 
        rule = (struct http_req_rule*)calloc(1, sizeof(struct http_req_rule));
        if (!rule) {
@@ -9081,14 +9074,11 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i
                rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
                LIST_INIT(&rule->arg.hdr_add.fmt);
 
-               if (!(rule->arg.hdr_add.re = calloc(1, sizeof(*rule->arg.hdr_add.re)))) {
-                       Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
-                       goto out_err;
-               }
-
-               if (regcomp(rule->arg.hdr_add.re, args[cur_arg + 1], REG_EXTENDED)) {
-                       Alert("parsing [%s:%d] : '%s' : bad regular expression.\n", file, linenum,
-                             args[cur_arg + 1]);
+               error = NULL;
+               if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
+                       Alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
+                             args[cur_arg + 1], error);
+                       free(error);
                        goto out_err;
                }
 
@@ -9303,6 +9293,7 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
        struct http_res_rule *rule;
        struct http_res_action_kw *custom = NULL;
        int cur_arg;
+       char *error;
 
        rule = calloc(1, sizeof(*rule));
        if (!rule) {
@@ -9435,14 +9426,11 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i
                rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
                LIST_INIT(&rule->arg.hdr_add.fmt);
 
-               if (!(rule->arg.hdr_add.re = calloc(1, sizeof(*rule->arg.hdr_add.re)))) {
-                       Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
-                       goto out_err;
-               }
-
-               if (regcomp(rule->arg.hdr_add.re, args[cur_arg + 1], REG_EXTENDED)) {
-                       Alert("parsing [%s:%d] : '%s' : bad regular expression.\n", file, linenum,
-                             args[cur_arg + 1]);
+               error = NULL;
+               if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
+                       Alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
+                             args[cur_arg + 1], error);
+                       free(error);
                        goto out_err;
                }
 
index 8de56e6c0afc6e4c6848eb2552f1f8c4640a5eec..22920026aecf4d3822cbe421af602d73226cd3f8 100644 (file)
@@ -124,7 +124,7 @@ const char *check_replace_string(const char *str)
 
 
 /* returns the pointer to an error in the replacement string, or NULL if OK */
-const char *chain_regex(struct hdr_exp **head, const regex_t *preg,
+const char *chain_regex(struct hdr_exp **head, struct my_regex *preg,
                        int action, const char *replace, void *cond)
 {
        struct hdr_exp *exp;