summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2007-06-13 21:57:36 +0000
committerChristian Grothoff <christian@grothoff.org>2007-06-13 21:57:36 +0000
commit817a963a53ce67d3efbcf223df0bbe35299dc38e (patch)
treee2d4dd680d13980efde175b50c81c354dfaf2c87
parentb0912d1929accce21b75c97ab69c4c499ca9e921 (diff)
essentials implemented
-rw-r--r--README12
-rw-r--r--src/daemon/daemon.c21
-rw-r--r--src/daemon/session.c132
-rw-r--r--src/daemon/session.h7
4 files changed, 117 insertions, 55 deletions
diff --git a/README b/README
index 70219998..ab45ad10 100644
--- a/README
+++ b/README
@@ -5,11 +5,6 @@ things need to be implemented (in list of importance)
before certain features can be used at all:
-For ANYTHING:
-=============
-session.c:
-- MHD_session_get_fdset (essentially not implemented)
-
For GET args:
=============
session.c:
@@ -26,6 +21,13 @@ For COOKIES:
session.c:
- MHD_parse_session_headers: take cookie header apart
+For http-compliance:
+====================
+session.c:
+- send proper error code back if headers are too long
+ (investigate what we should do with those headers,
+ read? give user control?)
+
For IPv6:
=========
daemon.c:
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index 2a2636db..490317ea 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -163,7 +163,8 @@ MHD_handle_connection(void * data) {
if (con == NULL)
abort();
- while (! con->daemon->shutdown) {
+ while ( (! con->daemon->shutdown) &&
+ (con->socket_fd != -1) ) {
FD_ZERO(&rs);
FD_ZERO(&ws);
FD_ZERO(&es);
@@ -189,8 +190,10 @@ MHD_handle_connection(void * data) {
(MHD_YES != MHD_session_handle_write(con)) ) )
break;
}
- close(con->socket_fd);
- con->socket_fd = -1;
+ if (con->socket_fd != -1) {
+ close(con->socket_fd);
+ con->socket_fd = -1;
+ }
return NULL;
}
@@ -260,6 +263,11 @@ MHD_accept_connection(struct MHD_Daemon * daemon) {
* Free resources associated with all closed sessions.
* (destroy responses, free buffers, etc.). A session
* is known to be closed if the socket_fd is -1.
+ *
+ * Also performs session actions that need to be run
+ * even if the session is not selectable (such as
+ * calling the application again with upload data when
+ * the upload data buffer is full).
*/
static void
MHD_cleanup_sessions(struct MHD_Daemon * daemon) {
@@ -295,6 +303,13 @@ MHD_cleanup_sessions(struct MHD_Daemon * daemon) {
MHD_destroy_response(pos->response);
free(pos);
}
+
+ if ( (pos->headersReceived == 1) &&
+ (pos->read_buffer_size == pos->readLoc) &&
+ (pos->readLoc > 0) )
+ MHD_call_session_handler(pos);
+
+
prev = pos;
pos = pos->next;
}
diff --git a/src/daemon/session.c b/src/daemon/session.c
index fc713137..ed1b6b88 100644
--- a/src/daemon/session.c
+++ b/src/daemon/session.c
@@ -109,7 +109,9 @@ MHD_queue_response(struct MHD_Session * session,
struct MHD_Response * response) {
if ( (session == NULL) ||
(response == NULL) ||
- (session->response != NULL) )
+ (session->response != NULL) ||
+ (session->bodyReceived == 0) ||
+ (session->headers_received == 0) )
return MHD_NO;
MHD_increment_response_rc(response);
session->response = response;
@@ -129,13 +131,15 @@ MHD_session_get_fdset(struct MHD_Session * session,
fd_set * write_fd_set,
fd_set * except_fd_set,
int * max_fd) {
- /* FIXME: need to be VERY careful here
- determining when the socket is ready for
- reading/writing; plenty of cases to handle!
- (the current code is one big bug) */
- FD_SET(session->socket_fd, read_fd_set);
- FD_SET(session->socket_fd, write_fd_set);
- if (session->socket_fd > *max_fd)
+ if ( (session->headers_received == 0) ||
+ (session->readLoc < session->read_buffer_size) )
+ FD_SET(session->socket_fd, read_fd_set);
+ if (session->response != NULL)
+ FD_SET(session->socket_fd, write_fd_set);
+ if ( (session->socket_fd > *max_fd) &&
+ ( (session->headers_received == 0) ||
+ (session->readLoc < session->read_buffer_size) ||
+ (session->response != NULL) ) )
*max_fd = session->socket_fd;
return MHD_YES;
}
@@ -233,6 +237,7 @@ MHD_parse_session_headers(struct MHD_Session * session) {
httpType = strstr(uri, " ");
if (httpType != NULL)
httpType[0] = '\0';
+ /* FIXME: parse URI some more here */
session->url = strdup(uri);
/* do we want to do anything with httpType? */
free(line);
@@ -267,9 +272,9 @@ MHD_parse_session_headers(struct MHD_Session * session) {
hdr->kind = MHD_HEADER_KIND;
session->headers_received = hdr;
}
+ /* FIXME: here: find cookie header and parse that! */
if (session->bodyReceived == 0)
return;
- /* FIXME: here: find cookie header and parse that! */
return;
DIE:
close(session->socket_fd);
@@ -295,6 +300,48 @@ MHD_find_access_handler(struct MHD_Session * session) {
}
/**
+ * Call the handler of the application for this
+ * session.
+ */
+void
+MHD_call_session_handler(struct MHD_Session * session) {
+ struct MHD_Access_Handler * ah;
+ unsigned int processed;
+
+ if (session->headers_received == 0)
+ abort(); /* bad timing... */
+ ah = MHD_find_access_handler(session);
+ processed = session->readLoc;
+ if (MHD_NO == ah->dh(ah->dh_cls,
+ session,
+ session->url,
+ session->method,
+ session->read_buffer,
+ &processed)) {
+ /* serios internal error, close connection */
+ MHD_DLOG(session->daemon,
+ "Internal application error, closing connection.");
+ close(session->socket_fd);
+ session->socket_fd = -1;
+ return;
+ }
+ /* dh left "processed" bytes in buffer for next time... */
+ memmove(session->read_buffer,
+ &session->read_buffer[session->readLoc - processed],
+ processed);
+ session->readLoc = processed;
+ session->uploadSize -= processed;
+ if (session->uploadSize == 0) {
+ session->bodyReceived = 1;
+ session->readLoc = 0;
+ session->read_buffer_size = 0;
+ free(session->read_buffer);
+ session->read_buffer = NULL;
+ }
+}
+
+
+/**
* This function handles a particular connection when it has been
* determined that there is data to be read off a socket. All implementations
* (multithreaded, external select, internal select) call this function
@@ -304,16 +351,10 @@ int
MHD_session_handle_read(struct MHD_Session * session) {
int bytes_read;
void * tmp;
- struct MHD_Access_Handler * ah;
- unsigned int processed;
+
- if (session->bodyReceived) {
- MHD_DLOG(session->daemon,
- "Unexpected call to %s.\n",
- __FUNCTION__);
- return MHD_NO;
- }
- if (session->readLoc >= session->read_buffer_size) {
+ if ( (session->readLoc >= session->read_buffer_size) &&
+ (session->headers_received == 0) ) {
/* need to grow read buffer */
tmp = malloc(session->read_buffer_size * 2 + MHD_MAX_BUF_SIZE);
memcpy(tmp,
@@ -321,6 +362,12 @@ MHD_session_handle_read(struct MHD_Session * session) {
session->read_buffer_size);
session->read_buffer_size = session->read_buffer_size * 2 + MHD_MAX_BUF_SIZE;
}
+ if (session->readLoc >= session->read_buffer_size) {
+ MHD_DLOG(session->daemon,
+ "Unexpected call to %s.\n",
+ __FUNCTION__);
+ return MHD_NO;
+ }
bytes_read = recv(session->socket_fd,
&session->read_buffer[session->readLoc],
session->read_buffer_size - session->readLoc,
@@ -331,39 +378,24 @@ MHD_session_handle_read(struct MHD_Session * session) {
MHD_DLOG(session->daemon,
"Failed to receive data: %s\n",
strerror(errno));
- return MHD_NO;
+ close(session->socket_fd);
+ session->socket_fd = -1;
+ return MHD_YES;
}
if (bytes_read == 0) {
/* other side closed connection */
+ /* FIXME: proper handling of end of upload!
+ If we were receiving an unbounded upload,
+ we should finish up nicely now! */
close(session->socket_fd);
session->socket_fd = -1;
- return MHD_NO;
+ return MHD_YES;
}
session->readLoc += bytes_read;
if (session->headersReceived == 0)
MHD_parse_session_headers(session);
- if (session->headersReceived == 1) {
- ah = MHD_find_access_handler(session);
- processed = session->readLoc;
- if (MHD_NO == ah->dh(ah->dh_cls,
- session,
- session->url,
- session->method,
- session->read_buffer,
- &processed)) {
- /* serios error, close connection */
- close(session->socket_fd);
- session->socket_fd = -1;
- return MHD_NO;
- }
- /* dh left "processed" bytes in buffer for next time... */
- memmove(session->read_buffer,
- &session->read_buffer[session->readLoc - processed],
- processed);
- session->readLoc = processed;
- session->uploadSize -= processed;
- /* FIXME: proper handling of end of upload! */
- }
+ if (session->headersReceived == 1)
+ MHD_call_session_handler(session);
return MHD_YES;
}
@@ -447,7 +479,7 @@ MHD_session_handle_write(struct MHD_Session * session) {
strerror(errno));
close(session->socket_fd);
session->socket_fd = -1;
- return MHD_NO;
+ return MHD_YES;
}
session->writeLoc += ret;
if (session->writeLoc == session->write_buffer_size) {
@@ -489,7 +521,7 @@ MHD_session_handle_write(struct MHD_Session * session) {
response->data_start = session->messagePos;
response->data_size = ret;
if (ret == 0)
- return MHD_YES; /* or NO? */
+ return MHD_YES;
}
/* transmit */
@@ -499,17 +531,23 @@ MHD_session_handle_write(struct MHD_Session * session) {
0);
if (response->crc != NULL)
pthread_mutex_unlock(&response->mutex);
- if (ret == -1) {
+ if (ret < 0) {
if (errno == EINTR)
return MHD_YES;
MHD_DLOG(session->daemon,
"Failed to send data: %s\n",
strerror(errno));
- return MHD_NO;
+ close(session->socket_fd);
+ session->socket_fd = -1;
+ return MHD_YES;
}
session->messagePos += ret;
+ if (session->messagePos > response->data_size)
+ abort(); /* internal error */
if (session->messagePos == response->data_size) {
- /* reset session, wait for next request! */
+ if ( (session->bodyReceived == 0) ||
+ (session->headers_received == 0) )
+ abort(); /* internal error */
MHD_destroy_response(response);
session->responseCode = 0;
session->response = NULL;
diff --git a/src/daemon/session.h b/src/daemon/session.h
index 0097a398..bf072901 100644
--- a/src/daemon/session.h
+++ b/src/daemon/session.h
@@ -44,6 +44,13 @@ MHD_session_get_fdset(struct MHD_Session * session,
/**
+ * Call the handler of the application for this
+ * session.
+ */
+void
+MHD_call_session_handler(struct MHD_Session * session);
+
+/**
* This function handles a particular connection when it has been
* determined that there is data to be read off a socket. All implementations
* (multithreaded, external select, internal select) call this function