[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 server *s = t->context;
|
||||
char *desc;
|
||||
int done;
|
||||
|
||||
if (unlikely((s->result & SRV_CHK_ERROR) || (fdtab[fd].state == FD_STERROR))) {
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
done = 0;
|
||||
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);
|
||||
if (len <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (len < 0) { /* recv returned an error */
|
||||
if (errno == EAGAIN) {
|
||||
/* not ready, we want to poll first */
|
||||
fdtab[fd].ev &= ~FD_POLL_IN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
done = 1; /* connection hangup received */
|
||||
else if (len < 0 && errno != EAGAIN) {
|
||||
/* Report network errors only if we got no other data. Otherwise
|
||||
* 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
|
||||
* reported as an error just after the last data chunk.
|
||||
*/
|
||||
done = 1;
|
||||
if (!s->check_data_len) {
|
||||
if (!(s->result & SRV_CHK_ERROR))
|
||||
set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL);
|
||||
|
@ -909,18 +908,21 @@ static int event_srv_chk_r(int fd)
|
|||
}
|
||||
}
|
||||
|
||||
/* Full response received.
|
||||
* Terminate string in check_data buffer... */
|
||||
/* Intermediate or complete response received.
|
||||
* Terminate string in check_data buffer.
|
||||
*/
|
||||
if (s->check_data_len < BUFSIZE)
|
||||
s->check_data[s->check_data_len] = '\0';
|
||||
else
|
||||
else {
|
||||
s->check_data[s->check_data_len - 1] = '\0';
|
||||
|
||||
/* Close the connection... */
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
done = 1; /* buffer full, don't wait for more data */
|
||||
}
|
||||
|
||||
/* Run the checks... */
|
||||
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 */
|
||||
if ((s->check_data_len < strlen("HTTP/1.0 000\r")) ||
|
||||
(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) {
|
||||
if (!done && s->check_data_len < 5)
|
||||
goto wait_more_data;
|
||||
|
||||
/* Check for SSLv3 alert or handshake */
|
||||
if ((s->check_data_len >= 5) && (*s->check_data == 0x15 || *s->check_data == 0x16))
|
||||
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);
|
||||
}
|
||||
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 */
|
||||
if ((s->check_data_len < strlen("000\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) {
|
||||
/* MySQL Error packet always begin with field_count = 0xff
|
||||
* 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') {
|
||||
/* We set the MySQL Version in description for information 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);
|
||||
}
|
||||
else {
|
||||
if (!done)
|
||||
goto wait_more_data;
|
||||
/* it seems we have a OK packet but without a valid length,
|
||||
* 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_len = 0;
|
||||
|
||||
/* Close the connection... */
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
EV_FD_CLR(fd, DIR_RD);
|
||||
task_wakeup(t, TASK_WOKEN_IO);
|
||||
fdtab[fd].ev &= ~FD_POLL_IN;
|
||||
return 1;
|
||||
|
||||
wait_more_data:
|
||||
fdtab[fd].ev &= ~FD_POLL_IN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue