Merge tag 'v2.0.17' into dev-2.0
HAProxy 2.0.17
diff --git a/include/types/backend.h b/include/types/backend.h
index 22e5f21..92e3d48 100644
--- a/include/types/backend.h
+++ b/include/types/backend.h
@@ -157,6 +157,7 @@
int arg_opt1; /* extra option 1 for the LB algo (algo-specific) */
int arg_opt2; /* extra option 2 for the LB algo (algo-specific) */
int arg_opt3; /* extra option 3 for the LB algo (algo-specific) */
+ int arg_opt4; /* extra option 4 for the LB algo (algo-specific) */
struct server *fbck; /* first backup server when !PR_O_USE_ALL_BK, or NULL */
__decl_hathreads(HA_SPINLOCK_T lock);
diff --git a/include/types/global.h b/include/types/global.h
index eab3345..abc930d 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -94,6 +94,9 @@
/* FIXME : this will have to be redefined correctly */
struct global {
+ int email_alert;
+ char email_to[3][50];
+ char email_from[50];
int uid;
int gid;
int external_check;
diff --git a/src/backend.c b/src/backend.c
index 75ebada..92d1016 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -210,6 +210,12 @@
int c;
int slashes = 0;
const char *start, *end;
+ int depth = 1;
+ int orig_uri_len = uri_len;
+ const char *orig_start;
+ const char *p, *params;
+ int buflen = 0;
+ char *buf;
if (px->lbprm.tot_weight == 0)
return NULL;
@@ -221,20 +227,116 @@
if (px->lbprm.arg_opt2) // "len"
uri_len = MIN(uri_len, px->lbprm.arg_opt2);
- start = end = uri;
- while (uri_len--) {
- c = *end;
- if (c == '/') {
- slashes++;
- if (slashes == px->lbprm.arg_opt3) /* depth+1 */
+ orig_start = start = end = uri;
+ if (px->lbprm.arg_opt4 == 1) {
+ p = memchr(uri, '?', uri_len);
+ params = p;
+ if (p) {
+ p++;
+ uri_len = p - uri;
+ params = p;
+ if (p[7] == '=') {
+ if (memcmp(p, "service", 7) == 0) {
+ p += 8;
+ depth = 2;
+ }
+ }
+ }
+
+ end = uri + uri_len - 1;
+ while (uri_len--) {
+ c = *end;
+ if (c == '/') {
+ if (p == NULL)
+ p = end + 1;
+ slashes++;
+ if (slashes == depth)
+ break;
+ }
+ end--;
+ }
+ if (p != NULL && (!strncmp(p, "git-receive-pack", 16) || !strncmp(p, "git-upload-pack", 15))) {
+ // we have git request here
+ // get rid of redundant '/'
+ while ((end - start) > 1 && *(start+1) == '/')
+ start++;
+ while ((end - start) > 1 && *(end-1) == '/')
+ end--;
+ // get rid of trailing ".git"
+ if ((end - start) > 4 && strncmp(end-4, ".git", 4) == 0)
+ end -= 4;
+
+ hash = gen_hash(px, start, (end - start));
+ } else {
+ if (px->lbprm.arg_opt3 > 0){
+ // reset state
+ uri_len = orig_uri_len;
+ if (params != NULL)
+ uri_len = params - uri;
+ depth = px->lbprm.arg_opt3;
+ slashes = 0;
+ buf = (char *)malloc(uri_len);
+ orig_start = start = end = uri;
+ while (uri_len--) {
+ c = *end;
+ if (c == '/') {
+ if (slashes == 1 && end - start == 2) {
+ depth += 1;
+ orig_start = start = end;
+ }
+ slashes++;
+ if (slashes == depth - 1) {
+ if (memcmp(start, "/changes", end - start) != 0 && memcmp(start, "/projects", end - start) != 0)
+ break;
+ start = end;
+ p = start;
+ }
+ else if (slashes == depth) { /* depth+1 */
+ memcpy(buf + buflen, p, end - p);
+ buflen += (end - p);
+ break;
+ }
+ }
+ else if (c == '%') {
+ if (orig_start != start && uri_len > 2 && (memcmp(end, "%2F", 3) == 0 || memcmp(end, "%2f", 3) == 0)) {
+ memcpy(buf + buflen, p, end - p);
+ buflen += (end - p) + 1;
+ buf[buflen - 1] = '/';
+ p = end + 3;
+ }
+ }
+ else if (c == '~') {
+ if (orig_start != start) {
+ memcpy(buf + buflen, p, end - p);
+ buflen += (end - p);
+ break;
+ }
+ }
+ end++;
+ }
+ }
+ if (buflen > 0)
+ hash = gen_hash(px, buf, buflen);
+ if (buf != NULL)
+ free(buf);
+ if (buflen <= 0) /*let's fallback to round robin */
+ return NULL;
+ }
+ } else {
+ while (uri_len--) {
+ c = *end;
+ if (c == '/') {
+ slashes++;
+ if (slashes == px->lbprm.arg_opt3) /* depth+1 */
+ break;
+ }
+ else if (c == '?' && !px->lbprm.arg_opt1) // "whole"
break;
+ end++;
}
- else if (c == '?' && !px->lbprm.arg_opt1) // "whole"
- break;
- end++;
- }
- hash = gen_hash(px, start, (end - start));
+ hash = gen_hash(px, start, (end - start));
+ }
if ((px->lbprm.algo & BE_LB_HASH_MOD) == BE_LB_HMOD_AVAL)
hash = full_hash(hash);
@@ -1984,6 +2086,7 @@
curproxy->lbprm.arg_opt1 = 0; // "whole"
curproxy->lbprm.arg_opt2 = 0; // "len"
curproxy->lbprm.arg_opt3 = 0; // "depth"
+ curproxy->lbprm.arg_opt4 = 0; // "gerrit"
while (*args[arg]) {
if (!strcmp(args[arg], "len")) {
@@ -2009,6 +2112,16 @@
curproxy->lbprm.arg_opt1 = 1;
arg += 1;
}
+ else if (!strcmp(args[arg], "gerrit")) {
+ if (!*args[arg+1] || (atoi(args[arg+1]) < 0)) {
+ memprintf(err, "%s : '%s' expects a non negative integer (got '%s').", args[0], args[arg], args[arg+1]);
+ return -1;
+ }
+ curproxy->lbprm.arg_opt4 = 1;
+ // 0 means whole uri
+ curproxy->lbprm.arg_opt3 = atoi(args[arg+1]);
+ arg += 2;
+ }
else {
memprintf(err, "%s only accepts parameters 'len', 'depth', and 'whole' (got '%s').", args[0], args[arg]);
return -1;
diff --git a/src/cfgparse-global.c b/src/cfgparse-global.c
index b117ebc..4e185e2 100644
--- a/src/cfgparse-global.c
+++ b/src/cfgparse-global.c
@@ -26,6 +26,7 @@
*/
int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
{
+ int i = 0;
int err_code = 0;
char *errmsg = NULL;
@@ -1172,6 +1173,20 @@
env++;
}
}
+ else if (!strcmp(args[0], "email_alert")) {
+ global.email_alert = 1;
+ if (*(args[1]) == 0) {
+ ha_alert("parsing [%s:%d] : email_alert Expects email address as argument.\n", file, linenum);
+ global.email_alert = 0;
+ err_code |= ERR_ALERT;
+ goto out;
+ }
+ strncpy(global.email_from,args[1],50);
+ for (i=0; i<3; i++) {
+ if (*(args[i+2]) != 0)
+ strncpy(global.email_to[i],args[i+2],50);
+ }
+ }
else {
struct cfg_kw_list *kwl;
int index;
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index 31c61c2..1328430 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -494,6 +494,7 @@
curproxy->lbprm.arg_opt1 = defproxy.lbprm.arg_opt1;
curproxy->lbprm.arg_opt2 = defproxy.lbprm.arg_opt2;
curproxy->lbprm.arg_opt3 = defproxy.lbprm.arg_opt3;
+ curproxy->lbprm.arg_opt4 = defproxy.lbprm.arg_opt4;
if (defproxy.conn_src.iface_name)
curproxy->conn_src.iface_name = strdup(defproxy.conn_src.iface_name);
diff --git a/src/log.c b/src/log.c
index 84e12b6..53ec4bb 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1048,6 +1048,69 @@
free(msg);
}
+void make_literal(char const *input, char *output) {
+ // the following two arrays must be maintained in matching order:
+ static char inputs[] = "\a\b\f\n\r\t\v\\\"\'";
+ static char outputs[] = "abfnrtv\\\"\'";
+
+ char *pos;
+
+ for (;*input;input++) {
+ if (NULL!= (pos=strchr(inputs, *input))) {
+ *output++ = '\\';
+ *output++ = outputs[pos-inputs];
+ }
+ else
+ *output++ = *input;
+ }
+ *output = '\0';
+}
+
+void Emaila(const char *fmt, ...)
+{
+ va_list argp;
+ char tmp[256];
+ char buf[500];
+ char alertcmd[1024];
+ int sysreturn;
+ size_t len = 0, len1 = 0, len2 = 0, len3 = 0;
+
+ if (global.email_alert) {
+ va_start(argp, fmt);
+ vsnprintf(tmp,128,fmt, argp);
+ make_literal(tmp, buf);
+
+ len1 = strlen(global.email_to[0]);
+ len2 = strlen(global.email_to[1]);
+ len3 = strlen(global.email_to[2]);
+ memcpy(tmp, global.email_to[0], len1);
+ tmp[len1] = ' ';
+ len = len1 + 1;
+ if (len2 > 0) {
+ memcpy(tmp + len, global.email_to[1], len2); // includes terminating null
+ len += len2;
+ tmp[len] = ' ';
+ len += 1;
+ if (len3 > 0) {
+ memcpy(tmp + len, global.email_to[2], len3); // includes terminating null
+ len += len3;
+ tmp[len] = ' ';
+ len += 1;
+ }
+ }
+ tmp[len] = '\0';
+ snprintf(alertcmd, 1024, "echo \"%s\" | mail -s \"$(echo -e \"[HAProxy alert %s] %.60s...\nFrom:HAProxy <%s>\n\")\" %s&", buf, global.email_from, buf, global.email_from, tmp);
+
+ sysreturn = system(alertcmd);
+ if (sysreturn == -1) {
+ ha_warning("There was an error sending the email alert");
+ }
+ vfprintf(stderr, fmt, argp);
+ fflush(stderr);
+ va_end(argp);
+ }
+}
+
/*
* Displays the message on stderr with the date and pid. Overrides the quiet
* mode during startup.
diff --git a/src/server.c b/src/server.c
index 5490216..206ba5d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -4841,6 +4841,7 @@
srv_append_status(tmptrash, s, NULL, xferred, 0);
ha_warning("%s.\n", tmptrash->area);
+ Emaila("%s \n", tmptrash->area);
/* we don't send an alert if the server was previously paused */
log_level = srv_was_stopping ? LOG_NOTICE : LOG_ALERT;
@@ -4935,6 +4936,7 @@
srv_append_status(tmptrash, s, NULL, xferred, 0);
ha_warning("%s.\n", tmptrash->area);
+ Emaila("%s \n", tmptrash->area);
send_log(s->proxy, LOG_NOTICE, "%s.\n",
tmptrash->area);
send_email_alert(s, LOG_NOTICE, "%s",