CLEANUP: promex: make the applet use its own context

The prometheus applet used to map to the stats context since it was not
convenient to have one's own context, and to reuse the fields with its
own values and enums. The obj1 pointer was used both for proxies and
stick-tables; obj2 was used both for servers and listeners.

This change makes use of the generic command context allocation so that
the there's now a properly typed context for prometheus, defined in the
code itself and independent on the stats or appctx ones. For clarity,
the types are correctly set and there's one proxy, one table, one server
and one listener. Some could be compacted using unions but that's not
necessary since the context is reasonably compact. The stats' st_code
field was used as the object state so the new field name is obj_state.

An attempt was made to change the types to const for what us only visited
but some calls pass through the stats code to retrieve info and that code
uses non-const variables due to internal API limitations (read_freq_ctr()
being used and requiring variable). That could change in the future,
though.
diff --git a/addons/promex/service-prometheus.c b/addons/promex/service-prometheus.c
index 99c3ca7..e4cf8ea 100644
--- a/addons/promex/service-prometheus.c
+++ b/addons/promex/service-prometheus.c
@@ -60,7 +60,7 @@
 	PROMEX_DUMPER_DONE,       /* finished */
 };
 
-/* Prometheus exporter flags (appctx->ctx.stats.flags) */
+/* Prometheus exporter flags (ctx->flags) */
 #define PROMEX_FL_METRIC_HDR        0x00000001
 #define PROMEX_FL_INFO_METRIC       0x00000002
 #define PROMEX_FL_FRONT_METRIC      0x00000004
@@ -80,6 +80,16 @@
 			     PROMEX_FL_SCOPE_LI | PROMEX_FL_SCOPE_BACK | \
 			     PROMEX_FL_SCOPE_SERVER | PROMEX_FL_SCOPE_STICKTABLE)
 
+/* the context of the applet */
+struct promex_ctx {
+	struct proxy *px;          /* current proxy */
+	struct stktable *st;       /* current table */
+	struct listener *li;       /* current listener */
+	struct server *sv;         /* current server */
+	unsigned int flags;	   /* PROMEX_FL_* */
+	int obj_state;             /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */
+};
+
 /* Promtheus metric type (gauge or counter) */
 enum promex_mt_type {
 	PROMEX_MT_GAUGE   = 1,
@@ -480,6 +490,7 @@
 			      struct promex_label *labels, struct ist *out, size_t max)
 {
 	struct ist name = { .ptr = (char[PROMEX_MAX_NAME_LEN]){ 0 }, .len = 0 };
+	struct promex_ctx *ctx = appctx->svcctx;
 	size_t len = out->len;
 
 	if (out->len + PROMEX_MAX_METRIC_LENGTH > max)
@@ -490,7 +501,7 @@
 	istcat(&name, metric->n, PROMEX_MAX_NAME_LEN);
 
 
-	if ((appctx->ctx.stats.flags & PROMEX_FL_METRIC_HDR) &&
+	if ((ctx->flags & PROMEX_FL_METRIC_HDR) &&
 	    !promex_dump_metric_header(appctx, htx, metric, name, out, max))
 		goto full;
 
@@ -528,7 +539,7 @@
 		goto full;
 	out->len = trash.data;
 
-	appctx->ctx.stats.flags &= ~PROMEX_FL_METRIC_HDR;
+	ctx->flags &= ~PROMEX_FL_METRIC_HDR;
 	return 1;
   full:
 	// Restore previous length
@@ -543,6 +554,7 @@
 static int promex_dump_global_metrics(struct appctx *appctx, struct htx *htx)
 {
 	static struct ist prefix = IST("haproxy_process_");
+	struct promex_ctx *ctx = appctx->svcctx;
 	struct field val;
 	struct channel *chn = cs_ic(appctx->owner);
 	struct ist out = ist2(trash.area, 0);
@@ -555,7 +567,7 @@
 	for (; appctx->st2 < INF_TOTAL_FIELDS; appctx->st2++) {
 		struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 
-		if (!(promex_global_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
+		if (!(promex_global_metrics[appctx->st2].flags & ctx->flags))
 			continue;
 
 		switch (appctx->st2) {
@@ -573,7 +585,7 @@
 					&val, labels, &out, max))
 			goto full;
 
-		appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
+		ctx->flags |= PROMEX_FL_METRIC_HDR;
 	}
 
   end:
@@ -593,6 +605,7 @@
 static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
 {
 	static struct ist prefix = IST("haproxy_frontend_");
+	struct promex_ctx *ctx = appctx->svcctx;
 	struct proxy *px;
 	struct field val;
 	struct channel *chn = cs_ic(appctx->owner);
@@ -603,13 +616,13 @@
 	enum promex_front_state state;
 
 	for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
-		if (!(promex_st_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
+		if (!(promex_st_metrics[appctx->st2].flags & ctx->flags))
 			continue;
 
-		while (appctx->ctx.stats.obj1) {
+		while (ctx->px) {
 			struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 
-			px = appctx->ctx.stats.obj1;
+			px = ctx->px;
 
 			labels[0].name  = ist("proxy");
 			labels[0].value = ist2(px->id, strlen(px->id));
@@ -624,15 +637,15 @@
 			switch (appctx->st2) {
 				case ST_F_STATUS:
 					state = !(px->flags & PR_FL_STOPPED);
-					for (; appctx->ctx.stats.st_code < PROMEX_FRONT_STATE_COUNT; appctx->ctx.stats.st_code++) {
+					for (; ctx->obj_state < PROMEX_FRONT_STATE_COUNT; ctx->obj_state++) {
 						labels[1].name = ist("state");
-						labels[1].value = promex_front_st[appctx->ctx.stats.st_code];
-						val = mkf_u32(FO_STATUS, state == appctx->ctx.stats.st_code);
+						labels[1].value = promex_front_st[ctx->obj_state];
+						val = mkf_u32(FO_STATUS, state == ctx->obj_state);
 						if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
 									&val, labels, &out, max))
 							goto full;
 					}
-					appctx->ctx.stats.st_code = 0;
+					ctx->obj_state = 0;
 					goto next_px;
 				case ST_F_REQ_RATE_MAX:
 				case ST_F_REQ_TOT:
@@ -656,7 +669,7 @@
 					if (px->mode != PR_MODE_HTTP)
 						goto next_px;
 					if (appctx->st2 != ST_F_HRSP_1XX)
-						appctx->ctx.stats.flags &= ~PROMEX_FL_METRIC_HDR;
+						ctx->flags &= ~PROMEX_FL_METRIC_HDR;
 					labels[1].name = ist("code");
 					labels[1].value = promex_hrsp_code[appctx->st2 - ST_F_HRSP_1XX];
 					val = stats[appctx->st2];
@@ -670,10 +683,10 @@
 						&val, labels, &out, max))
 				goto full;
 		  next_px:
-			appctx->ctx.stats.obj1 = px->next;
+			ctx->px = px->next;
 		}
-		appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
-		appctx->ctx.stats.obj1 = proxies_list;
+		ctx->flags |= PROMEX_FL_METRIC_HDR;
+		ctx->px = proxies_list;
 	}
 
   end:
@@ -693,6 +706,7 @@
 static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
 {
 	static struct ist prefix = IST("haproxy_listener_");
+	struct promex_ctx *ctx = appctx->svcctx;
 	struct proxy *px;
 	struct field val;
 	struct channel *chn = cs_ic(appctx->owner);
@@ -704,13 +718,13 @@
 	enum li_status status;
 
 	for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
-		if (!(promex_st_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
+		if (!(promex_st_metrics[appctx->st2].flags & ctx->flags))
 			continue;
 
-		while (appctx->ctx.stats.obj1) {
+		while (ctx->px) {
 			struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 
-			px = appctx->ctx.stats.obj1;
+			px = ctx->px;
 
 			labels[0].name  = ist("proxy");
 			labels[0].value = ist2(px->id, strlen(px->id));
@@ -719,7 +733,7 @@
 			if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
 				goto next_px;
 
-			li = appctx->ctx.stats.obj2;
+			li = ctx->li;
 			list_for_each_entry_from(li, &px->conf.listeners, by_fe) {
 
 				if (!li->counters)
@@ -735,15 +749,15 @@
 				switch (appctx->st2) {
 					case ST_F_STATUS:
 						status = get_li_status(li);
-						for (; appctx->ctx.stats.st_code < LI_STATE_COUNT; appctx->ctx.stats.st_code++) {
-							val = mkf_u32(FO_STATUS, status == appctx->ctx.stats.st_code);
+						for (; ctx->obj_state < LI_STATE_COUNT; ctx->obj_state++) {
+							val = mkf_u32(FO_STATUS, status == ctx->obj_state);
 							labels[2].name = ist("state");
-							labels[2].value = ist(li_status_st[appctx->ctx.stats.st_code]);
+							labels[2].value = ist(li_status_st[ctx->obj_state]);
 							if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
 										&val, labels, &out, max))
 								goto full;
 						}
-						appctx->ctx.stats.st_code = 0;
+						ctx->obj_state = 0;
 						continue;
 					default:
 						val = stats[appctx->st2];
@@ -757,12 +771,12 @@
 
 		  next_px:
 			px = px->next;
-			appctx->ctx.stats.obj1 = px;
-			appctx->ctx.stats.obj2 = (px ? LIST_NEXT(&px->conf.listeners, struct listener *, by_fe) : NULL);
+			ctx->px = px;
+			ctx->li = (px ? LIST_NEXT(&px->conf.listeners, struct listener *, by_fe) : NULL);
 		}
-		appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
-		appctx->ctx.stats.obj1 = proxies_list;
-		appctx->ctx.stats.obj2 =  LIST_NEXT(&proxies_list->conf.listeners, struct listener *, by_fe);
+		ctx->flags |= PROMEX_FL_METRIC_HDR;
+		ctx->px = proxies_list;
+		ctx->li =  LIST_NEXT(&proxies_list->conf.listeners, struct listener *, by_fe);
 	}
 
   end:
@@ -773,7 +787,7 @@
 	}
 	return ret;
   full:
-	appctx->ctx.stats.obj2 = li;
+	ctx->li = li;
 	ret = 0;
 	goto end;
 }
@@ -783,6 +797,7 @@
 static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
 {
 	static struct ist prefix = IST("haproxy_backend_");
+	struct promex_ctx *ctx = appctx->svcctx;
 	struct proxy *px;
 	struct server *sv;
 	struct field val;
@@ -796,14 +811,14 @@
 	enum promex_srv_state srv_state;
 
 	for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
-		if (!(promex_st_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
+		if (!(promex_st_metrics[appctx->st2].flags & ctx->flags))
 			continue;
 
-		while (appctx->ctx.stats.obj1) {
+		while (ctx->px) {
 			struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 			unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 };
 
-			px = appctx->ctx.stats.obj1;
+			px = ctx->px;
 
 			labels[0].name  = ist("proxy");
 			labels[0].value = ist2(px->id, strlen(px->id));
@@ -825,27 +840,27 @@
 						srv_state_count[srv_state] += 1;
 						sv = sv->next;
 					}
-					for (; appctx->ctx.stats.st_code < PROMEX_SRV_STATE_COUNT; appctx->ctx.stats.st_code++) {
-						val = mkf_u32(FN_GAUGE, srv_state_count[appctx->ctx.stats.st_code]);
+					for (; ctx->obj_state < PROMEX_SRV_STATE_COUNT; ctx->obj_state++) {
+						val = mkf_u32(FN_GAUGE, srv_state_count[ctx->obj_state]);
 						labels[1].name = ist("state");
-						labels[1].value = promex_srv_st[appctx->ctx.stats.st_code];
+						labels[1].value = promex_srv_st[ctx->obj_state];
 						if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
 									&val, labels, &out, max))
 							goto full;
 					}
-					appctx->ctx.stats.st_code = 0;
+					ctx->obj_state = 0;
 					goto next_px;
 				case ST_F_STATUS:
 					bkd_state = ((px->lbprm.tot_weight > 0 || !px->srv) ? 1 : 0);
-					for (; appctx->ctx.stats.st_code < PROMEX_BACK_STATE_COUNT; appctx->ctx.stats.st_code++) {
+					for (; ctx->obj_state < PROMEX_BACK_STATE_COUNT; ctx->obj_state++) {
 						labels[1].name = ist("state");
-						labels[1].value = promex_back_st[appctx->ctx.stats.st_code];
-						val = mkf_u32(FO_STATUS, bkd_state == appctx->ctx.stats.st_code);
+						labels[1].value = promex_back_st[ctx->obj_state];
+						val = mkf_u32(FO_STATUS, bkd_state == ctx->obj_state);
 						if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
 									&val, labels, &out, max))
 							goto full;
 					}
-					appctx->ctx.stats.st_code = 0;
+					ctx->obj_state = 0;
 					goto next_px;
 				case ST_F_QTIME:
 					secs = (double)swrate_avg(px->be_counters.q_time, TIME_STATS_SAMPLES) / 1000.0;
@@ -899,7 +914,7 @@
 					if (px->mode != PR_MODE_HTTP)
 						goto next_px;
 					if (appctx->st2 != ST_F_HRSP_1XX)
-						appctx->ctx.stats.flags &= ~PROMEX_FL_METRIC_HDR;
+						ctx->flags &= ~PROMEX_FL_METRIC_HDR;
 					labels[1].name = ist("code");
 					labels[1].value = promex_hrsp_code[appctx->st2 - ST_F_HRSP_1XX];
 					val = stats[appctx->st2];
@@ -913,10 +928,10 @@
 						&val, labels, &out, max))
 				goto full;
 		  next_px:
-			appctx->ctx.stats.obj1 = px->next;
+			ctx->px = px->next;
 		}
-		appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
-		appctx->ctx.stats.obj1 = proxies_list;
+		ctx->flags |= PROMEX_FL_METRIC_HDR;
+		ctx->px = proxies_list;
 	}
 
   end:
@@ -936,6 +951,7 @@
 static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
 {
 	static struct ist prefix = IST("haproxy_server_");
+	struct promex_ctx *ctx = appctx->svcctx;
 	struct proxy *px;
 	struct server *sv;
 	struct field val;
@@ -949,13 +965,13 @@
 	const char *check_state;
 
 	for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
-		if (!(promex_st_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
+		if (!(promex_st_metrics[appctx->st2].flags & ctx->flags))
 			continue;
 
-		while (appctx->ctx.stats.obj1) {
+		while (ctx->px) {
 			struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 
-			px = appctx->ctx.stats.obj1;
+			px = ctx->px;
 
 			labels[0].name  = ist("proxy");
 			labels[0].value = ist2(px->id, strlen(px->id));
@@ -964,8 +980,8 @@
 			if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
 				goto next_px;
 
-			while (appctx->ctx.stats.obj2) {
-				sv = appctx->ctx.stats.obj2;
+			while (ctx->sv) {
+				sv = ctx->sv;
 
 				labels[1].name  = ist("server");
 				labels[1].value = ist2(sv->id, strlen(sv->id));
@@ -973,21 +989,21 @@
 				if (!stats_fill_sv_stats(px, sv, 0, stats, ST_F_TOTAL_FIELDS, &(appctx->st2)))
 					return -1;
 
-				if ((appctx->ctx.stats.flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT))
+				if ((ctx->flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT))
 					goto next_sv;
 
 				switch (appctx->st2) {
 					case ST_F_STATUS:
 						state = promex_srv_status(sv);
-						for (; appctx->ctx.stats.st_code < PROMEX_SRV_STATE_COUNT; appctx->ctx.stats.st_code++) {
-							val = mkf_u32(FO_STATUS, state == appctx->ctx.stats.st_code);
+						for (; ctx->obj_state < PROMEX_SRV_STATE_COUNT; ctx->obj_state++) {
+							val = mkf_u32(FO_STATUS, state == ctx->obj_state);
 							labels[2].name = ist("state");
-							labels[2].value = promex_srv_st[appctx->ctx.stats.st_code];
+							labels[2].value = promex_srv_st[ctx->obj_state];
 							if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
 										&val, labels, &out, max))
 								goto full;
 						}
-						appctx->ctx.stats.st_code = 0;
+						ctx->obj_state = 0;
 						goto next_sv;
 					case ST_F_QTIME:
 						secs = (double)swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES) / 1000.0;
@@ -1025,18 +1041,18 @@
 						if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED)
 							goto next_sv;
 
-						for (; appctx->ctx.stats.st_code < HCHK_STATUS_SIZE; appctx->ctx.stats.st_code++) {
-							if (get_check_status_result(appctx->ctx.stats.st_code) < CHK_RES_FAILED)
+						for (; ctx->obj_state < HCHK_STATUS_SIZE; ctx->obj_state++) {
+							if (get_check_status_result(ctx->obj_state) < CHK_RES_FAILED)
 								continue;
-							val = mkf_u32(FO_STATUS, sv->check.status == appctx->ctx.stats.st_code);
-							check_state = get_check_status_info(appctx->ctx.stats.st_code);
+							val = mkf_u32(FO_STATUS, sv->check.status == ctx->obj_state);
+							check_state = get_check_status_info(ctx->obj_state);
 							labels[2].name = ist("state");
 							labels[2].value = ist(check_state);
 							if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
 										&val, labels, &out, max))
 								goto full;
 						}
-						appctx->ctx.stats.st_code = 0;
+						ctx->obj_state = 0;
 						goto next_sv;
 					case ST_F_CHECK_CODE:
 						if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED)
@@ -1063,7 +1079,7 @@
 						if (px->mode != PR_MODE_HTTP)
 							goto next_px;
 						if (appctx->st2 != ST_F_HRSP_1XX)
-							appctx->ctx.stats.flags &= ~PROMEX_FL_METRIC_HDR;
+							ctx->flags &= ~PROMEX_FL_METRIC_HDR;
 						labels[2].name = ist("code");
 						labels[2].value = promex_hrsp_code[appctx->st2 - ST_F_HRSP_1XX];
 						val = stats[appctx->st2];
@@ -1077,16 +1093,16 @@
 							&val, labels, &out, max))
 					goto full;
 			  next_sv:
-				appctx->ctx.stats.obj2 = sv->next;
+				ctx->sv = sv->next;
 			}
 
 		  next_px:
-			appctx->ctx.stats.obj1 = px->next;
-			appctx->ctx.stats.obj2 = (appctx->ctx.stats.obj1 ? ((struct proxy *)appctx->ctx.stats.obj1)->srv : NULL);
+			ctx->px = px->next;
+			ctx->sv = (ctx->px ? ctx->px->srv : NULL);
 		}
-		appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
-		appctx->ctx.stats.obj1 = proxies_list;
-		appctx->ctx.stats.obj2 = (appctx->ctx.stats.obj1 ? ((struct proxy *)appctx->ctx.stats.obj1)->srv : NULL);
+		ctx->flags |= PROMEX_FL_METRIC_HDR;
+		ctx->px = proxies_list;
+		ctx->sv = (ctx->px ? ctx->px->srv : NULL);
 	}
 
 
@@ -1107,6 +1123,7 @@
 static int promex_dump_sticktable_metrics(struct appctx *appctx, struct htx *htx)
 {
 	static struct ist prefix = IST("haproxy_sticktable_");
+	struct promex_ctx *ctx = appctx->svcctx;
 	struct field val;
 	struct channel *chn = cs_ic(appctx->owner);
 	struct ist out = ist2(trash.area, 0);
@@ -1115,13 +1132,13 @@
 	struct stktable *t;
 
 	for (; appctx->st2 < STICKTABLE_TOTAL_FIELDS; appctx->st2++) {
-		if (!(promex_sticktable_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
+		if (!(promex_sticktable_metrics[appctx->st2].flags & ctx->flags))
 			continue;
 
-		while (appctx->ctx.stats.obj1) {
+		while (ctx->st) {
 			struct promex_label labels[PROMEX_MAX_LABELS - 1] = {};
 
-			t = appctx->ctx.stats.obj1;
+			t = ctx->st;
 			if (!t->size)
 				goto next_px;
 
@@ -1146,10 +1163,10 @@
 				goto full;
 
 		  next_px:
-			appctx->ctx.stats.obj1 = t->next;
+			ctx->st = t->next;
 		}
-		appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
-		appctx->ctx.stats.obj1 = stktables_list;
+		ctx->flags |= PROMEX_FL_METRIC_HDR;
+		ctx->st = stktables_list;
 	}
 
   end:
@@ -1167,24 +1184,28 @@
 /* Dump all metrics (global, frontends, backends and servers) depending on the
  * dumper state (appctx->st1). It returns 1 on success, 0 if <htx> is full and
  * -1 in case of any error.
- * Uses <appctx.ctx.stats.obj1> as a pointer to the current proxy and <obj2> as
- * a pointer to the current server/listener. */
+ * Uses <appctx.ctx.stats.px> as a pointer to the current proxy and <sv>/<li>
+ * as pointers to the current server/listener respectively.
+ */
 static int promex_dump_metrics(struct appctx *appctx, struct conn_stream *cs, struct htx *htx)
 {
+	struct promex_ctx *ctx = appctx->svcctx;
 	int ret;
 
 	switch (appctx->st1) {
 		case PROMEX_DUMPER_INIT:
-			appctx->ctx.stats.obj1 = NULL;
-			appctx->ctx.stats.obj2 = NULL;
-			appctx->ctx.stats.flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_INFO_METRIC);
-			appctx->ctx.stats.st_code = 0;
+			ctx->px = NULL;
+			ctx->st = NULL;
+			ctx->li = NULL;
+			ctx->sv = NULL;
+			ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_INFO_METRIC);
+			ctx->obj_state = 0;
 			appctx->st2 = INF_NAME;
 			appctx->st1 = PROMEX_DUMPER_GLOBAL;
 			/* fall through */
 
 		case PROMEX_DUMPER_GLOBAL:
-			if (appctx->ctx.stats.flags & PROMEX_FL_SCOPE_GLOBAL) {
+			if (ctx->flags & PROMEX_FL_SCOPE_GLOBAL) {
 				ret = promex_dump_global_metrics(appctx, htx);
 				if (ret <= 0) {
 					if (ret == -1)
@@ -1193,17 +1214,19 @@
 				}
 			}
 
-			appctx->ctx.stats.obj1 = proxies_list;
-			appctx->ctx.stats.obj2 = NULL;
-			appctx->ctx.stats.flags &= ~PROMEX_FL_INFO_METRIC;
-			appctx->ctx.stats.flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_FRONT_METRIC);
-			appctx->ctx.stats.st_code = 0;
+			ctx->px = proxies_list;
+			ctx->st = NULL;
+			ctx->li = NULL;
+			ctx->sv = NULL;
+			ctx->flags &= ~PROMEX_FL_INFO_METRIC;
+			ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_FRONT_METRIC);
+			ctx->obj_state = 0;
 			appctx->st2 = ST_F_PXNAME;
 			appctx->st1 = PROMEX_DUMPER_FRONT;
 			/* fall through */
 
 		case PROMEX_DUMPER_FRONT:
-			if (appctx->ctx.stats.flags & PROMEX_FL_SCOPE_FRONT) {
+			if (ctx->flags & PROMEX_FL_SCOPE_FRONT) {
 				ret = promex_dump_front_metrics(appctx, htx);
 				if (ret <= 0) {
 					if (ret == -1)
@@ -1212,17 +1235,19 @@
 				}
 			}
 
-			appctx->ctx.stats.obj1 = proxies_list;
-			appctx->ctx.stats.obj2 =  LIST_NEXT(&proxies_list->conf.listeners, struct listener *, by_fe);
-			appctx->ctx.stats.flags &= ~PROMEX_FL_FRONT_METRIC;
-			appctx->ctx.stats.flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_LI_METRIC);
-			appctx->ctx.stats.st_code = 0;
+			ctx->px = proxies_list;
+			ctx->st = NULL;
+			ctx->li = LIST_NEXT(&proxies_list->conf.listeners, struct listener *, by_fe);
+			ctx->sv = NULL;
+			ctx->flags &= ~PROMEX_FL_FRONT_METRIC;
+			ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_LI_METRIC);
+			ctx->obj_state = 0;
 			appctx->st2 = ST_F_PXNAME;
 			appctx->st1 = PROMEX_DUMPER_LI;
 			/* fall through */
 
 		case PROMEX_DUMPER_LI:
-			if (appctx->ctx.stats.flags & PROMEX_FL_SCOPE_LI) {
+			if (ctx->flags & PROMEX_FL_SCOPE_LI) {
 				ret = promex_dump_listener_metrics(appctx, htx);
 				if (ret <= 0) {
 					if (ret == -1)
@@ -1231,17 +1256,19 @@
 				}
 			}
 
-			appctx->ctx.stats.obj1 = proxies_list;
-			appctx->ctx.stats.obj2 = NULL;
-			appctx->ctx.stats.flags &= ~PROMEX_FL_LI_METRIC;
-			appctx->ctx.stats.flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_BACK_METRIC);
-			appctx->ctx.stats.st_code = 0;
+			ctx->px = proxies_list;
+			ctx->st = NULL;
+			ctx->li = NULL;
+			ctx->sv = NULL;
+			ctx->flags &= ~PROMEX_FL_LI_METRIC;
+			ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_BACK_METRIC);
+			ctx->obj_state = 0;
 			appctx->st2 = ST_F_PXNAME;
 			appctx->st1 = PROMEX_DUMPER_BACK;
 			/* fall through */
 
 		case PROMEX_DUMPER_BACK:
-			if (appctx->ctx.stats.flags & PROMEX_FL_SCOPE_BACK) {
+			if (ctx->flags & PROMEX_FL_SCOPE_BACK) {
 				ret = promex_dump_back_metrics(appctx, htx);
 				if (ret <= 0) {
 					if (ret == -1)
@@ -1250,17 +1277,19 @@
 				}
 			}
 
-			appctx->ctx.stats.obj1 = proxies_list;
-			appctx->ctx.stats.obj2 = (appctx->ctx.stats.obj1 ? ((struct proxy *)appctx->ctx.stats.obj1)->srv : NULL);
-			appctx->ctx.stats.flags &= ~PROMEX_FL_BACK_METRIC;
-			appctx->ctx.stats.flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
-			appctx->ctx.stats.st_code = 0;
+			ctx->px = proxies_list;
+			ctx->st = NULL;
+			ctx->li = NULL;
+			ctx->sv = ctx->px ? ctx->px->srv : NULL;
+			ctx->flags &= ~PROMEX_FL_BACK_METRIC;
+			ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
+			ctx->obj_state = 0;
 			appctx->st2 = ST_F_PXNAME;
 			appctx->st1 = PROMEX_DUMPER_SRV;
 			/* fall through */
 
 		case PROMEX_DUMPER_SRV:
-			if (appctx->ctx.stats.flags & PROMEX_FL_SCOPE_SERVER) {
+			if (ctx->flags & PROMEX_FL_SCOPE_SERVER) {
 				ret = promex_dump_srv_metrics(appctx, htx);
 				if (ret <= 0) {
 					if (ret == -1)
@@ -1269,16 +1298,18 @@
 				}
 			}
 
-			appctx->ctx.stats.obj1 = stktables_list;
-			appctx->ctx.stats.obj2 = NULL;
-			appctx->ctx.stats.flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
-			appctx->ctx.stats.flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
+			ctx->px = NULL;
+			ctx->st = stktables_list;
+			ctx->li = NULL;
+			ctx->sv = NULL;
+			ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
+			ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
 			appctx->st2 = STICKTABLE_SIZE;
 			appctx->st1 = PROMEX_DUMPER_STICKTABLE;
 			/* fall through */
 
 		case PROMEX_DUMPER_STICKTABLE:
-			if (appctx->ctx.stats.flags & PROMEX_FL_SCOPE_STICKTABLE) {
+			if (ctx->flags & PROMEX_FL_SCOPE_STICKTABLE) {
 				ret = promex_dump_sticktable_metrics(appctx, htx);
 				if (ret <= 0) {
 					if (ret == -1)
@@ -1287,9 +1318,11 @@
 				}
 			}
 
-			appctx->ctx.stats.obj1 = NULL;
-			appctx->ctx.stats.obj2 = NULL;
-			appctx->ctx.stats.flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
+			ctx->px = NULL;
+			ctx->st = NULL;
+			ctx->li = NULL;
+			ctx->sv = NULL;
+			ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
 			appctx->st2 = 0;
 			appctx->st1 = PROMEX_DUMPER_DONE;
 			/* fall through */
@@ -1306,9 +1339,11 @@
 	return 0;
   error:
 	/* unrecoverable error */
-	appctx->ctx.stats.obj1 = NULL;
-	appctx->ctx.stats.obj2 = NULL;
-	appctx->ctx.stats.flags = 0;
+	ctx->px = NULL;
+	ctx->st = NULL;
+	ctx->li = NULL;
+	ctx->sv = NULL;
+	ctx->flags = 0;
 	appctx->st2 = 0;
 	appctx->st1 = PROMEX_DUMPER_DONE;
 	return -1;
@@ -1318,6 +1353,7 @@
  * success and -1 on error. */
 static int promex_parse_uri(struct appctx *appctx, struct conn_stream *cs)
 {
+	struct promex_ctx *ctx = appctx->svcctx;
 	struct channel *req = cs_oc(cs);
 	struct channel *res = cs_ic(cs);
 	struct htx *req_htx, *res_htx;
@@ -1387,30 +1423,30 @@
 			if (!value)
 				goto error;
 			else if (*value == 0)
-				appctx->ctx.stats.flags &= ~PROMEX_FL_SCOPE_ALL;
+				ctx->flags &= ~PROMEX_FL_SCOPE_ALL;
 			else if (*value == '*')
-				appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_ALL;
+				ctx->flags |= PROMEX_FL_SCOPE_ALL;
 			else if (strcmp(value, "global") == 0)
-				appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_GLOBAL;
+				ctx->flags |= PROMEX_FL_SCOPE_GLOBAL;
 			else if (strcmp(value, "server") == 0)
-				appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_SERVER;
+				ctx->flags |= PROMEX_FL_SCOPE_SERVER;
 			else if (strcmp(value, "backend") == 0)
-				appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_BACK;
+				ctx->flags |= PROMEX_FL_SCOPE_BACK;
 			else if (strcmp(value, "frontend") == 0)
-				appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_FRONT;
+				ctx->flags |= PROMEX_FL_SCOPE_FRONT;
 			else if (strcmp(value, "listener") == 0)
-				appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_LI;
+				ctx->flags |= PROMEX_FL_SCOPE_LI;
 			else if (strcmp(value, "sticktable") == 0)
-				appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_STICKTABLE;
+				ctx->flags |= PROMEX_FL_SCOPE_STICKTABLE;
 			else
 				goto error;
 		}
 		else if (strcmp(key, "no-maint") == 0)
-			appctx->ctx.stats.flags |= PROMEX_FL_NO_MAINT_SRV;
+			ctx->flags |= PROMEX_FL_NO_MAINT_SRV;
 	}
 
   end:
-	appctx->ctx.stats.flags |= default_scopes;
+	ctx->flags |= default_scopes;
 	return 1;
 
   error:
@@ -1457,6 +1493,7 @@
  */
 static int promex_appctx_init(struct appctx *appctx)
 {
+	applet_reserve_svcctx(appctx, sizeof(struct promex_ctx));
 	appctx->st0 = PROMEX_ST_INIT;
 	return 1;
 }