diff -Nru haproxy-1.5.3/CHANGELOG haproxy-1.5.5/CHANGELOG --- haproxy-1.5.3/CHANGELOG 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/CHANGELOG 2014-10-08 08:07:23.000000000 +0000 @@ -1,6 +1,46 @@ ChangeLog : =========== +2014/10/08 : 1.5.5 + - DOC: Address issue where documentation is excluded due to a gitignore rule. + - MEDIUM: Improve signal handling in systemd wrapper. + - BUG/MINOR: config: don't propagate process binding for dynamic use_backend + - MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper + - DOC: clearly state that the "show sess" output format is not fixed + - MINOR: stats: fix minor typo fix in stats_dump_errors_to_buffer() + - DOC: indicate in the doc that track-sc* can wait if data are missing + - MEDIUM: http: enable header manipulation for 101 responses + - BUG/MEDIUM: config: propagate frontend to backend process binding again. + - MEDIUM: config: properly propagate process binding between proxies + - MEDIUM: config: make the frontends automatically bind to the listeners' processes + - MEDIUM: config: compute the exact bind-process before listener's maxaccept + - MEDIUM: config: only warn if stats are attached to multi-process bind directives + - MEDIUM: config: report it when tcp-request rules are misplaced + - MINOR: config: detect the case where a tcp-request content rule has no inspect-delay + - MEDIUM: systemd-wrapper: support multiple executable versions and names + - BUG/MEDIUM: remove debugging code from systemd-wrapper + - BUG/MEDIUM: http: adjust close mode when switching to backend + - BUG/MINOR: config: don't propagate process binding on fatal errors. + - BUG/MEDIUM: check: rule-less tcp-check must detect connect failures + - BUG/MINOR: tcp-check: report the correct failed step in the status + - DOC: indicate that weight zero is reported as DRAIN + +2014/09/02 : 1.5.4 + - BUG: config: error in http-response replace-header number of arguments + - BUG/MINOR: Fix search for -p argument in systemd wrapper. + - BUG/MEDIUM: auth: fix segfault with http-auth and a configuration with an unknown encryption algorithm + - BUG/MEDIUM: config: userlists should ensure that encrypted passwords are supported + - MEDIUM: connection: add new bit in Proxy Protocol V2 + - BUG/MINOR: server: move the directive #endif to the end of file + - BUG/MEDIUM: http: tarpit timeout is reset + - BUG/MAJOR: tcp: fix a possible busy spinning loop in content track-sc* + - BUG/MEDIUM: http: fix inverted condition in pat_match_meth() + - BUG/MEDIUM: http: fix improper parsing of HTTP methods for use with ACLs + - BUG/MINOR: pattern: remove useless allocation of unused trash in pat_parse_reg() + - BUG/MEDIUM: acl: correctly compute the output type when a converter is used + - CLEANUP: acl: cleanup some of the redundancy and spaghetti after last fix + - BUG/CRITICAL: http: don't update msg->sov once data start to leave the buffer + 2014/07/25 : 1.5.3 - DOC: fix typo in Unix Socket commands - BUG/MEDIUM: connection: fix memory corruption when building a proxy v2 header diff -Nru haproxy-1.5.3/debian/changelog haproxy-1.5.5/debian/changelog --- haproxy-1.5.3/debian/changelog 2014-07-26 07:14:51.000000000 +0000 +++ haproxy-1.5.5/debian/changelog 2014-10-10 06:21:25.000000000 +0000 @@ -1,3 +1,72 @@ +haproxy (1.5.5-1ppa1~lucid) lucid; urgency=medium + + * Rebuild for Lucid (PPA). + + -- Vincent Bernat Fri, 10 Oct 2014 08:21:19 +0200 + +haproxy (1.5.5-1) unstable; urgency=medium + + [ Vincent Bernat ] + * initscript: use start-stop-daemon to reliably terminate all haproxy + processes. Also treat stopping a non-running haproxy as success. + (Closes: #762608, LP: #1038139) + + [ Apollon Oikonomopoulos ] + * New upstream stable release including the following fixes: + + DOC: Address issue where documentation is excluded due to a gitignore + rule. + + MEDIUM: Improve signal handling in systemd wrapper. + + BUG/MINOR: config: don't propagate process binding for dynamic + use_backend + + MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper + + DOC: clearly state that the "show sess" output format is not fixed + + MINOR: stats: fix minor typo fix in stats_dump_errors_to_buffer() + + DOC: indicate in the doc that track-sc* can wait if data are missing + + MEDIUM: http: enable header manipulation for 101 responses + + BUG/MEDIUM: config: propagate frontend to backend process binding again. + + MEDIUM: config: properly propagate process binding between proxies + + MEDIUM: config: make the frontends automatically bind to the listeners' + processes + + MEDIUM: config: compute the exact bind-process before listener's + maxaccept + + MEDIUM: config: only warn if stats are attached to multi-process bind + directives + + MEDIUM: config: report it when tcp-request rules are misplaced + + MINOR: config: detect the case where a tcp-request content rule has no + inspect-delay + + MEDIUM: systemd-wrapper: support multiple executable versions and names + + BUG/MEDIUM: remove debugging code from systemd-wrapper + + BUG/MEDIUM: http: adjust close mode when switching to backend + + BUG/MINOR: config: don't propagate process binding on fatal errors. + + BUG/MEDIUM: check: rule-less tcp-check must detect connect failures + + BUG/MINOR: tcp-check: report the correct failed step in the status + + DOC: indicate that weight zero is reported as DRAIN + * Add a new patch (haproxy.service-set-killmode-to-mixed.patch) to fix the + systemctl stop action conflicting with the systemd wrapper now catching + SIGTERM. + * Bump standards to 3.9.6; no changes needed. + * haproxy-doc: link to tracker.debian.org instead of packages.qa.debian.org. + * d/copyright: move debian/dconv/* paragraph after debian/*, so that it + actually matches the files it is supposed to. + + -- Apollon Oikonomopoulos Wed, 08 Oct 2014 12:34:53 +0300 + +haproxy (1.5.4-1ppa1~lucid) lucid; urgency=high + + * Rebuild for Lucid (PPA). + + -- Vincent Bernat Tue, 02 Sep 2014 19:44:45 +0200 + +haproxy (1.5.4-1) unstable; urgency=high + + * New upstream version. + + Fix a critical bug that, under certain unlikely conditions, allows a + client to crash haproxy. + * Prefix rsyslog configuration file to ensure to log only to + /var/log/haproxy. Thanks to Paul Bourke for the patch. + + -- Vincent Bernat Tue, 02 Sep 2014 19:14:38 +0200 + haproxy (1.5.3-1ppa1~lucid) lucid; urgency=medium * Rebuild for Lucid (PPA). diff -Nru haproxy-1.5.3/debian/control haproxy-1.5.5/debian/control --- haproxy-1.5.3/debian/control 2014-07-26 07:14:51.000000000 +0000 +++ haproxy-1.5.5/debian/control 2014-10-10 06:21:25.000000000 +0000 @@ -5,7 +5,7 @@ Uploaders: Apollon Oikonomopoulos , Prach Pongpanich , Vincent Bernat -Standards-Version: 3.9.5 +Standards-Version: 3.9.6 Build-Depends: debhelper (>= 7.0.50~), libpcre3-dev, libssl-dev Homepage: http://haproxy.1wt.eu/ Vcs-Git: git://anonscm.debian.org/pkg-haproxy/haproxy.git diff -Nru haproxy-1.5.3/debian/copyright haproxy-1.5.5/debian/copyright --- haproxy-1.5.3/debian/copyright 2014-07-26 07:14:51.000000000 +0000 +++ haproxy-1.5.5/debian/copyright 2014-10-10 06:21:25.000000000 +0000 @@ -130,10 +130,6 @@ Copyright: Copyright 2007 Aleksandar Lazic License: GPL-2+ -Files: debian/dconv/* -Copyright: Copyright (C) 2012 Cyril Bonté -License: Apache-2.0 - Files: debian/* Copyright: Copyright (C) 2007-2011, Arnaud Cornet Copyright (C) 2011, Christo Buschek @@ -141,6 +137,10 @@ Copyright (C) 2013-2014, Apollon Oikonomopoulos Copyright (C) 2013, Vincent Bernat License: GPL-2 + +Files: debian/dconv/* +Copyright: Copyright (C) 2012 Cyril Bonté +License: Apache-2.0 License: GPL-2+ This program is free software; you can redistribute it diff -Nru haproxy-1.5.3/debian/haproxy.init haproxy-1.5.5/debian/haproxy.init --- haproxy-1.5.3/debian/haproxy.init 2014-07-26 07:14:51.000000000 +0000 +++ haproxy-1.5.5/debian/haproxy.init 2014-10-10 06:21:25.000000000 +0000 @@ -59,11 +59,16 @@ # This is a success according to LSB return 0 fi - for pid in $(cat $PIDFILE) ; do - /bin/kill $pid || return 4 + + ret=0 + for pid in $(cat $PIDFILE); do + start-stop-daemon --quiet --oknodo --stop \ + --retry 5 --pid $pid --exec $HAPROXY || ret=$? done - rm -f $PIDFILE - return 0 + + [ $ret -eq 0 ] && rm -f $PIDFILE + + return $ret } haproxy_reload() diff -Nru haproxy-1.5.3/debian/haproxy.maintscript haproxy-1.5.5/debian/haproxy.maintscript --- haproxy-1.5.3/debian/haproxy.maintscript 1970-01-01 00:00:00.000000000 +0000 +++ haproxy-1.5.5/debian/haproxy.maintscript 2014-10-10 06:21:25.000000000 +0000 @@ -0,0 +1 @@ +mv_conffile /etc/rsyslog.d/haproxy.conf /etc/rsyslog.d/49-haproxy.conf 1.5.3-2~ diff -Nru haproxy-1.5.3/debian/patches/debianize-dconv.patch haproxy-1.5.5/debian/patches/debianize-dconv.patch --- haproxy-1.5.3/debian/patches/debianize-dconv.patch 2014-07-26 07:14:51.000000000 +0000 +++ haproxy-1.5.5/debian/patches/debianize-dconv.patch 2014-10-10 06:21:25.000000000 +0000 @@ -144,7 +144,7 @@ - +
  • Bug Tracking System
  • +
  • Package page
  • -+
  • Package Tracking System
  • ++
  • Package Tracking System
  • +
  • +
  • Package Git Repository
  • diff -Nru haproxy-1.5.3/debian/patches/haproxy.service-set-killmode-to-mixed.patch haproxy-1.5.5/debian/patches/haproxy.service-set-killmode-to-mixed.patch --- haproxy-1.5.3/debian/patches/haproxy.service-set-killmode-to-mixed.patch 1970-01-01 00:00:00.000000000 +0000 +++ haproxy-1.5.5/debian/patches/haproxy.service-set-killmode-to-mixed.patch 2014-10-10 06:21:25.000000000 +0000 @@ -0,0 +1,28 @@ +Author: Apollon Oikonomopoulos +Description: Set KillMode to "mixed" + Since 1.5.5, the systemd wrapper handles SIGTERM by dispatching SIGINT to the + workers (which are its grand-children). By default, systemd sends the TERM + signal to all processes in the control group, including the wrapper that used + to die as well. However, now the wrapper lives on and gets a SIGCHLD from the + master haproxy process getting killed by systemd and assumes this is an error. + . + To work around this behaviour, we set KillMode to "mixed", which means that + systemd will dispatch the initial SIGTERM to the wrapper only (as it's the + main process) and if this doesn't work, it will send the SIGKILL to all + processes in the group, thus making sure no runaway children are left behind. + See systemd.kill(5) for more information on this behavior. + +Last-Update: 2014-10-08 +Forwarded: no +--- a/contrib/systemd/haproxy.service.in ++++ b/contrib/systemd/haproxy.service.in +@@ -13,6 +13,9 @@ + ExecReload=@SBINDIR@/haproxy -c -f ${CONFIG} + ExecReload=/bin/kill -USR2 $MAINPID + Restart=always ++# Send SIGTERM to the wrapper, let it propagate it to the children. Send ++# SIGKILL, if needed, to everyone. ++KillMode=mixed + + [Install] + WantedBy=multi-user.target diff -Nru haproxy-1.5.3/debian/patches/series haproxy-1.5.5/debian/patches/series --- haproxy-1.5.3/debian/patches/series 2014-07-26 07:14:51.000000000 +0000 +++ haproxy-1.5.5/debian/patches/series 2014-10-10 06:21:25.000000000 +0000 @@ -4,3 +4,4 @@ haproxy.service-check-config-before-reload.patch haproxy.service-use-environment-variables.patch haproxy.service-also-check-on-start.patch +haproxy.service-set-killmode-to-mixed.patch diff -Nru haproxy-1.5.3/debian/rules haproxy-1.5.5/debian/rules --- haproxy-1.5.3/debian/rules 2014-07-26 07:14:51.000000000 +0000 +++ haproxy-1.5.5/debian/rules 2014-10-10 06:21:25.000000000 +0000 @@ -46,7 +46,7 @@ override_dh_auto_install: make $(MAKEARGS) install - install -m 0644 -D debian/rsyslog.conf debian/haproxy/etc/rsyslog.d/haproxy.conf + install -m 0644 -D debian/rsyslog.conf debian/haproxy/etc/rsyslog.d/49-haproxy.conf install -m 0644 -D debian/logrotate.conf debian/haproxy/etc/logrotate.d/haproxy override_dh_installdocs: diff -Nru haproxy-1.5.3/doc/configuration.txt haproxy-1.5.5/doc/configuration.txt --- haproxy-1.5.3/doc/configuration.txt 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/doc/configuration.txt 2014-10-08 08:07:23.000000000 +0000 @@ -2,9 +2,9 @@ HAProxy Configuration Manual ---------------------- - version 1.5.3 + version 1.5.4 willy tarreau - 2014/07/25 + 2014/09/02 This document covers the configuration language as implemented in the version @@ -1905,6 +1905,10 @@ Each "bind" line may further be limited to a subset of the proxy's processes, please consult the "process" bind keyword in section 5.1. + When a frontend has no explicit "bind-process" line, it tries to bind to all + the processes referenced by its "bind" lines. That means that frontends can + easily adapt to their listeners' processes. + If some backends are referenced by frontends bound to other processes, the backend automatically inherits the frontend's processes. @@ -7470,9 +7474,9 @@ contents will always be immediately present when the rule is evaluated first. Tracking layer7 information is also possible provided that the information - are present when the rule is processed. The current solution for making the - rule engine wait for such information is to set an inspect delay and to - condition its execution with an ACL relying on such information. + are present when the rule is processed. The rule processing engine is able to + wait until the inspect delay expires when the data to be tracked is not yet + available. Example: # Accept HTTP requests containing a Host header saying "example.com" @@ -7497,12 +7501,12 @@ Example: # Track the last IP from X-Forwarded-For tcp-request inspect-delay 10s - tcp-request content track-sc0 hdr(x-forwarded-for,-1) if HTTP + tcp-request content track-sc0 hdr(x-forwarded-for,-1) Example: # track request counts per "base" (concatenation of Host+URL) tcp-request inspect-delay 10s - tcp-request content track-sc0 base table req-rate if HTTP + tcp-request content track-sc0 base table req-rate Example: track per-frontend and per-backend counters, block abusers at the frontend when the backend detects abuse. @@ -8645,7 +8649,9 @@ - An ASCII representation of a positive integer percentage, e.g. "75%". Values in this format will set the weight proportional to the initial - weight of a server as configured when haproxy starts. + weight of a server as configured when haproxy starts. Note that a zero + weight is reported on the stats page as "DRAIN" since it has the same + effect on the server (it's removed from the LB farm). - The word "ready". This will turn the server's administrative state to the READY mode, thus cancelling any DRAIN or MAINT state @@ -13734,9 +13740,11 @@ of "show sess" (it corresponds to the session pointer). Those information are useless to most users but may be used by haproxy developers to troubleshoot a complex bug. The output format is intentionally not documented so that it can - freely evolve depending on demands. The special id "all" dumps the states of - all sessions, which can be avoided as much as possible as it is highly CPU - intensive and can take a lot of time. + freely evolve depending on demands. You may find a description of all fields + returned in src/dumpstats.c + + The special id "all" dumps the states of all sessions, which must be avoided + as much as possible as it is highly CPU intensive and can take a lot of time. show stat [ ] Dump statistics in the CSV format. By passing , and , it is diff -Nru haproxy-1.5.3/examples/haproxy.spec haproxy-1.5.5/examples/haproxy.spec --- haproxy-1.5.3/examples/haproxy.spec 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/examples/haproxy.spec 2014-10-08 08:07:23.000000000 +0000 @@ -1,6 +1,6 @@ Summary: HA-Proxy is a TCP/HTTP reverse proxy for high availability environments Name: haproxy -Version: 1.5.3 +Version: 1.5.5 Release: 1 License: GPL Group: System Environment/Daemons @@ -76,6 +76,12 @@ %attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name} %changelog +* Wed Oct 8 2014 Willy Tarreau +- updated to 1.5.5 + +* Tue Sep 2 2014 Willy Tarreau +- updated to 1.5.4 + * Fri Jul 25 2014 Willy Tarreau - updated to 1.5.3 diff -Nru haproxy-1.5.3/.gitignore haproxy-1.5.5/.gitignore --- haproxy-1.5.3/.gitignore 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/.gitignore 2014-10-08 08:07:23.000000000 +0000 @@ -12,6 +12,7 @@ *.log* *.trace* haproxy-* +!doc/haproxy-*.txt !src/*.c make-* dlmalloc.c diff -Nru haproxy-1.5.3/include/common/cfgparse.h haproxy-1.5.5/include/common/cfgparse.h --- haproxy-1.5.3/include/common/cfgparse.h 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/include/common/cfgparse.h 2014-10-08 08:07:23.000000000 +0000 @@ -73,6 +73,8 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, const char *file, int line, char **err); int cfg_register_section(char *section_name, int (*section_parser)(const char *, int, char **, int)); +int warnif_misplaced_tcp_conn(struct proxy *proxy, const char *file, int line, const char *arg); +int warnif_misplaced_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg); /* * Sends a warning if proxy does not have at least one of the diff -Nru haproxy-1.5.3/include/proto/proto_http.h haproxy-1.5.5/include/proto/proto_http.h --- haproxy-1.5.3/include/proto/proto_http.h 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/include/proto/proto_http.h 2014-10-08 08:07:23.000000000 +0000 @@ -112,6 +112,7 @@ void http_init_txn(struct session *s); void http_end_txn(struct session *s); void http_reset_txn(struct session *s); +void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg); struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy); struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy); diff -Nru haproxy-1.5.3/include/proto/server.h haproxy-1.5.5/include/proto/server.h --- haproxy-1.5.3/include/proto/server.h 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/include/proto/server.h 2014-10-08 08:07:23.000000000 +0000 @@ -54,8 +54,6 @@ s->counters.last_sess = now.tv_sec; } -#endif /* _PROTO_SERVER_H */ - /* * Registers the server keyword list as a list of valid keywords for next * parsing sessions. @@ -200,6 +198,8 @@ srv_clr_admin_flag(s, SRV_ADMF_FMAINT); } +#endif /* _PROTO_SERVER_H */ + /* * Local variables: * c-indent-level: 8 diff -Nru haproxy-1.5.3/include/proto/ssl_sock.h haproxy-1.5.5/include/proto/ssl_sock.h --- haproxy-1.5.3/include/proto/ssl_sock.h 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/include/proto/ssl_sock.h 2014-10-08 08:07:23.000000000 +0000 @@ -51,7 +51,8 @@ const char *ssl_sock_get_cipher_name(struct connection *conn); const char *ssl_sock_get_proto_version(struct connection *conn); char *ssl_sock_get_version(struct connection *conn); -int ssl_sock_get_cert_used(struct connection *conn); +int ssl_sock_get_cert_used_sess(struct connection *conn); +int ssl_sock_get_cert_used_conn(struct connection *conn); int ssl_sock_get_remote_common_name(struct connection *conn, struct chunk *out); unsigned int ssl_sock_get_verify_result(struct connection *conn); #ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB diff -Nru haproxy-1.5.3/include/types/channel.h haproxy-1.5.5/include/types/channel.h --- haproxy-1.5.3/include/types/channel.h 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/include/types/channel.h 2014-10-08 08:07:23.000000000 +0000 @@ -105,7 +105,7 @@ #define CF_STREAMER 0x00010000 /* the producer is identified as streaming data */ #define CF_STREAMER_FAST 0x00020000 /* the consumer seems to eat the stream very fast */ -/* unused: 0x00040000 */ +#define CF_WROTE_DATA 0x00040000 /* some data were sent from this buffer */ #define CF_ANA_TIMEOUT 0x00080000 /* the analyser timeout has expired */ #define CF_READ_ATTACHED 0x00100000 /* the read side is attached for the first time */ #define CF_KERN_SPLICING 0x00200000 /* kernel splicing desired for this channel */ diff -Nru haproxy-1.5.3/include/types/connection.h haproxy-1.5.5/include/types/connection.h --- haproxy-1.5.3/include/types/connection.h 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/include/types/connection.h 2014-10-08 08:07:23.000000000 +0000 @@ -345,8 +345,9 @@ uint8_t sub_tlv[0]; }__attribute__((packed)); -#define PP2_CLIENT_SSL 0x01 -#define PP2_CLIENT_CERT 0x02 +#define PP2_CLIENT_SSL 0x01 +#define PP2_CLIENT_CERT_CONN 0x02 +#define PP2_CLIENT_CERT_SESS 0x04 #endif /* _TYPES_CONNECTION_H */ diff -Nru haproxy-1.5.3/README haproxy-1.5.5/README --- haproxy-1.5.3/README 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/README 2014-10-08 08:07:23.000000000 +0000 @@ -1,9 +1,9 @@ ---------------------- HAProxy how-to ---------------------- - version 1.5.3 + version 1.5.4 willy tarreau - 2014/07/25 + 2014/09/02 1) How to build it diff -Nru haproxy-1.5.3/src/acl.c haproxy-1.5.5/src/acl.c --- haproxy-1.5.3/src/acl.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/acl.c 2014-10-08 08:07:23.000000000 +0000 @@ -145,7 +145,6 @@ const char *begw; const char *endw; const char *endt; - unsigned long prev_type; int cur_type; int nbargs; int operator = STD_OP_EQ; @@ -161,6 +160,7 @@ struct pat_ref *ref; struct pattern_expr *pattern_expr; int load_as_map = 0; + int acl_conv_found = 0; /* First, we look for an ACL keyword. And if we don't find one, then * we look for a sample fetch expression starting with a sample fetch @@ -229,8 +229,10 @@ /* look for the begining of the converters list. Those directly attached * to the ACL keyword are found just after which points to the comma. + * If we find any converter, then we don't use the ACL keyword's match + * anymore but the one related to the converter's output type. */ - prev_type = smp->fetch->out_type; + cur_type = smp->fetch->out_type; while (*arg) { struct sample_conv *conv; struct sample_conv_expr *conv_expr; @@ -289,19 +291,20 @@ } /* If impossible type conversion */ - if (!sample_casts[prev_type][conv->in_type]) { + if (!sample_casts[cur_type][conv->in_type]) { memprintf(err, "ACL keyword '%s' : conv method '%s' cannot be applied.", aclkw->kw, ckw); goto out_free_smp; } - prev_type = conv->out_type; + cur_type = conv->out_type; conv_expr = calloc(1, sizeof(struct sample_conv_expr)); if (!conv_expr) goto out_free_smp; LIST_ADDQ(&(smp->conv_exprs), &(conv_expr->list)); conv_expr->conv = conv; + acl_conv_found = 1; if (arg != endw) { int err_arg; @@ -347,6 +350,7 @@ memprintf(err, "%s in ACL expression '%s'", *err, *args); goto out_return; } + cur_type = smp_expr_output_type(smp); } expr = (struct acl_expr *)calloc(1, sizeof(*expr)); @@ -357,38 +361,26 @@ pattern_init_head(&expr->pat); - expr->kw = aclkw ? aclkw->kw : smp->fetch->kw; - expr->pat.parse = aclkw ? aclkw->parse : NULL; - expr->pat.index = aclkw ? aclkw->index : NULL; - expr->pat.match = aclkw ? aclkw->match : NULL; - expr->pat.delete = aclkw ? aclkw->delete : NULL; - expr->pat.prune = aclkw ? aclkw->prune : NULL; - expr->pat.expect_type = smp->fetch->out_type; - expr->smp = smp; - smp = NULL; - - /* Fill NULL pointers with values provided by the pattern.c arrays */ - if (aclkw) { - if (!expr->pat.parse) - expr->pat.parse = pat_parse_fcts[aclkw->match_type]; - - if (!expr->pat.index) - expr->pat.index = pat_index_fcts[aclkw->match_type]; - - if (!expr->pat.match) - expr->pat.match = pat_match_fcts[aclkw->match_type]; - - if (!expr->pat.delete) - expr->pat.delete = pat_delete_fcts[aclkw->match_type]; - - if (!expr->pat.prune) - expr->pat.prune = pat_prune_fcts[aclkw->match_type]; + expr->pat.expect_type = cur_type; + expr->smp = smp; + expr->kw = smp->fetch->kw; + smp = NULL; /* don't free it anymore */ + + if (aclkw && !acl_conv_found) { + expr->kw = aclkw->kw; + expr->pat.parse = aclkw->parse ? aclkw->parse : pat_parse_fcts[aclkw->match_type]; + expr->pat.index = aclkw->index ? aclkw->index : pat_index_fcts[aclkw->match_type]; + expr->pat.match = aclkw->match ? aclkw->match : pat_match_fcts[aclkw->match_type]; + expr->pat.delete = aclkw->delete ? aclkw->delete : pat_delete_fcts[aclkw->match_type]; + expr->pat.prune = aclkw->prune ? aclkw->prune : pat_prune_fcts[aclkw->match_type]; } if (!expr->pat.parse) { - /* some types can be automatically converted */ - - switch (expr->smp ? expr->smp->fetch->out_type : aclkw->smp->out_type) { + /* Parse/index/match functions depend on the expression type, + * so we have to map them now. Some types can be automatically + * converted. + */ + switch (cur_type) { case SMP_T_BOOL: expr->pat.parse = pat_parse_fcts[PAT_MATCH_BOOL]; expr->pat.index = pat_index_fcts[PAT_MATCH_BOOL]; @@ -427,7 +419,6 @@ } /* Additional check to protect against common mistakes */ - cur_type = smp_expr_output_type(expr->smp); if (expr->pat.parse && cur_type != SMP_T_BOOL && !*args[1]) { Warning("parsing acl keyword '%s' :\n" " no pattern to match against were provided, so this ACL will never match.\n" diff -Nru haproxy-1.5.3/src/auth.c haproxy-1.5.5/src/auth.c --- haproxy-1.5.3/src/auth.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/auth.c 2014-10-08 08:07:23.000000000 +0000 @@ -252,7 +252,7 @@ fprintf(stderr, ", crypt=%s\n", ep); #endif - if (!strcmp(ep, u->pass)) + if (ep && strcmp(ep, u->pass) == 0) return 1; else return 0; diff -Nru haproxy-1.5.3/src/cfgparse.c haproxy-1.5.5/src/cfgparse.c --- haproxy-1.5.3/src/cfgparse.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/cfgparse.c 2014-10-08 08:07:23.000000000 +0000 @@ -10,6 +10,16 @@ * */ +#ifdef CONFIG_HAP_CRYPT +/* This is to have crypt() defined on Linux */ +#define _GNU_SOURCE + +#ifdef NEED_CRYPT_H +/* some platforms such as Solaris need this */ +#include +#endif +#endif /* CONFIG_HAP_CRYPT */ + #include #include #include @@ -307,6 +317,19 @@ return 0; } +/* Report a warning if a rule is placed after a 'tcp-request content' rule. + * Return 1 if the warning has been emitted, otherwise 0. + */ +int warnif_rule_after_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg) +{ + if (!LIST_ISEMPTY(&proxy->tcp_req.inspect_rules)) { + Warning("parsing [%s:%d] : a '%s' rule placed after a 'tcp-request content' rule will still be processed before.\n", + file, line, arg); + return 1; + } + return 0; +} + /* Report a warning if a rule is placed after a 'block' rule. * Return 1 if the warning has been emitted, otherwise 0. */ @@ -398,6 +421,31 @@ return 0; } +/* report a warning if a "tcp request connection" rule is dangerously placed */ +int warnif_misplaced_tcp_conn(struct proxy *proxy, const char *file, int line, const char *arg) +{ + return warnif_rule_after_tcp_cont(proxy, file, line, arg) || + warnif_rule_after_block(proxy, file, line, arg) || + warnif_rule_after_http_req(proxy, file, line, arg) || + warnif_rule_after_reqxxx(proxy, file, line, arg) || + warnif_rule_after_reqadd(proxy, file, line, arg) || + warnif_rule_after_redirect(proxy, file, line, arg) || + warnif_rule_after_use_backend(proxy, file, line, arg) || + warnif_rule_after_use_server(proxy, file, line, arg); +} + +/* report a warning if a "tcp request content" rule is dangerously placed */ +int warnif_misplaced_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg) +{ + return warnif_rule_after_block(proxy, file, line, arg) || + warnif_rule_after_http_req(proxy, file, line, arg) || + warnif_rule_after_reqxxx(proxy, file, line, arg) || + warnif_rule_after_reqadd(proxy, file, line, arg) || + warnif_rule_after_redirect(proxy, file, line, arg) || + warnif_rule_after_use_backend(proxy, file, line, arg) || + warnif_rule_after_use_server(proxy, file, line, arg); +} + /* report a warning if a block rule is dangerously placed */ int warnif_misplaced_block(struct proxy *proxy, const char *file, int line, const char *arg) { @@ -5689,7 +5737,14 @@ while (*args[cur_arg]) { if (!strcmp(args[cur_arg], "password")) { -#ifndef CONFIG_HAP_CRYPT +#ifdef CONFIG_HAP_CRYPT + if (!crypt("", args[cur_arg + 1])) { + Alert("parsing [%s:%d]: the encrypted password used for user '%s' is not supported by crypt(3).\n", + file, linenum, newuser->user); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } +#else Warning("parsing [%s:%d]: no crypt(3) support compiled, encrypted passwords will not work.\n", file, linenum); err_code |= ERR_ALERT; @@ -5915,6 +5970,66 @@ return err_code; } +/* This function propagates processes from frontend to backend so + * that it is always guaranteed that a backend pointed to by a frontend is + * bound to all of its processes. After that, if the target is a "listen" + * instance, the function recursively descends the target's own targets along + * default_backend, use_backend rules, and reqsetbe rules. Since the bits are + * checked first to ensure that is already bound to all processes of + * , there is no risk of looping and we ensure to follow the shortest + * path to the destination. + * + * It is possible to set to NULL for the first call so that the function + * takes care of visiting the initial frontend in . + * + * It is important to note that the function relies on the fact that all names + * have already been resolved. + */ +void propagate_processes(struct proxy *from, struct proxy *to) +{ + struct switching_rule *rule; + struct hdr_exp *exp; + + if (to) { + /* check whether we need to go down */ + if (from->bind_proc && + (from->bind_proc & to->bind_proc) == from->bind_proc) + return; + + if (!from->bind_proc && !to->bind_proc) + return; + + to->bind_proc = from->bind_proc ? + (to->bind_proc | from->bind_proc) : 0; + + /* now propagate down */ + from = to; + } + + if (!from->cap & PR_CAP_FE) + return; + + /* default_backend */ + if (from->defbe.be) + propagate_processes(from, from->defbe.be); + + /* use_backend */ + list_for_each_entry(rule, &from->switching_rules, list) { + if (rule->dynamic) + continue; + to = rule->be.backend; + propagate_processes(from, to); + } + + /* reqsetbe */ + for (exp = from->req_exp; exp != NULL; exp = exp->next) { + if (exp->action != ACT_SETBE) + continue; + to = (struct proxy *)exp->replace; + propagate_processes(from, to); + } +} + /* * Returns the error code, 0 if OK, or any combination of : * - ERR_ABORT: must abort ASAP @@ -5967,12 +6082,11 @@ proxy = next; } - while (curproxy != NULL) { + for (curproxy = proxy; curproxy; curproxy = curproxy->next) { struct switching_rule *rule; struct server_rule *srule; struct sticking_rule *mrule; struct tcp_rule *trule; - struct listener *listener; unsigned int next_id; int nbproc; @@ -6040,14 +6154,6 @@ } } - /* here, if bind_proc is null, it means no limit, otherwise it's explicit. - * We now check how many processes the proxy will effectively run on. - */ - - nbproc = global.nbproc; - if (curproxy->bind_proc) - nbproc = popcount(curproxy->bind_proc & nbits(global.nbproc)); - if (global.nbproc > 1 && curproxy->table.peers.name) { Alert("Proxy '%s': peers can't be used in multi-process mode (nbproc > 1).\n", curproxy->id); @@ -6145,12 +6251,6 @@ } else { free(curproxy->defbe.name); curproxy->defbe.be = target; - /* we force the backend to be present on at least all of - * the frontend's processes. - */ - if (target->bind_proc) - target->bind_proc = curproxy->bind_proc ? - (target->bind_proc | curproxy->bind_proc) : 0; /* Emit a warning if this proxy also has some servers */ if (curproxy->srv) { @@ -6183,12 +6283,6 @@ } else { free((void *)exp->replace); exp->replace = (const char *)target; - /* we force the backend to be present on at least all of - * the frontend's processes. - */ - if (target->bind_proc) - target->bind_proc = curproxy->bind_proc ? - (target->bind_proc | curproxy->bind_proc) : 0; } } } @@ -6237,16 +6331,10 @@ } else { free((void *)rule->be.name); rule->be.backend = target; - /* we force the backend to be present on at least all of - * the frontend's processes. - */ - if (target->bind_proc) - target->bind_proc = curproxy->bind_proc ? - (target->bind_proc | curproxy->bind_proc) : 0; } } - /* find the target proxy for 'use_backend' rules */ + /* find the target server for 'use_server' rules */ list_for_each_entry(srule, &curproxy->server_rules, list) { struct server *target = findserver(curproxy, srule->srv.name); @@ -6912,6 +7000,29 @@ newsrv = newsrv->next; } + /* check if we have a frontend with "tcp-request content" looking at L7 + * with no inspect-delay + */ + if ((curproxy->cap & PR_CAP_FE) && !curproxy->tcp_req.inspect_delay) { + list_for_each_entry(trule, &curproxy->tcp_req.inspect_rules, list) { + if (trule->action == TCP_ACT_CAPTURE && + !(trule->act_prm.cap.expr->fetch->val & SMP_VAL_FE_SES_ACC)) + break; + if ((trule->action >= TCP_ACT_TRK_SC0 && trule->action <= TCP_ACT_TRK_SCMAX) && + !(trule->act_prm.trk_ctr.expr->fetch->val & SMP_VAL_FE_SES_ACC)) + break; + } + + if (&trule->list != &curproxy->tcp_req.inspect_rules) { + Warning("config : %s '%s' : some 'tcp-request content' rules explicitly depending on request" + " contents were found in a frontend without any 'tcp-request inspect-delay' setting." + " This means that these rules will randomly find their contents. This can be fixed by" + " setting the tcp-request inspect-delay.\n", + proxy_type_str(curproxy), curproxy->id); + err_code |= ERR_WARN; + } + } + if (curproxy->cap & PR_CAP_FE) { if (!curproxy->accept) curproxy->accept = frontend_accept; @@ -6948,6 +7059,90 @@ if (curproxy->options2 & PR_O2_RDPC_PRST) curproxy->be_req_ana |= AN_REQ_PRST_RDP_COOKIE; } + } + + /***********************************************************/ + /* At this point, target names have already been resolved. */ + /***********************************************************/ + + /* Check multi-process mode compatibility */ + + if (global.nbproc > 1 && global.stats_fe) { + list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { + unsigned long mask; + + mask = nbits(global.nbproc); + if (global.stats_fe->bind_proc) + mask &= global.stats_fe->bind_proc; + + if (bind_conf->bind_proc) + mask &= bind_conf->bind_proc; + + /* stop here if more than one process is used */ + if (popcount(mask) > 1) + break; + } + if (&bind_conf->by_fe != &global.stats_fe->conf.bind) { + Warning("stats socket will not work as expected in multi-process mode (nbproc > 1), you should force process binding globally using 'stats bind-process' or per socket using the 'process' attribute.\n"); + } + } + + /* Make each frontend inherit bind-process from its listeners when not specified. */ + for (curproxy = proxy; curproxy; curproxy = curproxy->next) { + if (curproxy->bind_proc) + continue; + + list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) { + unsigned long mask; + + mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; + curproxy->bind_proc |= mask; + } + + if (!curproxy->bind_proc) + curproxy->bind_proc = ~0UL; + } + + if (global.stats_fe) { + list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { + unsigned long mask; + + mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; + global.stats_fe->bind_proc |= mask; + } + if (!global.stats_fe->bind_proc) + global.stats_fe->bind_proc = ~0UL; + } + + /* propagate bindings from frontends to backends. Don't do it if there + * are any fatal errors as we must not call it with unresolved proxies. + */ + if (!cfgerr) { + for (curproxy = proxy; curproxy; curproxy = curproxy->next) { + if (curproxy->cap & PR_CAP_FE) + propagate_processes(curproxy, NULL); + } + } + + /* Bind each unbound backend to all processes when not specified. */ + for (curproxy = proxy; curproxy; curproxy = curproxy->next) { + if (curproxy->bind_proc) + continue; + curproxy->bind_proc = ~0UL; + } + + /*******************************************************/ + /* At this step, all proxies have a non-null bind_proc */ + /*******************************************************/ + + /* perform the final checks before creating tasks */ + + for (curproxy = proxy; curproxy; curproxy = curproxy->next) { + struct listener *listener; + unsigned int next_id; + int nbproc; + + nbproc = popcount(curproxy->bind_proc & nbits(global.nbproc)); #ifdef USE_OPENSSL /* Configure SSL for each bind line. @@ -7061,8 +7256,19 @@ if (nbproc > 1) { if (curproxy->uri_auth) { - Warning("Proxy '%s': in multi-process mode, stats will be limited to process assigned to the current request.\n", - curproxy->id); + int count, maxproc = 0; + + list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) { + count = popcount(bind_conf->bind_proc); + if (count > maxproc) + maxproc = count; + } + /* backends have 0, frontends have 1 or more */ + if (maxproc != 1) + Warning("Proxy '%s': in multi-process mode, stats will be" + " limited to process assigned to the current request.\n", + curproxy->id); + if (!LIST_ISEMPTY(&curproxy->uri_auth->admin_rules)) { Warning("Proxy '%s': stats admin will not work correctly in multi-process mode.\n", curproxy->id); @@ -7092,29 +7298,6 @@ curproxy->id); cfgerr++; } - - curproxy = curproxy->next; - } - - /* Check multi-process mode compatibility */ - if (global.nbproc > 1 && global.stats_fe) { - list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { - unsigned long mask; - - mask = nbits(global.nbproc); - if (global.stats_fe->bind_proc) - mask &= global.stats_fe->bind_proc; - - if (bind_conf->bind_proc) - mask &= bind_conf->bind_proc; - - /* stop here if more than one process is used */ - if (popcount(mask) > 1) - break; - } - if (&bind_conf->by_fe != &global.stats_fe->conf.bind) { - Warning("stats socket will not work as expected in multi-process mode (nbproc > 1), you should force process binding globally using 'stats bind-process' or per socket using the 'process' attribute.\n"); - } } /* automatically compute fullconn if not set. We must not do it in the diff -Nru haproxy-1.5.3/src/checks.c haproxy-1.5.5/src/checks.c --- haproxy-1.5.3/src/checks.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/checks.c 2014-10-08 08:07:23.000000000 +0000 @@ -580,6 +580,7 @@ struct check *check = conn->owner; const char *err_msg; struct chunk *chk; + int step; if (check->result != CHK_RES_UNKNOWN) return; @@ -599,19 +600,27 @@ chk = get_trash_chunk(); if (check->type == PR_O2_TCPCHK_CHK) { - chunk_printf(chk, " at step %d of tcp-check", tcpcheck_get_step_id(check->server)); - /* we were looking for a string */ - if (check->current_step && check->current_step->action == TCPCHK_ACT_CONNECT) { - chunk_appendf(chk, " (connect)"); - } - else if (check->current_step && check->current_step->action == TCPCHK_ACT_EXPECT) { - if (check->current_step->string) - chunk_appendf(chk, " (string '%s')", check->current_step->string); - else if (check->current_step->expect_regex) - chunk_appendf(chk, " (expect regex)"); - } - else if (check->current_step && check->current_step->action == TCPCHK_ACT_SEND) { - chunk_appendf(chk, " (send)"); + step = tcpcheck_get_step_id(check->server); + if (!step) + chunk_printf(chk, " at initial connection step of tcp-check"); + else { + chunk_printf(chk, " at step %d of tcp-check", step); + /* we were looking for a string */ + if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_CONNECT) { + if (check->last_started_step->port) + chunk_appendf(chk, " (connect port %d)" ,check->last_started_step->port); + else + chunk_appendf(chk, " (connect)"); + } + else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_EXPECT) { + if (check->last_started_step->string) + chunk_appendf(chk, " (string '%s')", check->last_started_step->string); + else if (check->last_started_step->expect_regex) + chunk_appendf(chk, " (expect regex)"); + } + else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_SEND) { + chunk_appendf(chk, " (send)"); + } } } @@ -1818,6 +1827,10 @@ struct tcpcheck_rule *cur = NULL, *next = NULL; int i = 0; + /* not even started anything yet => step 0 = initial connect */ + if (!s->check.current_step) + return 0; + cur = s->check.last_started_step; /* no step => first step */ @@ -1837,20 +1850,34 @@ static void tcpcheck_main(struct connection *conn) { char *contentptr; - struct list *head = NULL; struct tcpcheck_rule *cur = NULL; int done = 0, ret = 0; - struct check *check = conn->owner; struct server *s = check->server; struct task *t = check->task; + struct list *head = &s->proxy->tcpcheck_rules; - /* - * don't do anything until the connection is established but if we're running - * first step which must be a connect + /* here, we know that the check is complete or that it failed */ + if (check->result != CHK_RES_UNKNOWN) + goto out_end_tcpcheck; + + /* We have 4 possibilities here : + * 1. we've not yet attempted step 1, and step 1 is a connect, so no + * connection attempt was made yet ; + * 2. we've not yet attempted step 1, and step 1 is a not connect or + * does not exist (no rule), so a connection attempt was made + * before coming here. + * 3. we're coming back after having started with step 1, so we may + * be waiting for a connection attempt to complete. + * 4. the connection + handshake are complete + * + * #2 and #3 are quite similar, we want both the connection and the + * handshake to complete before going any further. Thus we must always + * wait for a connection to complete unless we're before and existing + * step 1. */ - if (check->current_step && (!(conn->flags & CO_FL_CONNECTED))) { - /* update expire time, should be done by process_chk */ + if ((!(conn->flags & CO_FL_CONNECTED) || (conn->flags & CO_FL_HANDSHAKE)) && + (check->current_step || LIST_ISEMPTY(head))) { /* we allow up to min(inter, timeout.connect) for a connection * to establish but only when timeout.check is set * as it may be to short for a full check otherwise @@ -1867,16 +1894,15 @@ return; } - /* here, we know that the connection is established */ - if (check->result != CHK_RES_UNKNOWN) + /* special case: option tcp-check with no rule, a connect is enough */ + if (LIST_ISEMPTY(head)) { + set_server_check_status(check, HCHK_STATUS_L4OK, NULL); goto out_end_tcpcheck; + } - /* head is be the first element of the double chained list */ - head = &s->proxy->tcpcheck_rules; - - /* no step means first step - * initialisation */ + /* no step means first step initialisation */ if (check->current_step == NULL) { + check->last_started_step = NULL; check->bo->p = check->bo->data; check->bo->o = 0; check->bi->p = check->bi->data; @@ -1891,9 +1917,6 @@ cur = check->current_step; } - if (conn->flags & CO_FL_HANDSHAKE) - return; - /* It's only the rules which will enable send/recv */ __conn_data_stop_both(conn); diff -Nru haproxy-1.5.3/src/connection.c haproxy-1.5.5/src/connection.c --- haproxy-1.5.3/src/connection.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/connection.c 2014-10-08 08:07:23.000000000 +0000 @@ -678,9 +678,11 @@ tlv_len = make_tlv(&buf[ret+ssl_tlv_len], (buf_len-ret-ssl_tlv_len), PP2_TYPE_SSL_VERSION, strlen(value), value); ssl_tlv_len += tlv_len; } - if (ssl_sock_get_cert_used(remote)) { - tlv->client |= PP2_CLIENT_CERT; + if (ssl_sock_get_cert_used_sess(remote)) { + tlv->client |= PP2_CLIENT_CERT_SESS; tlv->verify = htonl(ssl_sock_get_verify_result(remote)); + if (ssl_sock_get_cert_used_conn(remote)) + tlv->client |= PP2_CLIENT_CERT_CONN; } if (srv->pp_opts & SRV_PP_V2_SSL_CN) { cn_trash = get_trash_chunk(); diff -Nru haproxy-1.5.3/src/dumpstats.c haproxy-1.5.5/src/dumpstats.c --- haproxy-1.5.3/src/dumpstats.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/dumpstats.c 2014-10-08 08:07:23.000000000 +0000 @@ -6045,7 +6045,7 @@ break; case 1: chunk_appendf(&trash, - " backend %s (#%d) : invalid response\n" + " backend %s (#%d): invalid response\n" " frontend %s (#%d)", appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid, es->oe->id, es->oe->uuid); diff -Nru haproxy-1.5.3/src/haproxy-systemd-wrapper.c haproxy-1.5.5/src/haproxy-systemd-wrapper.c --- haproxy-1.5.3/src/haproxy-systemd-wrapper.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/haproxy-systemd-wrapper.c 2014-10-08 08:07:23.000000000 +0000 @@ -22,24 +22,42 @@ #define SD_DEBUG "<7>" #define SD_NOTICE "<5>" +static volatile sig_atomic_t caught_signal; + static char *pid_file = "/run/haproxy.pid"; static int wrapper_argc; static char **wrapper_argv; +/* returns the path to the haproxy binary into , whose size indicated + * in must be at least 1 byte long. + */ static void locate_haproxy(char *buffer, size_t buffer_size) { char *end = NULL; + int len; - if (readlink("/proc/self/exe", buffer, buffer_size) > 0) - end = strrchr(buffer, '/'); + len = readlink("/proc/self/exe", buffer, buffer_size - 1); + if (len == -1) + goto fail; + + buffer[len] = 0; + end = strrchr(buffer, '/'); + if (end == NULL) + goto fail; - if (end == NULL) { - strncpy(buffer, "/usr/sbin/haproxy", buffer_size); + if (strcmp(end + strlen(end) - 16, "-systemd-wrapper") == 0) { + end[strlen(end) - 16] = '\0'; return; } + end[1] = '\0'; strncpy(end + 1, "haproxy", buffer + buffer_size - (end + 1)); buffer[buffer_size - 1] = '\0'; + return; + fail: + strncpy(buffer, "/usr/sbin/haproxy", buffer_size); + buffer[buffer_size - 1] = '\0'; + return; } static void spawn_haproxy(char **pid_strv, int nb_pid) @@ -103,7 +121,12 @@ return read; } -static void sigusr2_handler(int signum __attribute__((unused))) +static void signal_handler(int signum) +{ + caught_signal = signum; +} + +static void do_restart(void) { setenv(REEXEC_FLAG, "1", 1); fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: re-executing\n"); @@ -111,7 +134,7 @@ execv(wrapper_argv[0], wrapper_argv); } -static void sigint_handler(int signum __attribute__((unused))) +static void do_shutdown(void) { int i, pid; char **pid_strv = NULL; @@ -130,11 +153,8 @@ static void init(int argc, char **argv) { while (argc > 1) { - if (**argv == '-') { - char *flag = *argv + 1; - --argc; ++argv; - if (*flag == 'p') - pid_file = *argv; + if ((*argv)[0] == '-' && (*argv)[1] == 'p') { + pid_file = *(argv + 1); } --argc; ++argv; } @@ -150,25 +170,23 @@ --argc; ++argv; init(argc, argv); - signal(SIGINT, &sigint_handler); - signal(SIGUSR2, &sigusr2_handler); + struct sigaction sa; + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = &signal_handler; + sigaction(SIGUSR2, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); if (getenv(REEXEC_FLAG) != NULL) { /* We are being re-executed: restart HAProxy gracefully */ int i; char **pid_strv = NULL; int nb_pid = read_pids(&pid_strv); - sigset_t sigs; unsetenv(REEXEC_FLAG); spawn_haproxy(pid_strv, nb_pid); - /* Unblock SIGUSR2 which was blocked by the signal handler - * before re-exec */ - sigprocmask(SIG_BLOCK, NULL, &sigs); - sigdelset(&sigs, SIGUSR2); - sigprocmask(SIG_SETMASK, &sigs, NULL); - for (i = 0; i < nb_pid; ++i) free(pid_strv[i]); free(pid_strv); @@ -179,8 +197,16 @@ } status = -1; - while (-1 != wait(&status) || errno == EINTR) - ; + while (-1 != wait(&status) || errno == EINTR) { + if (caught_signal == SIGUSR2 || caught_signal == SIGHUP) { + caught_signal = 0; + do_restart(); + } + else if (caught_signal == SIGINT || caught_signal == SIGTERM) { + caught_signal = 0; + do_shutdown(); + } + } fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: exit, haproxy RC=%d\n", status); diff -Nru haproxy-1.5.3/src/pattern.c haproxy-1.5.5/src/pattern.c --- haproxy-1.5.3/src/pattern.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/pattern.c 2014-10-08 08:07:23.000000000 +0000 @@ -178,19 +178,15 @@ * * These functions are exported and may be used by any other component. * - * The following functions are used for parsing pattern matching - * input value. The contain the string to be parsed. - * must be a preallocated pattern. The pat_parse_* functions fill this - * structure with the parsed value. can be PAT_U_COMPILE or - * PAT_U_LOOKUP. If the value PAT_U_COMPILE is used memory is allocated - * for filling the pattern. If the value PAT_U_LOOKUP is set, the parser - * use "trash" or return pointers to the input strings. In both cases, - * the caller must use the value PAT_U_LOOKUP with caution. is - * filled with an error message built with memprintf() function. - * - * In succes case, the pat_parse_* function return 1. If the function - * fail, it returns 0 and is filled. + * The following functions are used for parsing pattern matching input value. + * The contain the string to be parsed. must be a preallocated + * pattern. The pat_parse_* functions fill this structure with the parsed value. + * is filled with an error message built with memprintf() function. It is + * allowed to use a trash as a temporary storage for the returned pattern, as + * the next call after these functions will be pat_idx_*. * + * In success case, the pat_parse_* function returns 1. If the function + * fails, it returns 0 and is filled. */ /* ignore the current line */ @@ -223,17 +219,7 @@ /* Parse a regex. It is allocated. */ int pat_parse_reg(const char *text, struct pattern *pattern, int mflags, char **err) { - struct chunk *trash; - - trash = get_trash_chunk(); - if (trash->size < sizeof(*pattern->ptr.reg)) { - memprintf(err, "no space avalaible in the buffer. expect %d, provides %d", - (int)sizeof(*pattern->ptr.reg), trash->size); - return 0; - } - pattern->ptr.str = (char *)text; - return 1; } diff -Nru haproxy-1.5.3/src/proto_http.c haproxy-1.5.5/src/proto_http.c --- haproxy-1.5.3/src/proto_http.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/proto_http.c 2014-10-08 08:07:23.000000000 +0000 @@ -2393,6 +2393,59 @@ return 0; } +void http_adjust_conn_mode(struct session *s, struct http_txn *txn, struct http_msg *msg) +{ + int tmp = TX_CON_WANT_KAL; + + if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) { + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN) + tmp = TX_CON_WANT_TUN; + + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) + tmp = TX_CON_WANT_TUN; + } + + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) { + /* option httpclose + server_close => forceclose */ + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) + tmp = TX_CON_WANT_CLO; + else + tmp = TX_CON_WANT_SCL; + } + + if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL) + tmp = TX_CON_WANT_CLO; + + if ((txn->flags & TX_CON_WANT_MSK) < tmp) + txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp; + + if (!(txn->flags & TX_HDR_CONN_PRS) && + (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) { + /* parse the Connection header and possibly clean it */ + int to_del = 0; + if ((msg->flags & HTTP_MSGF_VER_11) || + ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL && + !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA))) + to_del |= 2; /* remove "keep-alive" */ + if (!(msg->flags & HTTP_MSGF_VER_11)) + to_del |= 1; /* remove "close" */ + http_parse_connection_header(txn, msg, to_del); + } + + /* check if client or config asks for explicit close in KAL/SCL */ + if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL || + (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) && + ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */ + (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */ + !(msg->flags & HTTP_MSGF_XFER_LEN) || /* no length known => close */ + s->fe->state == PR_STSTOPPED)) /* frontend is stopping */ + txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO; +} /* This stream analyser waits for a complete HTTP request. It returns 1 if the * processing can continue on next analysers, or zero if it either needs more @@ -2929,58 +2982,8 @@ * time. */ if (!(txn->flags & TX_HDR_CONN_PRS) || - ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE))) { - int tmp = TX_CON_WANT_KAL; - - if (!((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA)) { - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN) - tmp = TX_CON_WANT_TUN; - - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) - tmp = TX_CON_WANT_TUN; - } - - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) { - /* option httpclose + server_close => forceclose */ - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL) - tmp = TX_CON_WANT_CLO; - else - tmp = TX_CON_WANT_SCL; - } - - if ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL || - (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL) - tmp = TX_CON_WANT_CLO; - - if ((txn->flags & TX_CON_WANT_MSK) < tmp) - txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp; - - if (!(txn->flags & TX_HDR_CONN_PRS) && - (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) { - /* parse the Connection header and possibly clean it */ - int to_del = 0; - if ((msg->flags & HTTP_MSGF_VER_11) || - ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL && - !((s->fe->options2|s->be->options2) & PR_O2_FAKE_KA))) - to_del |= 2; /* remove "keep-alive" */ - if (!(msg->flags & HTTP_MSGF_VER_11)) - to_del |= 1; /* remove "close" */ - http_parse_connection_header(txn, msg, to_del); - } - - /* check if client or config asks for explicit close in KAL/SCL */ - if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL || - (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) && - ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */ - (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */ - !(msg->flags & HTTP_MSGF_XFER_LEN) || /* no length known => close */ - s->fe->state == PR_STSTOPPED)) /* frontend is stopping */ - txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO; - } + ((s->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE))) + http_adjust_conn_mode(s, txn, msg); /* end of job, return OK */ req->analysers &= ~an_bit; @@ -4117,8 +4120,9 @@ done: /* done with this analyser, continue with next ones that the calling * points will have set, if any. */ - req->analysers &= ~an_bit; req->analyse_exp = TICK_ETERNITY; + done_without_exp: /* done with this analyser, but dont reset the analyse_exp. */ + req->analysers &= ~an_bit; return 1; tarpit: @@ -4144,7 +4148,7 @@ s->be->be_counters.denied_req++; if (s->listener->counters) s->listener->counters->denied_req++; - goto done; + goto done_without_exp; deny: /* this request was blocked (denied) */ txn->flags |= TX_CLDENY; @@ -4885,8 +4889,8 @@ s->req->cons->conn_retries = 0; /* used for logging too */ s->req->cons->exp = TICK_ETERNITY; s->req->cons->flags &= SI_FL_DONT_WAKE; /* we're in the context of process_session */ - s->req->flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_WRITE_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WAKE_CONNECT); - s->rep->flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_READ_ATTACHED|CF_READ_ERROR|CF_READ_NOEXP|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_PARTIAL|CF_NEVER_WAIT); + s->req->flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_WRITE_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WAKE_CONNECT|CF_WROTE_DATA); + s->rep->flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_READ_ATTACHED|CF_READ_ERROR|CF_READ_NOEXP|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_PARTIAL|CF_NEVER_WAIT|CF_WROTE_DATA); s->flags &= ~(SN_DIRECT|SN_ASSIGNED|SN_ADDR_SET|SN_BE_ASSIGNED|SN_FORCE_PRST|SN_IGNORE_PRST); s->flags &= ~(SN_CURR_SESS|SN_REDIRECTABLE|SN_SRV_REUSED); @@ -5429,7 +5433,7 @@ * such as last chunk of data or trailers. */ b_adv(req->buf, msg->next); - if (unlikely(!(s->rep->flags & CF_READ_ATTACHED))) + if (unlikely(!(s->req->flags & CF_WROTE_DATA))) msg->sov -= msg->next; msg->next = 0; @@ -5481,7 +5485,7 @@ missing_data: /* we may have some pending data starting at req->buf->p */ b_adv(req->buf, msg->next); - if (unlikely(!(s->rep->flags & CF_READ_ATTACHED))) + if (unlikely(!(s->req->flags & CF_WROTE_DATA))) msg->sov -= msg->next + MIN(msg->chunk_len, req->buf->i); msg->next = 0; @@ -6248,7 +6252,7 @@ /* add response headers from the rule sets in the same order */ list_for_each_entry(wl, &rule_set->rsp_add, list) { - if (txn->status < 200) + if (txn->status < 200 && txn->status != 101) break; if (wl->cond) { int ret = acl_exec_cond(wl->cond, px, s, txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL); @@ -6269,7 +6273,7 @@ } /* OK that's all we can do for 1xx responses */ - if (unlikely(txn->status < 200)) + if (unlikely(txn->status < 200 && txn->status != 101)) goto skip_header_mangling; /* @@ -6282,7 +6286,7 @@ /* * Check for cache-control or pragma headers if required. */ - if ((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC)) + if (((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC)) && txn->status != 101) check_response_for_cacheability(s, rep); /* @@ -6398,9 +6402,11 @@ * Adjust "Connection: close" or "Connection: keep-alive" if needed. * If an "Upgrade" token is found, the header is left untouched in order * not to have to deal with some client bugs : some of them fail an upgrade - * if anything but "Upgrade" is present in the Connection header. + * if anything but "Upgrade" is present in the Connection header. We don't + * want to touch any 101 response either since it's switching to another + * protocol. */ - if (!(txn->flags & TX_HDR_CONN_UPG) && + if ((txn->status != 101) && !(txn->flags & TX_HDR_CONN_UPG) && (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) || ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL))) { @@ -9281,8 +9287,8 @@ cur_arg = 1; if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] || - (*args[cur_arg+3] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) { - Alert("parsing [%s:%d]: 'http-request %s' expects exactly 3 arguments.\n", + (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) { + Alert("parsing [%s:%d]: 'http-response %s' expects exactly 3 arguments.\n", file, linenum, args[0]); goto out_err; } @@ -9770,20 +9776,13 @@ static int pat_parse_meth(const char *text, struct pattern *pattern, int mflags, char **err) { int len, meth; - struct chunk *trash; len = strlen(text); meth = find_http_meth(text, len); pattern->val.i = meth; if (meth == HTTP_METH_OTHER) { - trash = get_trash_chunk(); - if (trash->size < len) { - memprintf(err, "no space avalaible in the buffer. expect %d, provides %d", - len, trash->size); - return 0; - } - pattern->ptr.str = trash->str; + pattern->ptr.str = (char *)text; pattern->len = len; } else { @@ -9848,8 +9847,8 @@ continue; icase = expr->mflags & PAT_MF_IGNORE_CASE; - if ((icase && strncasecmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0) || - (!icase && strncmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) != 0)) + if ((icase && strncasecmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) == 0) || + (!icase && strncmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) == 0)) return pattern; } return NULL; diff -Nru haproxy-1.5.3/src/proto_tcp.c haproxy-1.5.5/src/proto_tcp.c --- haproxy-1.5.3/src/proto_tcp.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/proto_tcp.c 2014-10-08 08:07:23.000000000 +0000 @@ -1048,8 +1048,8 @@ t = rule->act_prm.trk_ctr.table.t; key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.trk_ctr.expr, &smp); - if (smp.flags & SMP_F_MAY_CHANGE) - goto missing_data; + if ((smp.flags & SMP_F_MAY_CHANGE) && !(partial & SMP_OPT_FINAL)) + goto missing_data; /* key might appear later */ if (key && (ts = stktable_get_entry(t, key))) { session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts); @@ -1711,6 +1711,8 @@ warn++; } + /* the following function directly emits the warning */ + warnif_misplaced_tcp_cont(curpx, file, line, args[0]); LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list); } else if (strcmp(args[1], "connection") == 0) { @@ -1754,6 +1756,8 @@ warn++; } + /* the following function directly emits the warning */ + warnif_misplaced_tcp_conn(curpx, file, line, args[0]); LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list); } else { diff -Nru haproxy-1.5.3/src/proxy.c haproxy-1.5.5/src/proxy.c --- haproxy-1.5.3/src/proxy.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/proxy.c 2014-10-08 08:07:23.000000000 +0000 @@ -955,6 +955,14 @@ http_init_txn(s); } + /* If we chain to an HTTP backend running a different HTTP mode, we + * have to re-adjust the desired keep-alive/close mode to accommodate + * both the frontend's and the backend's modes. + */ + if (s->fe->mode == PR_MODE_HTTP && be->mode == PR_MODE_HTTP && + ((s->fe->options & PR_O_HTTP_MODE) != (be->options & PR_O_HTTP_MODE))) + http_adjust_conn_mode(s, &s->txn, &s->txn.req); + /* If an LB algorithm needs to access some pre-parsed body contents, * we must not start to forward anything until the connection is * confirmed otherwise we'll lose the pointer to these data and diff -Nru haproxy-1.5.3/src/sample.c haproxy-1.5.5/src/sample.c --- haproxy-1.5.3/src/sample.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/sample.c 2014-10-08 08:07:23.000000000 +0000 @@ -896,6 +896,18 @@ * Note: the fetch functions are required to properly set the return type. The * conversion functions must do so too. However the cast functions do not need * to since they're made to cast mutiple types according to what is required. + * + * The caller may indicate in if it considers the result final or not. + * The caller needs to check the SMP_F_MAY_CHANGE flag in p->flags to verify + * if the result is stable or not, according to the following table : + * + * return MAY_CHANGE FINAL Meaning for the sample + * NULL 0 * Not present and will never be (eg: header) + * NULL 1 0 Not present yet, could change (eg: POST param) + * NULL 1 1 Not present yet, will not change anymore + * smp 0 * Present and will not change (eg: header) + * smp 1 0 Present, may change (eg: request length) + * smp 1 1 Present, last known value (eg: request length) */ struct sample *sample_process(struct proxy *px, struct session *l4, void *l7, unsigned int opt, @@ -1153,7 +1165,16 @@ * and does not contain SMP_OPT_FINAL, then the sample is returned as-is * with its SMP_F_MAY_CHANGE flag so that the caller can check it and decide to * take actions (eg: wait longer). If a sample could not be found or could not - * be converted, NULL is returned. + * be converted, NULL is returned. The caller MUST NOT use the sample if the + * SMP_F_MAY_CHANGE flag is present, as it is used only as a hint that there is + * still hope to get it after waiting longer, and is not converted to string. + * The possible output combinations are the following : + * + * return MAY_CHANGE FINAL Meaning for the sample + * NULL * * Not present and will never be (eg: header) + * smp 0 * Final value converted (eg: header) + * smp 1 0 Not present yet, may appear later (eg: header) + * smp 1 1 never happens (either flag is cleared on output) */ struct sample *sample_fetch_string(struct proxy *px, struct session *l4, void *l7, unsigned int opt, struct sample_expr *expr) diff -Nru haproxy-1.5.3/src/ssl_sock.c haproxy-1.5.5/src/ssl_sock.c --- haproxy-1.5.3/src/ssl_sock.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/ssl_sock.c 2014-10-08 08:07:23.000000000 +0000 @@ -2720,8 +2720,25 @@ return result; } -/* returns 1 if client passed a certificate, 0 if not */ -int ssl_sock_get_cert_used(struct connection *conn) +/* returns 1 if client passed a certificate for this session, 0 if not */ +int ssl_sock_get_cert_used_sess(struct connection *conn) +{ + X509 *crt = NULL; + + if (!ssl_sock_is_ssl(conn)) + return 0; + + /* SSL_get_peer_certificate, it increase X509 * ref count */ + crt = SSL_get_peer_certificate(conn->xprt_ctx); + if (!crt) + return 0; + + X509_free(crt); + return 1; +} + +/* returns 1 if client passed a certificate for this connection, 0 if not */ +int ssl_sock_get_cert_used_conn(struct connection *conn) { if (!ssl_sock_is_ssl(conn)) return 0; diff -Nru haproxy-1.5.3/src/stick_table.c haproxy-1.5.5/src/stick_table.c --- haproxy-1.5.3/src/stick_table.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/stick_table.c 2014-10-08 08:07:23.000000000 +0000 @@ -603,7 +603,16 @@ * no key could be extracted, or a pointer to the converted result stored in * static_table_key in format . If is not NULL, it will be reset * and its flags will be initialized so that the caller gets a copy of the input - * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present). + * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present + * without SMP_OPT_FINAL). The output will be usable like this : + * + * return MAY_CHANGE FINAL Meaning for the sample + * NULL 0 * Not present and will never be (eg: header) + * NULL 1 0 Not present or unstable, could change (eg: req_len) + * NULL 1 1 Not present, will not change anymore + * smp 0 * Present and will not change (eg: header) + * smp 1 0 not possible + * smp 1 1 Present, last known value (eg: request length) */ struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *l4, void *l7, unsigned int opt, struct sample_expr *expr, struct sample *smp) diff -Nru haproxy-1.5.3/src/stream_interface.c haproxy-1.5.5/src/stream_interface.c --- haproxy-1.5.3/src/stream_interface.c 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/src/stream_interface.c 2014-10-08 08:07:23.000000000 +0000 @@ -658,7 +658,7 @@ if (chn->pipe && conn->xprt->snd_pipe) { ret = conn->xprt->snd_pipe(conn, chn->pipe); if (ret > 0) - chn->flags |= CF_WRITE_PARTIAL; + chn->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA; if (!chn->pipe->data) { put_pipe(chn->pipe); @@ -702,7 +702,7 @@ ret = conn->xprt->snd_buf(conn, chn->buf, send_flag); if (ret > 0) { - chn->flags |= CF_WRITE_PARTIAL; + chn->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA; if (!chn->buf->o) { /* Always clear both flags once everything has been sent, they're one-shot */ diff -Nru haproxy-1.5.3/VERDATE haproxy-1.5.5/VERDATE --- haproxy-1.5.3/VERDATE 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/VERDATE 2014-10-08 08:07:23.000000000 +0000 @@ -1,2 +1,2 @@ $Format:%ci$ -2014/07/25 +2014/10/07 diff -Nru haproxy-1.5.3/VERSION haproxy-1.5.5/VERSION --- haproxy-1.5.3/VERSION 2014-07-25 06:56:07.000000000 +0000 +++ haproxy-1.5.5/VERSION 2014-10-08 08:07:23.000000000 +0000 @@ -1 +1 @@ -1.5.3 +1.5.5