diff options
author | Christian Grothoff <christian@grothoff.org> | 2007-06-13 21:57:36 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2007-06-13 21:57:36 +0000 |
commit | 817a963a53ce67d3efbcf223df0bbe35299dc38e (patch) | |
tree | e2d4dd680d13980efde175b50c81c354dfaf2c87 | |
parent | b0912d1929accce21b75c97ab69c4c499ca9e921 (diff) |
essentials implemented
-rw-r--r-- | README | 12 | ||||
-rw-r--r-- | src/daemon/daemon.c | 21 | ||||
-rw-r--r-- | src/daemon/session.c | 132 | ||||
-rw-r--r-- | src/daemon/session.h | 7 |
4 files changed, 117 insertions, 55 deletions
@@ -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 |