MINOR: ssl: add 'ssl_npn' sample/acl to extract TLS/NPN information

This may be used to distinguish between SPDY versions for example.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 208c432..119f440 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -8339,6 +8339,12 @@
   that the SSL library is build with support for TLS extensions enabled (check
   haproxy -vv).
 
+ssl_npn <string>
+  Returns true when the incoming connection was made over an SSL/TLS transport
+  layer which deciphered it and found a Next Protocol Negociation TLS extension
+  sent by the client, matching the specified string. This requires that the SSL
+  library is build with support for TLS extensions enabled (check haproxy -vv).
+
 ssl_sni <string>
   Returns true when the incoming connection was made over an SSL/TLS transport
   layer which deciphered it and found a Server Name Indication TLS extension
@@ -8996,6 +9002,13 @@
                otherwise zero. This requires that the SSL library is build with
                support for TLS extensions enabled (check haproxy -vv).
 
+  ssl_npn      This extracts the Next Protocol Negociation field from an
+               incoming connection made via an SSL/TLS transport layer and
+               locally deciphered by haproxy. The result is a string containing
+               the protocol name advertised by the client. The SSL library must
+               have been built with support for TLS extensions enabled (check
+               haproxy -vv).
+
   ssl_sni      This extracts the Server Name Indication field from an incoming
                connection made via an SSL/TLS transport layer and locally
                deciphered by haproxy. The result typically is a string matching
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 9aed915..6121b12 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1119,6 +1119,30 @@
 }
 
 static int
+smp_fetch_ssl_npn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
+                  const struct arg *args, struct sample *smp)
+{
+#ifdef OPENSSL_NPN_NEGOTIATED
+	smp->flags = 0;
+	smp->type = SMP_T_CSTR;
+
+	if (!l4 || !l4->si[0].conn.xprt_ctx || l4->si[0].conn.xprt != &ssl_sock)
+		return 0;
+
+	smp->data.str.str = NULL;
+	SSL_get0_next_proto_negotiated(l4->si[0].conn.xprt_ctx,
+	                                (const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len);
+
+	if (!smp->data.str.str)
+		return 0;
+
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static int
 smp_fetch_ssl_sni(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                   const struct arg *args, struct sample *smp)
 {
@@ -1662,6 +1686,9 @@
 	{ "client_crt",             smp_fetch_client_crt,         0,    NULL,    SMP_T_BOOL, SMP_CAP_REQ|SMP_CAP_RES },
 	{ "is_ssl",                 smp_fetch_is_ssl,             0,    NULL,    SMP_T_BOOL, SMP_CAP_REQ|SMP_CAP_RES },
 	{ "ssl_has_sni",            smp_fetch_has_sni,            0,    NULL,    SMP_T_BOOL, SMP_CAP_REQ|SMP_CAP_RES },
+#ifdef OPENSSL_NPN_NEGOTIATED
+	{ "ssl_npn",                smp_fetch_ssl_npn,            0,    NULL,    SMP_T_CSTR, SMP_CAP_REQ|SMP_CAP_RES },
+#endif
 	{ "ssl_sni",                smp_fetch_ssl_sni,            0,    NULL,    SMP_T_CSTR, SMP_CAP_REQ|SMP_CAP_RES },
 	{ "ssl_verify_caerr",       smp_fetch_verify_caerr,       0,    NULL,    SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
 	{ "ssl_verify_caerr_depth", smp_fetch_verify_caerr_depth, 0,    NULL,    SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
@@ -1677,6 +1704,9 @@
 	{ "client_crt",             acl_parse_int, smp_fetch_client_crt,         acl_match_nothing, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
 	{ "is_ssl",                 acl_parse_int, smp_fetch_is_ssl,             acl_match_nothing, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
 	{ "ssl_has_sni",            acl_parse_int, smp_fetch_has_sni,            acl_match_nothing, ACL_USE_L6REQ_PERMANENT, 0 },
+#ifdef OPENSSL_NPN_NEGOTIATED
+	{ "ssl_npn",                acl_parse_str, smp_fetch_ssl_npn,            acl_match_str,     ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
+#endif
 	{ "ssl_sni",                acl_parse_str, smp_fetch_ssl_sni,            acl_match_str,     ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
 	{ "ssl_sni_end",            acl_parse_str, smp_fetch_ssl_sni,            acl_match_end,     ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
 	{ "ssl_sni_reg",            acl_parse_str, smp_fetch_ssl_sni,            acl_match_reg,     ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },