mirror of
https://github.com/emikulic/darkhttpd.git
synced 2023-08-10 21:13:08 +03:00
. Added to struct connection:
o in_addr_t client o time last_active o {header,reply}_dont_free . Added IDLETIME and poll_check_timeout() . Added new_connection() and moved conn initialisation there . Added default_reply() . Skeleton for process_request() . connnection.request is now null-terminated . Removed debug code from poll_recv_request()
This commit is contained in:
parent
ebe1e1bfa0
commit
23b191239e
@ -16,6 +16,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* for easy defusal */
|
/* for easy defusal */
|
||||||
@ -29,6 +30,8 @@ struct connection
|
|||||||
LIST_ENTRY(connection) entries;
|
LIST_ENTRY(connection) entries;
|
||||||
|
|
||||||
int socket;
|
int socket;
|
||||||
|
in_addr_t client;
|
||||||
|
time_t last_active;
|
||||||
enum {
|
enum {
|
||||||
RECV_REQUEST, /* receiving request */
|
RECV_REQUEST, /* receiving request */
|
||||||
SEND_HEADER, /* sending generated header */
|
SEND_HEADER, /* sending generated header */
|
||||||
@ -36,29 +39,35 @@ struct connection
|
|||||||
DONE /* connection closed, need to remove from queue */
|
DONE /* connection closed, need to remove from queue */
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
|
/* char request[request_length+1] is null-terminated */
|
||||||
char *request;
|
char *request;
|
||||||
unsigned int request_length;
|
unsigned int request_length;
|
||||||
|
|
||||||
char *header;
|
char *header;
|
||||||
unsigned int header_sent, header_length;
|
unsigned int header_sent, header_length;
|
||||||
|
int header_dont_free;
|
||||||
|
|
||||||
enum { REPLY_GENERATED, REPLY_FROMFILE } reply_type;
|
enum { REPLY_GENERATED, REPLY_FROMFILE } reply_type;
|
||||||
char *reply;
|
char *reply;
|
||||||
|
int reply_dont_free;
|
||||||
FILE *reply_file;
|
FILE *reply_file;
|
||||||
unsigned int reply_sent, reply_length;
|
unsigned int reply_sent, reply_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* defaults can be overridden on the command-line */
|
/* If a connection is idle for IDLETIME seconds or more, it gets closed and
|
||||||
|
* removed from the connlist.
|
||||||
|
*/
|
||||||
|
#define IDLETIME 60
|
||||||
|
|
||||||
|
/* Defaults can be overridden on the command-line */
|
||||||
static in_addr_t bindaddr = INADDR_ANY;
|
static in_addr_t bindaddr = INADDR_ANY;
|
||||||
static u_int16_t bindport = 80;
|
static u_int16_t bindport = 80;
|
||||||
static int max_connections = -1; /* kern.ipc.somaxconn */
|
static int max_connections = -1; /* kern.ipc.somaxconn */
|
||||||
|
|
||||||
static int sockin; /* socket to accept connections from */
|
static int sockin; /* socket to accept connections from */
|
||||||
/*@null@*/
|
|
||||||
static char *wwwroot = NULL; /* a path name */
|
static char *wwwroot = NULL; /* a path name */
|
||||||
/*@null@*/
|
|
||||||
static char *logfile_name = NULL; /* NULL = no logging */
|
static char *logfile_name = NULL; /* NULL = no logging */
|
||||||
static int want_chroot = 0;
|
static int want_chroot = 0;
|
||||||
|
|
||||||
@ -189,6 +198,36 @@ static void *xmalloc(const size_t size)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* Allocate and initialize an empty connection.
|
||||||
|
*/
|
||||||
|
static struct connection *new_connection(void)
|
||||||
|
{
|
||||||
|
struct connection *conn = (struct connection *)
|
||||||
|
xmalloc(sizeof(struct connection));
|
||||||
|
|
||||||
|
conn->socket = -1;
|
||||||
|
conn->client = INADDR_ANY;
|
||||||
|
conn->last_active = time(NULL);
|
||||||
|
conn->request = NULL;
|
||||||
|
conn->request_length = 0;
|
||||||
|
conn->header = NULL;
|
||||||
|
conn->header_dont_free = 0; /* you'll want to, later */
|
||||||
|
conn->header_sent = conn->header_length = 0;
|
||||||
|
conn->reply = NULL;
|
||||||
|
conn->reply_dont_free = 0; /* you'll want to, later */
|
||||||
|
conn->reply_file = NULL;
|
||||||
|
|
||||||
|
/* Make it harmless so it gets garbage-collected if it should, for some
|
||||||
|
* reason, fail to be correctly filled out.
|
||||||
|
*/
|
||||||
|
conn->state = DONE;
|
||||||
|
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Accept a connection from sockin and add it to the connection queue.
|
* Accept a connection from sockin and add it to the connection queue.
|
||||||
*/
|
*/
|
||||||
@ -199,14 +238,7 @@ static void accept_connection(void)
|
|||||||
struct connection *conn;
|
struct connection *conn;
|
||||||
|
|
||||||
/* allocate and initialise struct connection */
|
/* allocate and initialise struct connection */
|
||||||
conn = (struct connection *)xmalloc(sizeof(struct connection));
|
conn = new_connection();
|
||||||
conn->socket = -1;
|
|
||||||
conn->request = NULL;
|
|
||||||
conn->request_length = 0;
|
|
||||||
conn->header = NULL;
|
|
||||||
conn->header_sent = conn->header_length = 0;
|
|
||||||
conn->reply = NULL;
|
|
||||||
conn->reply_file = NULL;
|
|
||||||
|
|
||||||
sin_size = (socklen_t)sizeof(struct sockaddr);
|
sin_size = (socklen_t)sizeof(struct sockaddr);
|
||||||
conn->socket = accept(sockin, (struct sockaddr *)&addrin,
|
conn->socket = accept(sockin, (struct sockaddr *)&addrin,
|
||||||
@ -214,6 +246,7 @@ static void accept_connection(void)
|
|||||||
if (conn->socket == -1) err(1, "accept()");
|
if (conn->socket == -1) err(1, "accept()");
|
||||||
|
|
||||||
conn->state = RECV_REQUEST;
|
conn->state = RECV_REQUEST;
|
||||||
|
conn->client = addrin.sin_addr.s_addr;
|
||||||
LIST_INSERT_HEAD(&connlist, conn, entries);
|
LIST_INSERT_HEAD(&connlist, conn, entries);
|
||||||
|
|
||||||
debugf("accepted connection from %s:%u\n",
|
debugf("accepted connection from %s:%u\n",
|
||||||
@ -230,8 +263,8 @@ static void free_connection(struct connection *conn)
|
|||||||
{
|
{
|
||||||
if (conn->socket != -1) close(conn->socket);
|
if (conn->socket != -1) close(conn->socket);
|
||||||
if (conn->request != NULL) free(conn->request);
|
if (conn->request != NULL) free(conn->request);
|
||||||
if (conn->header != NULL) free(conn->header);
|
if (conn->header != NULL && !conn->header_dont_free) free(conn->header);
|
||||||
if (conn->reply != NULL) free(conn->reply);
|
if (conn->reply != NULL && !conn->reply_dont_free) free(conn->reply);
|
||||||
if (conn->reply_file != NULL) fclose(conn->reply_file);
|
if (conn->reply_file != NULL) fclose(conn->reply_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +281,65 @@ static void *xrealloc(void *original, const size_t size)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* If a connection has been idle for more than IDLETIME seconds, it will be
|
||||||
|
* marked as DONE and killed off in httpd_poll()
|
||||||
|
*/
|
||||||
|
static void poll_check_timeout(struct connection *conn)
|
||||||
|
{
|
||||||
|
if (time(NULL) - conn->last_active >= IDLETIME)
|
||||||
|
conn->state = DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* A default reply for any occasion.
|
||||||
|
*/
|
||||||
|
static void default_reply(struct connection *conn,
|
||||||
|
const int errcode, const char *errname)
|
||||||
|
{
|
||||||
|
conn->reply_length = asprintf(&(conn->reply),
|
||||||
|
"<html><head><title>%d %s</title></head><body>\n"
|
||||||
|
"<h1>%s</h1><hr>\n"
|
||||||
|
"%s\n"
|
||||||
|
"</body></html>\n",
|
||||||
|
errcode, errname, errname, pkgname);
|
||||||
|
|
||||||
|
if (conn->reply == NULL) errx(1, "out of memory in asprintf()");
|
||||||
|
|
||||||
|
conn->header_length = asprintf(&(conn->header),
|
||||||
|
"HTTP/1.1 %d %s\r\n"
|
||||||
|
/* FIXME: Date */
|
||||||
|
"Server: %s\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"\r\n",
|
||||||
|
errcode, errname, pkgname, conn->reply_length);
|
||||||
|
|
||||||
|
if (conn->header == NULL) errx(1, "out of memory in asprintf()");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* Process a request: build the header and reply, advance state.
|
||||||
|
*/
|
||||||
|
static void process_request(struct connection *conn)
|
||||||
|
{
|
||||||
|
debugf(conn->request);
|
||||||
|
|
||||||
|
default_reply(conn, 501, "Not Implemented");
|
||||||
|
conn->state = DONE; /* FIXME: SEND_HEADER */
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
debugf("%s%s---\n", conn->header, conn->reply);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Receiving request.
|
* Receiving request.
|
||||||
*/
|
*/
|
||||||
@ -265,22 +357,20 @@ static void poll_recv_request(struct connection *conn)
|
|||||||
conn->state = DONE;
|
conn->state = DONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
conn->last_active = time(NULL);
|
||||||
|
#undef BUFSIZE
|
||||||
|
|
||||||
/* append to conn->request */
|
/* append to conn->request */
|
||||||
conn->request = xrealloc(conn->request, conn->request_length + recvd);
|
conn->request = xrealloc(conn->request,
|
||||||
|
conn->request_length + recvd + 1);
|
||||||
memcpy(conn->request+conn->request_length, buf, recvd);
|
memcpy(conn->request+conn->request_length, buf, recvd);
|
||||||
conn->request_length += recvd;
|
conn->request_length += recvd;
|
||||||
|
conn->request[conn->request_length] = 0;
|
||||||
|
|
||||||
#if 1
|
/* process request if we have all of it */
|
||||||
{ int i;
|
if (conn->request_length > 4 &&
|
||||||
printf("recvd %d: ", recvd);
|
memcmp(conn->request+conn->request_length-4, "\r\n\r\n", 4) == 0)
|
||||||
for (i=0; i<recvd; i++) printf("%02x ",
|
process_request(conn);
|
||||||
conn->request[conn->request_length-recvd+i]);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef BUFSIZE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -314,25 +404,28 @@ static void httpd_poll(void)
|
|||||||
MAX_FD_SET(sockin, &recv_set);
|
MAX_FD_SET(sockin, &recv_set);
|
||||||
|
|
||||||
LIST_FOREACH(conn, &connlist, entries)
|
LIST_FOREACH(conn, &connlist, entries)
|
||||||
switch (conn->state)
|
|
||||||
{
|
{
|
||||||
case RECV_REQUEST:
|
poll_check_timeout(conn);
|
||||||
MAX_FD_SET(conn->socket, &recv_set);
|
switch (conn->state)
|
||||||
break;
|
{
|
||||||
|
case RECV_REQUEST:
|
||||||
|
MAX_FD_SET(conn->socket, &recv_set);
|
||||||
|
break;
|
||||||
|
|
||||||
case SEND_HEADER:
|
case SEND_HEADER:
|
||||||
case SEND_REPLY:
|
case SEND_REPLY:
|
||||||
MAX_FD_SET(conn->socket, &send_set);
|
MAX_FD_SET(conn->socket, &send_set);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DONE:
|
case DONE:
|
||||||
/* clean out stale connections while we're at it */
|
/* clean out stale connections while we're at it */
|
||||||
LIST_REMOVE(conn, entries);
|
LIST_REMOVE(conn, entries);
|
||||||
free_connection(conn);
|
free_connection(conn);
|
||||||
free(conn);
|
free(conn);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: errx(1, "invalid state");
|
default: errx(1, "invalid state");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#undef MAX_FD_SET
|
#undef MAX_FD_SET
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user