httpd: stop reading headers using 1-byte read()
get_line 73 105 +32 httpd_main 769 766 -3 send_cgi_and_exit 1583 1577 -6 send_headers 449 432 -17 handle_incoming_and_exit 2217 2172 -45 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/4 up/down: 32/-71) Total: -39 bytes
This commit is contained in:
parent
367960ba9a
commit
d6cd9d7fe9
@ -131,11 +131,12 @@ typedef struct Htaccess_IP {
|
|||||||
} Htaccess_IP;
|
} Htaccess_IP;
|
||||||
|
|
||||||
struct globals {
|
struct globals {
|
||||||
int verbose;
|
int verbose; /* must be int (used by getopt32) */
|
||||||
smallint flg_deny_all;
|
smallint flg_deny_all;
|
||||||
|
|
||||||
unsigned rmt_ip;
|
unsigned rmt_ip;
|
||||||
unsigned rmt_port; /* for set env REMOTE_PORT */
|
unsigned rmt_port; /* for set env REMOTE_PORT */
|
||||||
|
char *rmt_ip_str; /* for set env REMOTE_ADDR */
|
||||||
const char *bind_addr_or_port;
|
const char *bind_addr_or_port;
|
||||||
|
|
||||||
const char *g_query;
|
const char *g_query;
|
||||||
@ -145,26 +146,27 @@ struct globals {
|
|||||||
const char *found_mime_type;
|
const char *found_mime_type;
|
||||||
const char *found_moved_temporarily;
|
const char *found_moved_temporarily;
|
||||||
time_t last_mod;
|
time_t last_mod;
|
||||||
off_t ContentLength; /* -1 - unknown */
|
off_t ContentLength; /* -1 - unknown */
|
||||||
Htaccess_IP *ip_a_d; /* config allow/deny lines */
|
Htaccess_IP *ip_a_d; /* config allow/deny lines */
|
||||||
|
|
||||||
USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
|
USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
|
||||||
USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
|
USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
|
||||||
USE_FEATURE_HTTPD_CGI(char *referer;)
|
USE_FEATURE_HTTPD_CGI(char *referer;)
|
||||||
USE_FEATURE_HTTPD_CGI(char *user_agent;)
|
USE_FEATURE_HTTPD_CGI(char *user_agent;)
|
||||||
|
|
||||||
char *rmt_ip_str; /* for set env REMOTE_ADDR */
|
|
||||||
|
|
||||||
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
|
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
|
||||||
Htaccess *g_auth; /* config user:password lines */
|
Htaccess *g_auth; /* config user:password lines */
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
|
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
|
||||||
Htaccess *mime_a; /* config mime types */
|
Htaccess *mime_a; /* config mime types */
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
|
#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
|
||||||
Htaccess *script_i; /* config script interpreters */
|
Htaccess *script_i; /* config script interpreters */
|
||||||
#endif
|
#endif
|
||||||
char iobuf[MAX_MEMORY_BUF];
|
char *iobuf; /* [MAX_MEMORY_BUF] */
|
||||||
|
#define hdr_buf bb_common_bufsiz1
|
||||||
|
char *hdr_ptr;
|
||||||
|
int hdr_cnt;
|
||||||
};
|
};
|
||||||
#define G (*ptr_to_globals)
|
#define G (*ptr_to_globals)
|
||||||
#define verbose (G.verbose )
|
#define verbose (G.verbose )
|
||||||
@ -189,6 +191,8 @@ struct globals {
|
|||||||
#define mime_a (G.mime_a )
|
#define mime_a (G.mime_a )
|
||||||
#define script_i (G.script_i )
|
#define script_i (G.script_i )
|
||||||
#define iobuf (G.iobuf )
|
#define iobuf (G.iobuf )
|
||||||
|
#define hdr_ptr (G.hdr_ptr )
|
||||||
|
#define hdr_cnt (G.hdr_cnt )
|
||||||
#define INIT_G() do { \
|
#define INIT_G() do { \
|
||||||
PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
|
PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
|
||||||
USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
|
USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
|
||||||
@ -196,6 +200,7 @@ struct globals {
|
|||||||
ContentLength = -1; \
|
ContentLength = -1; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HTTP_OK = 200,
|
HTTP_OK = 200,
|
||||||
HTTP_MOVED_TEMPORARILY = 302,
|
HTTP_MOVED_TEMPORARILY = 302,
|
||||||
@ -881,12 +886,21 @@ static void send_headers_and_exit(HttpResponseNum responseNum)
|
|||||||
static int get_line(void)
|
static int get_line(void)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
/* We must not read extra chars. Reading byte-by-byte... */
|
while (1) {
|
||||||
while (read(0, iobuf + count, 1) == 1) {
|
if (hdr_cnt <= 0) {
|
||||||
if (iobuf[count] == '\r')
|
hdr_cnt = safe_read(0, hdr_buf, sizeof(hdr_buf));
|
||||||
|
if (hdr_cnt <= 0)
|
||||||
|
break;
|
||||||
|
hdr_ptr = hdr_buf;
|
||||||
|
}
|
||||||
|
iobuf[count] = c = *hdr_ptr++;
|
||||||
|
hdr_cnt--;
|
||||||
|
|
||||||
|
if (c == '\r')
|
||||||
continue;
|
continue;
|
||||||
if (iobuf[count] == '\n') {
|
if (c == '\n') {
|
||||||
iobuf[count] = '\0';
|
iobuf[count] = '\0';
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -928,7 +942,6 @@ static void send_cgi_and_exit(
|
|||||||
char *fullpath;
|
char *fullpath;
|
||||||
char *script;
|
char *script;
|
||||||
char *purl;
|
char *purl;
|
||||||
size_t post_read_size, post_read_idx;
|
|
||||||
int buf_count;
|
int buf_count;
|
||||||
int status;
|
int status;
|
||||||
int pid = 0;
|
int pid = 0;
|
||||||
@ -1080,10 +1093,10 @@ static void send_cgi_and_exit(
|
|||||||
/* First, restore variables possibly changed by child */
|
/* First, restore variables possibly changed by child */
|
||||||
xfunc_error_retval = 0;
|
xfunc_error_retval = 0;
|
||||||
|
|
||||||
/* Prepare for pumping data */
|
/* Prepare for pumping data.
|
||||||
|
* iobuf is used for CGI -> network data,
|
||||||
|
* hdr_buf is for network -> CGI data (POSTDATA) */
|
||||||
buf_count = 0;
|
buf_count = 0;
|
||||||
post_read_size = 0;
|
|
||||||
post_read_idx = 0; /* for gcc */
|
|
||||||
close(fromCgi.wr);
|
close(fromCgi.wr);
|
||||||
close(toCgi.rd);
|
close(toCgi.rd);
|
||||||
|
|
||||||
@ -1091,25 +1104,25 @@ static void send_cgi_and_exit(
|
|||||||
* and send it to the peer. So please no SIGPIPEs! */
|
* and send it to the peer. So please no SIGPIPEs! */
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
/* This loop still looks messy. What is an exit criteria?
|
||||||
|
* "CGI's output closed"? Or "CGI has exited"?
|
||||||
|
* What to do if CGI has closed both input and output, but
|
||||||
|
* didn't exit? etc... */
|
||||||
|
|
||||||
|
/* NB: breaking out of this loop jumps to log_and_exit() */
|
||||||
while (1) {
|
while (1) {
|
||||||
fd_set readSet;
|
fd_set readSet;
|
||||||
fd_set writeSet;
|
fd_set writeSet;
|
||||||
char wbuf[128];
|
|
||||||
int nfound;
|
int nfound;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
/* This loop still looks messy. What is an exit criteria?
|
|
||||||
* "CGI's output closed"? Or "CGI has exited"?
|
|
||||||
* What to do if CGI has closed both input and output, but
|
|
||||||
* didn't exit? etc... */
|
|
||||||
|
|
||||||
FD_ZERO(&readSet);
|
FD_ZERO(&readSet);
|
||||||
FD_ZERO(&writeSet);
|
FD_ZERO(&writeSet);
|
||||||
FD_SET(fromCgi.rd, &readSet);
|
FD_SET(fromCgi.rd, &readSet);
|
||||||
if (bodyLen > 0 || post_read_size > 0) {
|
if (bodyLen > 0 || hdr_cnt > 0) {
|
||||||
FD_SET(toCgi.wr, &writeSet);
|
FD_SET(toCgi.wr, &writeSet);
|
||||||
nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd;
|
nfound = toCgi.wr > fromCgi.rd ? toCgi.wr : fromCgi.rd;
|
||||||
if (post_read_size == 0)
|
if (hdr_cnt <= 0)
|
||||||
FD_SET(0, &readSet);
|
FD_SET(0, &readSet);
|
||||||
/* Now wait on the set of sockets! */
|
/* Now wait on the set of sockets! */
|
||||||
nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL);
|
nfound = select(nfound + 1, &readSet, &writeSet, NULL, NULL);
|
||||||
@ -1135,30 +1148,30 @@ static void send_cgi_and_exit(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post_read_size > 0 && FD_ISSET(toCgi.wr, &writeSet)) {
|
if (hdr_cnt > 0 && FD_ISSET(toCgi.wr, &writeSet)) {
|
||||||
/* Have data from peer and can write to CGI */
|
/* Have data from peer and can write to CGI */
|
||||||
count = safe_write(toCgi.wr, wbuf + post_read_idx, post_read_size);
|
count = safe_write(toCgi.wr, hdr_ptr, hdr_cnt);
|
||||||
/* Doesn't happen, we dont use nonblocking IO here
|
/* Doesn't happen, we dont use nonblocking IO here
|
||||||
*if (count < 0 && errno == EAGAIN) {
|
*if (count < 0 && errno == EAGAIN) {
|
||||||
* ...
|
* ...
|
||||||
*} else */
|
*} else */
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
post_read_idx += count;
|
hdr_ptr += count;
|
||||||
post_read_size -= count;
|
hdr_cnt -= count;
|
||||||
} else {
|
} else {
|
||||||
post_read_size = bodyLen = 0; /* EOF/broken pipe to CGI */
|
hdr_cnt = bodyLen = 0; /* EOF/broken pipe to CGI */
|
||||||
}
|
}
|
||||||
} else if (bodyLen > 0 && post_read_size == 0
|
} else if (bodyLen > 0 && hdr_cnt == 0
|
||||||
&& FD_ISSET(0, &readSet)
|
&& FD_ISSET(0, &readSet)
|
||||||
) {
|
) {
|
||||||
/* We expect data, prev data portion is eaten by CGI
|
/* We expect data, prev data portion is eaten by CGI
|
||||||
* and there *is* data to read from the peer
|
* and there *is* data to read from the peer
|
||||||
* (POSTDATA?) */
|
* (POSTDATA?) */
|
||||||
count = bodyLen > (int)sizeof(wbuf) ? (int)sizeof(wbuf) : bodyLen;
|
count = bodyLen > (int)sizeof(hdr_buf) ? (int)sizeof(hdr_buf) : bodyLen;
|
||||||
count = safe_read(0, wbuf, count);
|
count = safe_read(0, hdr_buf, count);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
post_read_size = count;
|
hdr_cnt = count;
|
||||||
post_read_idx = 0;
|
hdr_ptr = hdr_buf;
|
||||||
bodyLen -= count;
|
bodyLen -= count;
|
||||||
} else {
|
} else {
|
||||||
bodyLen = 0; /* closed */
|
bodyLen = 0; /* closed */
|
||||||
@ -1195,7 +1208,7 @@ static void send_cgi_and_exit(
|
|||||||
full_write(1, HTTP_200, sizeof(HTTP_200)-1);
|
full_write(1, HTTP_200, sizeof(HTTP_200)-1);
|
||||||
full_write(1, rbuf, buf_count);
|
full_write(1, rbuf, buf_count);
|
||||||
}
|
}
|
||||||
break; /* closed */
|
break; /* CGI stdout is closed, exiting */
|
||||||
}
|
}
|
||||||
buf_count += count;
|
buf_count += count;
|
||||||
count = 0;
|
count = 0;
|
||||||
@ -1379,6 +1392,7 @@ static int checkPermIP(void)
|
|||||||
return !flg_deny_all;
|
return !flg_deny_all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
|
||||||
/*
|
/*
|
||||||
* Check the permission file for access password protected.
|
* Check the permission file for access password protected.
|
||||||
*
|
*
|
||||||
@ -1390,7 +1404,6 @@ static int checkPermIP(void)
|
|||||||
*
|
*
|
||||||
* Returns 1 if request is OK.
|
* Returns 1 if request is OK.
|
||||||
*/
|
*/
|
||||||
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
|
|
||||||
static int checkPerm(const char *path, const char *request)
|
static int checkPerm(const char *path, const char *request)
|
||||||
{
|
{
|
||||||
Htaccess *cur;
|
Htaccess *cur;
|
||||||
@ -1457,7 +1470,6 @@ static int checkPerm(const char *path, const char *request)
|
|||||||
|
|
||||||
return prev == NULL;
|
return prev == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* FEATURE_HTTPD_BASIC_AUTH */
|
#endif /* FEATURE_HTTPD_BASIC_AUTH */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1495,6 +1507,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
|
|||||||
int credentials = -1; /* if not required this is Ok */
|
int credentials = -1; /* if not required this is Ok */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Allocation of iobuf is postponed until now
|
||||||
|
* (IOW, server process doesn't need to waste 8k) */
|
||||||
|
iobuf = xmalloc(MAX_MEMORY_BUF);
|
||||||
|
|
||||||
rmt_port = get_nport(&fromAddr->sa);
|
rmt_port = get_nport(&fromAddr->sa);
|
||||||
rmt_port = ntohs(rmt_port);
|
rmt_port = ntohs(rmt_port);
|
||||||
rmt_ip = 0;
|
rmt_ip = 0;
|
||||||
@ -1731,6 +1747,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
|
|||||||
send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
|
send_headers_and_exit(HTTP_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
#endif /* FEATURE_HTTPD_CGI */
|
#endif /* FEATURE_HTTPD_CGI */
|
||||||
|
|
||||||
if (purl[-1] == '/')
|
if (purl[-1] == '/')
|
||||||
strcpy(purl, "index.html");
|
strcpy(purl, "index.html");
|
||||||
if (stat(test, &sb) == 0) {
|
if (stat(test, &sb) == 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user