[BUG] checks: don't wait for a close to start parsing the response
Cyril Bont reported a regression introduced with very last changes on the checks code, which causes failed checks on if the server does not close the connection in time. This happens on HTTP/1.1 checks or on SMTP checks for instance. This fix consists in restoring the old behaviour of parsing as soon as something is available in the response buffer, and waiting for more data if some are missing. This also helps releasing connections earlier (eg: a GET check will not have to download the whole object).
This commit is contained in:
parent
e437c44483
commit
039381855d
45
src/checks.c
45
src/checks.c
|
@ -865,6 +865,7 @@ static int event_srv_chk_r(int fd)
|
||||||
struct task *t = fdtab[fd].owner;
|
struct task *t = fdtab[fd].owner;
|
||||||
struct server *s = t->context;
|
struct server *s = t->context;
|
||||||
char *desc;
|
char *desc;
|
||||||
|
int done;
|
||||||
|
|
||||||
if (unlikely((s->result & SRV_CHK_ERROR) || (fdtab[fd].state == FD_STERROR))) {
|
if (unlikely((s->result & SRV_CHK_ERROR) || (fdtab[fd].state == FD_STERROR))) {
|
||||||
/* in case of TCP only, this tells us if the connection failed */
|
/* in case of TCP only, this tells us if the connection failed */
|
||||||
|
@ -884,24 +885,22 @@ static int event_srv_chk_r(int fd)
|
||||||
* with running the checks without attempting another socket read.
|
* with running the checks without attempting another socket read.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
done = 0;
|
||||||
for (len = 0; s->check_data_len < BUFSIZE; s->check_data_len += len) {
|
for (len = 0; s->check_data_len < BUFSIZE; s->check_data_len += len) {
|
||||||
len = recv(fd, s->check_data + s->check_data_len, BUFSIZE - s->check_data_len, 0);
|
len = recv(fd, s->check_data + s->check_data_len, BUFSIZE - s->check_data_len, 0);
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < 0) { /* recv returned an error */
|
if (len == 0)
|
||||||
if (errno == EAGAIN) {
|
done = 1; /* connection hangup received */
|
||||||
/* not ready, we want to poll first */
|
else if (len < 0 && errno != EAGAIN) {
|
||||||
fdtab[fd].ev &= ~FD_POLL_IN;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Report network errors only if we got no other data. Otherwise
|
/* Report network errors only if we got no other data. Otherwise
|
||||||
* we'll let the upper layers decide whether the response is OK
|
* we'll let the upper layers decide whether the response is OK
|
||||||
* or not. It is very common that an RST sent by the server is
|
* or not. It is very common that an RST sent by the server is
|
||||||
* reported as an error just after the last data chunk.
|
* reported as an error just after the last data chunk.
|
||||||
*/
|
*/
|
||||||
|
done = 1;
|
||||||
if (!s->check_data_len) {
|
if (!s->check_data_len) {
|
||||||
if (!(s->result & SRV_CHK_ERROR))
|
if (!(s->result & SRV_CHK_ERROR))
|
||||||
set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL);
|
set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL);
|
||||||
|
@ -909,18 +908,21 @@ static int event_srv_chk_r(int fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Full response received.
|
/* Intermediate or complete response received.
|
||||||
* Terminate string in check_data buffer... */
|
* Terminate string in check_data buffer.
|
||||||
|
*/
|
||||||
if (s->check_data_len < BUFSIZE)
|
if (s->check_data_len < BUFSIZE)
|
||||||
s->check_data[s->check_data_len] = '\0';
|
s->check_data[s->check_data_len] = '\0';
|
||||||
else
|
else {
|
||||||
s->check_data[s->check_data_len - 1] = '\0';
|
s->check_data[s->check_data_len - 1] = '\0';
|
||||||
|
done = 1; /* buffer full, don't wait for more data */
|
||||||
/* Close the connection... */
|
}
|
||||||
shutdown(fd, SHUT_RDWR);
|
|
||||||
|
|
||||||
/* Run the checks... */
|
/* Run the checks... */
|
||||||
if (s->proxy->options & PR_O_HTTP_CHK) {
|
if (s->proxy->options & PR_O_HTTP_CHK) {
|
||||||
|
if (!done && s->check_data_len < strlen("HTTP/1.0 000\r"))
|
||||||
|
goto wait_more_data;
|
||||||
|
|
||||||
/* Check if the server speaks HTTP 1.X */
|
/* Check if the server speaks HTTP 1.X */
|
||||||
if ((s->check_data_len < strlen("HTTP/1.0 000\r")) ||
|
if ((s->check_data_len < strlen("HTTP/1.0 000\r")) ||
|
||||||
(memcmp(s->check_data, "HTTP/1.", 7) != 0 ||
|
(memcmp(s->check_data, "HTTP/1.", 7) != 0 ||
|
||||||
|
@ -955,6 +957,9 @@ static int event_srv_chk_r(int fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (s->proxy->options & PR_O_SSL3_CHK) {
|
else if (s->proxy->options & PR_O_SSL3_CHK) {
|
||||||
|
if (!done && s->check_data_len < 5)
|
||||||
|
goto wait_more_data;
|
||||||
|
|
||||||
/* Check for SSLv3 alert or handshake */
|
/* Check for SSLv3 alert or handshake */
|
||||||
if ((s->check_data_len >= 5) && (*s->check_data == 0x15 || *s->check_data == 0x16))
|
if ((s->check_data_len >= 5) && (*s->check_data == 0x15 || *s->check_data == 0x16))
|
||||||
set_server_check_status(s, HCHK_STATUS_L6OK, NULL);
|
set_server_check_status(s, HCHK_STATUS_L6OK, NULL);
|
||||||
|
@ -962,6 +967,9 @@ static int event_srv_chk_r(int fd)
|
||||||
set_server_check_status(s, HCHK_STATUS_L6RSP, NULL);
|
set_server_check_status(s, HCHK_STATUS_L6RSP, NULL);
|
||||||
}
|
}
|
||||||
else if (s->proxy->options & PR_O_SMTP_CHK) {
|
else if (s->proxy->options & PR_O_SMTP_CHK) {
|
||||||
|
if (!done && s->check_data_len < strlen("000\r"))
|
||||||
|
goto wait_more_data;
|
||||||
|
|
||||||
/* Check if the server speaks SMTP */
|
/* Check if the server speaks SMTP */
|
||||||
if ((s->check_data_len < strlen("000\r")) ||
|
if ((s->check_data_len < strlen("000\r")) ||
|
||||||
(*(s->check_data + 3) != ' ' && *(s->check_data + 3) != '\r') ||
|
(*(s->check_data + 3) != ' ' && *(s->check_data + 3) != '\r') ||
|
||||||
|
@ -987,6 +995,9 @@ static int event_srv_chk_r(int fd)
|
||||||
else if (s->proxy->options2 & PR_O2_MYSQL_CHK) {
|
else if (s->proxy->options2 & PR_O2_MYSQL_CHK) {
|
||||||
/* MySQL Error packet always begin with field_count = 0xff
|
/* MySQL Error packet always begin with field_count = 0xff
|
||||||
* contrary to OK Packet who always begin whith 0x00 */
|
* contrary to OK Packet who always begin whith 0x00 */
|
||||||
|
if (!done && s->check_data_len < 5)
|
||||||
|
goto wait_more_data;
|
||||||
|
|
||||||
if (*(s->check_data + 4) != '\xff') {
|
if (*(s->check_data + 4) != '\xff') {
|
||||||
/* We set the MySQL Version in description for information purpose
|
/* We set the MySQL Version in description for information purpose
|
||||||
* FIXME : it can be cool to use MySQL Version for other purpose,
|
* FIXME : it can be cool to use MySQL Version for other purpose,
|
||||||
|
@ -997,6 +1008,8 @@ static int event_srv_chk_r(int fd)
|
||||||
set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
|
set_server_check_status(s, HCHK_STATUS_L7OKD, desc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (!done)
|
||||||
|
goto wait_more_data;
|
||||||
/* it seems we have a OK packet but without a valid length,
|
/* it seems we have a OK packet but without a valid length,
|
||||||
* it must be a protocol error
|
* it must be a protocol error
|
||||||
*/
|
*/
|
||||||
|
@ -1024,10 +1037,16 @@ static int event_srv_chk_r(int fd)
|
||||||
*s->check_data = '\0';
|
*s->check_data = '\0';
|
||||||
s->check_data_len = 0;
|
s->check_data_len = 0;
|
||||||
|
|
||||||
|
/* Close the connection... */
|
||||||
|
shutdown(fd, SHUT_RDWR);
|
||||||
EV_FD_CLR(fd, DIR_RD);
|
EV_FD_CLR(fd, DIR_RD);
|
||||||
task_wakeup(t, TASK_WOKEN_IO);
|
task_wakeup(t, TASK_WOKEN_IO);
|
||||||
fdtab[fd].ev &= ~FD_POLL_IN;
|
fdtab[fd].ev &= ~FD_POLL_IN;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
wait_more_data:
|
||||||
|
fdtab[fd].ev &= ~FD_POLL_IN;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue