src/proto_http.c
int http_handle_stats(struct session *s, struct channel *req)
{
	struct stats_admin_rule *stats_admin_rule;
	struct stream_interface *si = s->rep->prod;
	struct http_txn *txn = &s->txn;
	struct http_msg *msg = &txn->req;
	struct uri_auth *uri = s->be->uri_auth;

	/* now check whether we have some admin rules for this request */
	list_for_each_entry(stats_admin_rule, &s->be->uri_auth->admin_rules, list) {
		int ret = 1;

		if (stats_admin_rule->cond) {
			ret = acl_exec_cond(stats_admin_rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
			ret = acl_pass(ret);
			if (stats_admin_rule->cond->pol == ACL_COND_UNLESS)
				ret = !ret;
		}

		if (ret) {
			/* no rule, or the rule matches */
			s->rep->prod->applet.ctx.stats.flags |= STAT_ADMIN;
			break;
		}
	}

	/* Was the status page requested with a POST ? */
	if (unlikely(txn->meth == HTTP_METH_POST)) {
		char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN];

		if (si->applet.ctx.stats.flags & STAT_ADMIN) {
			if (msg->msg_state < HTTP_MSG_100_SENT) {
				/* If we have HTTP/1.1 and Expect: 100-continue, then we must
				 * send an HTTP/1.1 100 Continue intermediate response.
				 */
				if (msg->flags & HTTP_MSGF_VER_11) {
					struct hdr_ctx ctx;
					ctx.idx = 0;
					/* Expect is allowed in 1.1, look for it */
					if (http_find_header2("Expect", 6, req->buf->p, &txn->hdr_idx, &ctx) &&
					    unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val, "100-continue", 12) == 0)) {
						bo_inject(s->rep, http_100_chunk.str, http_100_chunk.len);
					}
				}
				msg->msg_state = HTTP_MSG_100_SENT;
				s->logs.tv_request = now;  /* update the request timer to reflect full request */
			}
			if (!http_process_req_stat_post(si, txn, req))
				return 0;   /* we need more data */
		}
		else
			si->applet.ctx.stats.st_code = STAT_STATUS_DENY;
		/* scope_txt = search pattern + search query, si->applet.ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
		scope_txt[0] = 0;
		if (si->applet.ctx.stats.scope_len) {
			strcpy(scope_txt, STAT_SCOPE_PATTERN);
			memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), bo_ptr(req->buf) + si->applet.ctx.stats.scope_str, si->applet.ctx.stats.scope_len);
			scope_txt[strlen(STAT_SCOPE_PATTERN) + si->applet.ctx.stats.scope_len] = 0;
		}


		/* We don't want to land on the posted stats page because a refresh will
		 * repost the data. We don't want this to happen on accident so we redirect
		 * the browse to the stats page with a GET.
		 */
		chunk_printf(&trash,
		             "HTTP/1.1 303 See Other\r\n"
		             "Cache-Control: no-cache\r\n"
		             "Content-Type: text/plain\r\n"
		             "Connection: close\r\n"
		             "Location: %s;st=%s%s%s%s\r\n"
		             "\r\n",
		             uri->uri_prefix,
		             ((si->applet.ctx.stats.st_code > STAT_STATUS_INIT) &&
		              (si->applet.ctx.stats.st_code < STAT_STATUS_SIZE) &&
		              stat_status_codes[si->applet.ctx.stats.st_code]) ?
		             stat_status_codes[si->applet.ctx.stats.st_code] :
		             stat_status_codes[STAT_STATUS_UNKN],
			     (si->applet.ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
			     (si->applet.ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
			     scope_txt);

		s->txn.status = 303;
		s->logs.tv_request = now;
		stream_int_retnclose(req->prod, &trash);
		s->target = &http_stats_applet.obj_type; /* just for logging the applet name */

		if (s->fe == s->be) /* report it if the request was intercepted by the frontend */
			s->fe->fe_counters.intercepted_req++;

		if (!(s->flags & SN_ERR_MASK))      // this is not really an error but it is
			s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
		if (!(s->flags & SN_FINST_MASK))
			s->flags |= SN_FINST_R;
		req->analysers = 0;
		return 1;
	}

	/* OK, let's go on now */

	chunk_printf(&trash,
	             "HTTP/1.0 200 OK\r\n"
	             "Cache-Control: no-cache\r\n"
	             "Connection: close\r\n"
	             "Content-Type: %s\r\n",
	             (si->applet.ctx.stats.flags & STAT_FMT_HTML) ? "text/html" : "text/plain");

	if (uri->refresh > 0 && !(si->applet.ctx.stats.flags & STAT_NO_REFRESH))
		chunk_appendf(&trash, "Refresh: %d\r\n",
		              uri->refresh);

	chunk_appendf(&trash, "\r\n");

	s->txn.status = 200;
	s->logs.tv_request = now;

	if (s->fe == s->be) /* report it if the request was intercepted by the frontend */
		s->fe->fe_counters.intercepted_req++;

	if (!(s->flags & SN_ERR_MASK))      // this is not really an error but it is
		s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
	if (!(s->flags & SN_FINST_MASK))
		s->flags |= SN_FINST_R;

	if (s->txn.meth == HTTP_METH_HEAD) {
		/* that's all we return in case of HEAD request, so let's immediately close. */
		stream_int_retnclose(req->prod, &trash);
		s->target = &http_stats_applet.obj_type; /* just for logging the applet name */
		req->analysers = 0;
		return 1;
	}

	/* OK, push the response and hand over to the stats I/O handler */
	bi_putchk(s->rep, &trash);

	s->task->nice = -32; /* small boost for HTTP statistics */
	stream_int_register_handler(s->rep->prod, &http_stats_applet);
	s->target = s->rep->prod->conn->target; // for logging only
	s->rep->prod->conn->xprt_ctx = s;
	s->rep->prod->applet.st0 = s->rep->prod->applet.st1 = 0;
	req->analysers = 0;
	return 1;
}
/* This function checks whether we need to enable a POST analyser to parse a
 * stats request, and also registers the stats I/O handler. It returns zero
 * if it needs to come back again, otherwise non-zero if it finishes. In the
 * latter case, it also clears the request analysers.
 */
This function checks whether we need to enable a POST analyser to parse a
stats request, and also registers the stats I/O handler. It returns zero
if it needs to come back again, otherwise non-zero if it finishes. In the
latter case, it also clears the request analysers.
This function checks whether we need to enable a POST analyser to parse a stats request and also registers the stats I / O handler . It returns zero if it needs to come back again otherwise non - zero if it finishes . In the latter case it also clears the request analysers .
int http_handle_stats(struct session *s, struct channel *req)
{
	struct stats_admin_rule *stats_admin_rule;
	struct stream_interface *si = s->rep->prod;
	struct http_txn *txn = &s->txn;
	struct http_msg *msg = &txn->req;
	struct uri_auth *uri = s->be->uri_auth;
	list_for_each_entry(stats_admin_rule, &s->be->uri_auth->admin_rules, list) {
		int ret = 1;
		if (stats_admin_rule->cond) {
			ret = acl_exec_cond(stats_admin_rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
			ret = acl_pass(ret);
			if (stats_admin_rule->cond->pol == ACL_COND_UNLESS)
				ret = !ret;
		}
		if (ret) {
			s->rep->prod->applet.ctx.stats.flags |= STAT_ADMIN;
			break;
		}
	}
	if (unlikely(txn->meth == HTTP_METH_POST)) {
		char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN];
		if (si->applet.ctx.stats.flags & STAT_ADMIN) {
			if (msg->msg_state < HTTP_MSG_100_SENT) {
				if (msg->flags & HTTP_MSGF_VER_11) {
					struct hdr_ctx ctx;
					ctx.idx = 0;
					if (http_find_header2("Expect", 6, req->buf->p, &txn->hdr_idx, &ctx) &&
					    unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val, "100-continue", 12) == 0)) {
						bo_inject(s->rep, http_100_chunk.str, http_100_chunk.len);
					}
				}
				msg->msg_state = HTTP_MSG_100_SENT;
				s->logs.tv_request = now;  
			}
			if (!http_process_req_stat_post(si, txn, req))
				return 0;   
		}
		else
			si->applet.ctx.stats.st_code = STAT_STATUS_DENY;
		scope_txt[0] = 0;
		if (si->applet.ctx.stats.scope_len) {
			strcpy(scope_txt, STAT_SCOPE_PATTERN);
			memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), bo_ptr(req->buf) + si->applet.ctx.stats.scope_str, si->applet.ctx.stats.scope_len);
			scope_txt[strlen(STAT_SCOPE_PATTERN) + si->applet.ctx.stats.scope_len] = 0;
		}
		chunk_printf(&trash,
		             "HTTP/1.1 303 See Other\r\n"
		             "Cache-Control: no-cache\r\n"
		             "Content-Type: text/plain\r\n"
		             "Connection: close\r\n"
		             "Location: %s;st=%s%s%s%s\r\n"
		             "\r\n",
		             uri->uri_prefix,
		             ((si->applet.ctx.stats.st_code > STAT_STATUS_INIT) &&
		              (si->applet.ctx.stats.st_code < STAT_STATUS_SIZE) &&
		              stat_status_codes[si->applet.ctx.stats.st_code]) ?
		             stat_status_codes[si->applet.ctx.stats.st_code] :
		             stat_status_codes[STAT_STATUS_UNKN],
			     (si->applet.ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
			     (si->applet.ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
			     scope_txt);
		s->txn.status = 303;
		s->logs.tv_request = now;
		stream_int_retnclose(req->prod, &trash);
		s->target = &http_stats_applet.obj_type; 
		if (s->fe == s->be) 
			s->fe->fe_counters.intercepted_req++;
		if (!(s->flags & SN_ERR_MASK))      
			s->flags |= SN_ERR_PRXCOND; 
		if (!(s->flags & SN_FINST_MASK))
			s->flags |= SN_FINST_R;
		req->analysers = 0;
		return 1;
	}
	chunk_printf(&trash,
	             "HTTP/1.0 200 OK\r\n"
	             "Cache-Control: no-cache\r\n"
	             "Connection: close\r\n"
	             "Content-Type: %s\r\n",
	             (si->applet.ctx.stats.flags & STAT_FMT_HTML) ? "text/html" : "text/plain");
	if (uri->refresh > 0 && !(si->applet.ctx.stats.flags & STAT_NO_REFRESH))
		chunk_appendf(&trash, "Refresh: %d\r\n",
		              uri->refresh);
	chunk_appendf(&trash, "\r\n");
	s->txn.status = 200;
	s->logs.tv_request = now;
	if (s->fe == s->be) 
		s->fe->fe_counters.intercepted_req++;
	if (!(s->flags & SN_ERR_MASK))      
		s->flags |= SN_ERR_PRXCOND; 
	if (!(s->flags & SN_FINST_MASK))
		s->flags |= SN_FINST_R;
	if (s->txn.meth == HTTP_METH_HEAD) {
		stream_int_retnclose(req->prod, &trash);
		s->target = &http_stats_applet.obj_type; 
		req->analysers = 0;
		return 1;
	}
	bi_putchk(s->rep, &trash);
	s->task->nice = -32; 
	stream_int_register_handler(s->rep->prod, &http_stats_applet);
	s->target = s->rep->prod->conn->target; 
	s->rep->prod->conn->xprt_ctx = s;
	s->rep->prod->applet.st0 = s->rep->prod->applet.st1 = 0;
	req->analysers = 0;
	return 1;
}
int http_handle_stats ( struct session * s , struct channel * req ) { struct stats_admin_rule * stats_admin_rule ; struct stream_interface * si = s -> rep -> prod ; struct http_txn * txn = & s -> txn ; struct http_msg * msg = & txn -> req ; struct uri_auth * uri = s -> be -> uri_auth ; list_for_each_entry ( stats_admin_rule , & s -> be -> uri_auth -> admin_rules , list ) { int ret = 1 ; if ( stats_admin_rule -> cond ) { ret = acl_exec_cond ( stats_admin_rule -> cond , s -> be , s , & s -> txn , SMP_OPT_DIR_REQ | SMP_OPT_FINAL ) ; ret = acl_pass ( ret ) ; if ( stats_admin_rule -> cond -> pol == ACL_COND_UNLESS ) ret = ! ret ; } if ( ret ) { s -> rep -> prod -> applet . ctx . stats . flags |= STAT_ADMIN ; break ; } } if ( unlikely ( txn -> meth == HTTP_METH_POST ) ) { char scope_txt [ STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN ] ; if ( si -> applet . ctx . stats . flags & STAT_ADMIN ) { if ( msg -> msg_state < HTTP_MSG_100_SENT ) { if ( msg -> flags & HTTP_MSGF_VER_11 ) { struct hdr_ctx ctx ; ctx . idx = 0 ; if ( http_find_header2 ( " " , 6 , req -> buf -> p , & txn -> hdr_idx , & ctx ) && unlikely ( ctx . vlen == 12 && strncasecmp ( ctx . line + ctx . val , " " , 12 ) == 0 ) ) { bo_inject ( s -> rep , http_100_chunk . str , http_100_chunk . len ) ; } } msg -> msg_state = HTTP_MSG_100_SENT ; s -> logs . tv_request = now ; } if ( ! http_process_req_stat_post ( si , txn , req ) ) return 0 ; } else si -> applet . ctx . stats . st_code = STAT_STATUS_DENY ; scope_txt [ 0 ] = 0 ; if ( si -> applet . ctx . stats . scope_len ) { strcpy ( scope_txt , STAT_SCOPE_PATTERN ) ; memcpy ( scope_txt + strlen ( STAT_SCOPE_PATTERN ) , bo_ptr ( req -> buf ) + si -> applet . ctx . stats . scope_str , si -> applet . ctx . stats . scope_len ) ; scope_txt [ strlen ( STAT_SCOPE_PATTERN ) + si -> applet . ctx . stats . scope_len ] = 0 ; } chunk_printf ( & trash , " \r \n " " \r \n " " \r \n " " \r \n " " \r \n " " \r \n " , uri -> uri_prefix , ( ( si -> applet . ctx . stats . st_code > STAT_STATUS_INIT ) && ( si -> applet . ctx . stats . st_code < STAT_STATUS_SIZE ) && stat_status_codes [ si -> applet . ctx . stats . st_code ] ) ? stat_status_codes [ si -> applet . ctx . stats . st_code ] : stat_status_codes [ STAT_STATUS_UNKN ] , ( si -> applet . ctx . stats . flags & STAT_HIDE_DOWN ) ? " " : " " , ( si -> applet . ctx . stats . flags & STAT_NO_REFRESH ) ? " " : " " , scope_txt ) ; s -> txn . status = 303 ; s -> logs . tv_request = now ; stream_int_retnclose ( req -> prod , & trash ) ; s -> target = & http_stats_applet . obj_type ; if ( s -> fe == s -> be ) s -> fe -> fe_counters . intercepted_req ++ ; if ( ! ( s -> flags & SN_ERR_MASK ) ) s -> flags |= SN_ERR_PRXCOND ; if ( ! ( s -> flags & SN_FINST_MASK ) ) s -> flags |= SN_FINST_R ; req -> analysers = 0 ; return 1 ; } chunk_printf ( & trash , " \r \n " " \r \n " " \r \n " " \r \n " , ( si -> applet . ctx . stats . flags & STAT_FMT_HTML ) ? " " : " " ) ; if ( uri -> refresh > 0 && ! ( si -> applet . ctx . stats . flags & STAT_NO_REFRESH ) ) chunk_appendf ( & trash , " \r \n " , uri -> refresh ) ; chunk_appendf ( & trash , " \r \n " ) ; s -> txn . status = 200 ; s -> logs . tv_request = now ; if ( s -> fe == s -> be ) s -> fe -> fe_counters . intercepted_req ++ ; if ( ! ( s -> flags & SN_ERR_MASK ) ) s -> flags |= SN_ERR_PRXCOND ; if ( ! ( s -> flags & SN_FINST_MASK ) ) s -> flags |= SN_FINST_R ; if ( s -> txn . meth == HTTP_METH_HEAD ) { stream_int_retnclose ( req -> prod , & trash ) ; s -> target = & http_stats_applet . obj_type ; req -> analysers = 0 ; return 1 ; } bi_putchk ( s -> rep , & trash ) ; s -> task -> nice = -32 ; stream_int_register_handler ( s -> rep -> prod , & http_stats_applet ) ; s -> target = s -> rep -> prod -> conn -> target ; s -> rep -> prod -> conn -> xprt_ctx = s ; s -> rep -> prod -> applet . st0 = s -> rep -> prod -> applet . st1 = 0 ; req -> analysers = 0 ; return 1 ; }
This function checks whether we need to enable a POST analyser to parse a
 stats request, and also registers the stats I/O handler.
This function checks whether we need to enable a POST analyser to parse a stats request and also registers the stats I / O handler .
/* now check whether we have some admin rules for this request */ /* no rule, or the rule matches */ /* Was the status page requested with a POST ? */ /* If we have HTTP/1.1 and Expect: 100-continue, then we must
				 * send an HTTP/1.1 100 Continue intermediate response.
				 */ /* Expect is allowed in 1.1, look for it */ /* update the request timer to reflect full request */ /* we need more data */ /* scope_txt = search pattern + search query, si->applet.ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */ /* We don't want to land on the posted stats page because a refresh will
		 * repost the data. We don't want this to happen on accident so we redirect
		 * the browse to the stats page with a GET.
		 */ /* just for logging the applet name */ /* report it if the request was intercepted by the frontend */ // this is not really an error but it is // to mark that it comes from the proxy /* OK, let's go on now */ /* report it if the request was intercepted by the frontend */ // this is not really an error but it is // to mark that it comes from the proxy /* that's all we return in case of HEAD request, so let's immediately close. */ /* just for logging the applet name */ /* OK, push the response and hand over to the stats I/O handler */ /* small boost for HTTP statistics */ // for logging only