From c574ccf210d44ca814d632568c9036ab9933ddc5 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 15 Nov 2018 16:13:04 +0000 Subject: New upstream version 1.30 --- README | 8 +- contrib/redhat-rpm/mini_httpd.spec | 2 +- htpasswd.c | 3 +- mini_httpd.c | 166 +++++++++++++++++++++++++++++-------- scripts/mini_httpd.sh | 47 +++++------ version.h | 2 +- 6 files changed, 160 insertions(+), 68 deletions(-) diff --git a/README b/README index 3f152b4..c12ae95 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ mini_httpd - small HTTP server - version 1.23 of 28Dec2015 + version 1.30 of 26Oct2018 mini_httpd is a small HTTP server. Its performance is not great, but for low or medium traffic sites it's quite adequate. It implements all the @@ -48,9 +48,9 @@ If you're doing SSL, uncomment those lines too. Otherwise, just do a make. On Red Hat Linux systems you can use RPM to install mini_httpd, like so: cd /usr/src/redhat/SOURCES - wget http://www.acme.com/software/mini_httpd/mini_httpd-1.20.tar.gz - rpm -ta mini_httpd-1.20.tar.gz - rpm -i /usr/src/redhat/RPMS/i386/mini_httpd-1.20-1.i386.rpm + wget http://www.acme.com/software/mini_httpd/mini_httpd-1.30.tar.gz + rpm -ta mini_httpd-1.30.tar.gz + rpm -i /usr/src/redhat/RPMS/i386/mini_httpd-1.30-1.i386.rpm Feedback is welcome - send bug reports, enhancements, checks, money orders, etc. to the addresses below. diff --git a/contrib/redhat-rpm/mini_httpd.spec b/contrib/redhat-rpm/mini_httpd.spec index 2cab698..c1ad3e7 100644 --- a/contrib/redhat-rpm/mini_httpd.spec +++ b/contrib/redhat-rpm/mini_httpd.spec @@ -1,6 +1,6 @@ Summary: small, simple http daemon, supports SSL Name: mini_httpd -Version: 1.23 +Version: 1.30 Release: 1 Copyright: Freely Redistributable Packager: Bennett Todd diff --git a/htpasswd.c b/htpasswd.c index 8ffda29..31ac769 100644 --- a/htpasswd.c +++ b/htpasswd.c @@ -184,7 +184,8 @@ int main(int argc, char *argv[]) { fprintf(stderr,"Use -c option to create new one.\n"); exit(1); } - strcpy(user,argv[2]); + strncpy(user,argv[2],sizeof(user)-1); + user[sizeof(user)-1] = '\0'; found = 0; while(!(my_getline(line,MAX_STRING_LEN,f))) { diff --git a/mini_httpd.c b/mini_httpd.c index 4051625..ed963f0 100644 --- a/mini_httpd.c +++ b/mini_httpd.c @@ -163,6 +163,9 @@ typedef long long int64_t; #define METHOD_GET 1 #define METHOD_HEAD 2 #define METHOD_POST 3 +#define METHOD_PUT 4 +#define METHOD_DELETE 5 +#define METHOD_TRACE 6 /* A multi-family sockaddr. */ @@ -244,7 +247,8 @@ static void read_config( char* filename ); static void value_required( char* name, char* value ); static void no_value_required( char* name, char* value ); static int initialize_listen_socket( usockaddr* usaP ); -static void handle_request( void ); +static void handle_request( void ) __attribute__((noreturn)); +static void finish_request( int exitstatus ) __attribute__((noreturn)); static void de_dotdot( char* f ); static int get_pathinfo( void ); static void do_file( void ); @@ -269,7 +273,7 @@ static int send_error_file( char* filename ); static void send_error_tail( void ); static void add_headers( int s, char* title, char* extra_header, char* me, char* mt, off_t b, time_t mod ); static void start_request( void ); -static void add_to_request( char* str ); +static void add_to_request( char* str, size_t len ); static char* get_request_line( void ); static void start_response( void ); static void add_to_response( char* str ); @@ -279,9 +283,10 @@ static void send_via_sendfile( int fd, int s, off_t size ); static ssize_t my_read( char* buf, size_t size ); static ssize_t my_write( void* buf, size_t size ); #ifdef HAVE_SENDFILE -static int my_sendfile( int fd, int s, off_t offset, size_t nbytes ); +static ssize_t my_sendfile( int fd, int s, off_t offset, size_t nbytes ); #endif /* HAVE_SENDFILE */ static void add_str( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str ); +static void add_data( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str, size_t len ); static void make_log_entry( void ); static void check_referrer( void ); static int really_check_referrer( void ); @@ -553,9 +558,10 @@ main( int argc, char** argv ) SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); ssl_ctx = SSL_CTX_new( SSLv23_server_method() ); - SSL_CTX_set_options( ssl_ctx, SSL_OP_NO_SSLv3 ); + SSL_CTX_set_options( ssl_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3 ); if ( certfile[0] != '\0' ) if ( SSL_CTX_use_certificate_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || + SSL_CTX_use_certificate_chain_file( ssl_ctx, certfile ) == 0 || SSL_CTX_use_PrivateKey_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 || SSL_CTX_check_private_key( ssl_ctx ) == 0 ) { @@ -857,7 +863,6 @@ main( int argc, char** argv ) if ( listen6_fd != -1 ) (void) close( listen6_fd ); handle_request(); - exit( 0 ); } (void) close( conn_fd ); } @@ -1196,7 +1201,7 @@ handle_request( void ) if ( SSL_accept( ssl ) == 0 ) { ERR_print_errors_fp( stderr ); - exit( 1 ); + finish_request( 1 ); } } #endif /* USE_SSL */ @@ -1205,15 +1210,14 @@ handle_request( void ) start_request(); for (;;) { - char buf[10000]; + char buf[50000]; int rr = my_read( buf, sizeof(buf) - 1 ); if ( rr < 0 && ( errno == EINTR || errno == EAGAIN ) ) continue; if ( rr <= 0 ) break; (void) alarm( READ_TIMEOUT ); - buf[rr] = '\0'; - add_to_request( buf ); + add_to_request( buf, rr ); if ( strstr( request, "\015\012\015\012" ) != (char*) 0 || strstr( request, "\012\012" ) != (char*) 0 ) break; @@ -1273,7 +1277,8 @@ handle_request( void ) cp = &line[5]; cp += strspn( cp, " \t" ); host = cp; - if ( strchr( host, '/' ) != (char*) 0 || host[0] == '.' ) + if ( host[0] == '\0' || host[0] == '.' || + strchr( host, '/' ) != (char*) 0 ) send_error( 400, "Bad Request", "", "Can't parse request." ); } else if ( strncasecmp( line, "If-Modified-Since:", 18 ) == 0 ) @@ -1308,6 +1313,12 @@ handle_request( void ) method = METHOD_HEAD; else if ( strcasecmp( method_str, get_method_str( METHOD_POST ) ) == 0 ) method = METHOD_POST; + else if ( strcasecmp( method_str, get_method_str( METHOD_PUT ) ) == 0 ) + method = METHOD_PUT; + else if ( strcasecmp( method_str, get_method_str( METHOD_DELETE ) ) == 0 ) + method = METHOD_DELETE; + else if ( strcasecmp( method_str, get_method_str( METHOD_TRACE ) ) == 0 ) + method = METHOD_TRACE; else send_error( 501, "Not Implemented", "", "That method is not implemented." ); @@ -1388,6 +1399,63 @@ handle_request( void ) #ifdef USE_SSL SSL_free( ssl ); #endif /* USE_SSL */ + + finish_request( 0 ); + } + + +static void +finish_request( int exitstatus ) + { +#undef LINGER_SOCKOPT +#define LINGER_READ + +#define LINGER_SECS 5 + +#ifdef LINGER_SOCKOPT + /* The sockopt version of lingering close. Doesn't actually work. */ + struct linger lin; + + shutdown( conn_fd, SHUT_WR ); + lin.l_onoff = 1; + lin.l_linger = LINGER_SECS; + (void) setsockopt( + conn_fd, SOL_SOCKET, SO_LINGER, (void*) &lin, sizeof(lin) ); +#endif /* LINGER_SOCKOPT */ + +#ifdef LINGER_READ + /* The "non-blocking read until error/eof/timeout" version of + ** lingering close. + */ + int flags; + fd_set rfds; + struct timeval tv; + int r; + char* buf[1024]; + + flags = fcntl( conn_fd, F_GETFL, 0 ); + if ( flags != -1 ) + { + flags |= (int) O_NDELAY; + (void) fcntl( conn_fd, F_SETFL, flags ); + } + shutdown( conn_fd, SHUT_WR ); + for (;;) + { + FD_ZERO( &rfds ); + FD_SET( conn_fd, &rfds ); + tv.tv_sec = LINGER_SECS; + tv.tv_usec = 0; + r = select( conn_fd + 1, &rfds, (fd_set*) 0, (fd_set*) 0, &tv ); + if ( r <= 0 ) /* timeout or error */ + break; + r = read( conn_fd, (void*) buf, sizeof(buf) ); + if ( r <= 0 ) /* eof or error */ + break; + } +#endif /* LINGER_READ */ + + exit( exitstatus ); } @@ -1508,9 +1576,12 @@ do_file( void ) do_cgi(); return; } - else if ( pathinfo != (char*) 0 ) + if ( pathinfo != (char*) 0 ) send_error( 404, "Not Found", "", "File not found." ); + if ( method != METHOD_GET && method != METHOD_HEAD ) + send_error( 501, "Not Implemented", "", "That method is not implemented." ); + fd = open( file, O_RDONLY ); if ( fd < 0 ) { @@ -1725,9 +1796,6 @@ do_cgi( void ) char* binary; char* directory; - if ( method != METHOD_GET && method != METHOD_POST ) - send_error( 501, "Not Implemented", "", "That method is not implemented for CGI." ); - /* If the socket happens to be using one of the stdin/stdout/stderr ** descriptors, move it to another descriptor so that the dup2 calls ** below don't screw things up. We arbitrarily pick fd 3 - if there @@ -1774,7 +1842,7 @@ do_cgi( void ) /* Interposer process. */ (void) close( p[0] ); cgi_interpose_input( p[1] ); - exit( 0 ); + finish_request( 0 ); } (void) close( p[1] ); if ( p[0] != STDIN_FILENO ) @@ -1816,7 +1884,7 @@ do_cgi( void ) /* Interposer process. */ (void) close( p[1] ); cgi_interpose_output( p[0], parse_headers ); - exit( 0 ); + finish_request( 0 ); } (void) close( p[0] ); if ( p[1] != STDOUT_FILENO ) @@ -1900,6 +1968,14 @@ cgi_interpose_input( int wfd ) ssize_t r, r2; char buf[1024]; + /* Set up the timeout for reading again, since we're in a sub-process. */ +#ifdef HAVE_SIGSET + (void) sigset( SIGALRM, handle_read_timeout ); +#else /* HAVE_SIGSET */ + (void) signal( SIGALRM, handle_read_timeout ); +#endif /* HAVE_SIGSET */ + (void) alarm( READ_TIMEOUT ); + c = request_len - request_idx; if ( c > 0 ) { @@ -1929,6 +2005,7 @@ cgi_interpose_input( int wfd ) break; } c += r; + (void) alarm( READ_TIMEOUT ); } post_post_garbage_hack(); } @@ -1967,6 +2044,14 @@ cgi_interpose_output( int rfd, int parse_headers ) ssize_t r, r2; char buf[1024]; + /* Set up the timeout for writing again, since we're in a sub-process. */ +#ifdef HAVE_SIGSET + (void) sigset( SIGALRM, handle_write_timeout ); +#else /* HAVE_SIGSET */ + (void) signal( SIGALRM, handle_write_timeout ); +#endif /* HAVE_SIGSET */ + (void) alarm( WRITE_TIMEOUT ); + if ( ! parse_headers ) { /* If we're not parsing headers, write out the default status line @@ -1994,10 +2079,10 @@ cgi_interpose_output( int rfd, int parse_headers ) /* Slurp in all headers. */ headers_size = 0; - add_str( &headers, &headers_size, &headers_len, (char*) 0 ); + add_data( &headers, &headers_size, &headers_len, (char*) 0, 0 ); for (;;) { - r = read( rfd, buf, sizeof(buf) - 1 ); + r = read( rfd, buf, sizeof(buf) ); if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) ) { sleep( 1 ); @@ -2008,15 +2093,14 @@ cgi_interpose_output( int rfd, int parse_headers ) br = &(headers[headers_len]); break; } - buf[r] = '\0'; - add_str( &headers, &headers_size, &headers_len, buf ); + add_data( &headers, &headers_size, &headers_len, buf, r ); if ( ( br = strstr( headers, "\015\012\015\012" ) ) != (char*) 0 || ( br = strstr( headers, "\012\012" ) ) != (char*) 0 ) break; } /* If there were no headers, bail. */ - if ( headers[0] == '\0' ) + if ( headers_len == 0 ) return; /* Figure out the status. */ @@ -2069,7 +2153,7 @@ cgi_interpose_output( int rfd, int parse_headers ) continue; } if ( r <= 0 ) - goto done; + return; for (;;) { r2 = my_write( buf, r ); @@ -2079,12 +2163,11 @@ cgi_interpose_output( int rfd, int parse_headers ) continue; } if ( r2 != r ) - goto done; + return; break; } + (void) alarm( WRITE_TIMEOUT ); } - done: - shutdown( conn_fd, SHUT_WR ); } @@ -2391,7 +2474,7 @@ send_error( int s, char* title, char* extra_header, char* text ) #ifdef USE_SSL SSL_free( ssl ); #endif /* USE_SSL */ - exit( 1 ); + finish_request( 1 ); } @@ -2576,9 +2659,9 @@ start_request( void ) } static void -add_to_request( char* str ) +add_to_request( char* str, size_t len ) { - add_str( &request, &request_size, &request_len, str ); + add_data( &request, &request_size, &request_len, str, len ); } static char* @@ -2704,6 +2787,7 @@ send_via_write( int fd, off_t size ) return; break; } + (void) alarm( WRITE_TIMEOUT ); } } } @@ -2769,14 +2853,19 @@ my_write( void* buf, size_t size ) #ifdef HAVE_SENDFILE -static int +static ssize_t my_sendfile( int fd, int s, off_t offset, size_t nbytes ) { #ifdef HAVE_LINUX_SENDFILE - off_t lo = offset; - return sendfile( s, fd, &lo, nbytes ); + off_t lo = offset; + return sendfile( s, fd, &lo, nbytes ); #else /* HAVE_LINUX_SENDFILE */ - return sendfile( fd, s, offset, nbytes, (struct sf_hdtr*) 0, (off_t*) 0, 0 ); + int r; + r = sendfile( fd, s, offset, nbytes, (struct sf_hdtr*) 0, (off_t*) 0, 0 ); + if ( r == 0 ) + return nbytes; + else + return r; #endif /* HAVE_LINUX_SENDFILE */ } #endif /* HAVE_SENDFILE */ @@ -2791,14 +2880,20 @@ add_str( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str ) len = 0; else len = strlen( str ); + add_data( bufP, bufsizeP, buflenP, str, len ); + } + +static void +add_data( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str, size_t len ) + { if ( *bufsizeP == 0 ) { *bufsizeP = len + 500; *buflenP = 0; *bufP = (char*) e_malloc( *bufsizeP ); } - else if ( *buflenP + len >= *bufsizeP ) + else if ( *buflenP + len >= *bufsizeP ) /* allow for NUL */ { *bufsizeP = *buflenP + len + 500; *bufP = (char*) e_realloc( (void*) *bufP, *bufsizeP ); @@ -2997,6 +3092,9 @@ get_method_str( int m ) case METHOD_GET: return "GET"; case METHOD_HEAD: return "HEAD"; case METHOD_POST: return "POST"; + case METHOD_PUT: return "PUT"; + case METHOD_DELETE: return "DELETE"; + case METHOD_TRACE: return "TRACE"; default: return "UNKNOWN"; } } @@ -3262,7 +3360,7 @@ static void handle_write_timeout( int sig ) { syslog( LOG_INFO, "%.80s connection timed out writing", ntoa( &client_addr ) ); - exit( 1 ); + finish_request( 1 ); } diff --git a/scripts/mini_httpd.sh b/scripts/mini_httpd.sh index 372ecee..61e7922 100755 --- a/scripts/mini_httpd.sh +++ b/scripts/mini_httpd.sh @@ -2,13 +2,16 @@ # # mini_httpd.sh - startup script for mini_httpd on FreeBSD # -# This goes in /usr/local/etc/rc.d and gets run at boot-time. +# This should be manually installed as: +# /usr/local/etc/rc.d/mini_httpd +# It gets run at boot-time. # # Variables available: -# mini_httpd_enable='YES/NO' -# mini_httpd_program='path' -# mini_httpd_pidfile='path' -# mini_httpd_devfs='path' +# mini_httpd_enable='YES' +# mini_httpd_program='/usr/local/sbin/mini_httpd' +# mini_httpd_pidfile='/var/run/mini_httpd.pid' +# mini_httpd_devfs=... +# mini_httpd_flags=... # # PROVIDE: mini_httpd # REQUIRE: LOGIN FILESYSTEMS @@ -18,31 +21,21 @@ name='mini_httpd' rcvar='mini_httpd_enable' +start_precmd='mini_httpd_precmd' +mini_httpd_enable_defval='NO' load_rc_config "$name" - -# Defaults. -mini_httpd_enable="${mini_httpd_enable:-'NO'}" -mini_httpd_program="${mini_httpd_program:-'/usr/local/sbin/mini_httpd'}" -mini_httpd_pidfile="${mini_httpd_pidfile:-'/var/run/mini_httpd.pid'}" +command="${mini_httpd_program:-/usr/local/sbin/${name}}" +pidfile="${mini_httpd_pidfile:-/var/run/${name}.pid}" +command_args="-i ${pidfile}" mini_httpd_precmd () - { - if [ '' != "$mini_httpd_devfs" ] ; then - mount -t devfs devfs "$mini_httpd_devfs" - devfs -m "$mini_httpd_devfs" rule -s 1 applyset - devfs -m "$mini_httpd_devfs" rule -s 2 applyset - fi - } - -mini_httpd_stop () - { - kill -USR1 `cat "$pidfile"` - } - -command="$mini_httpd_program" -pidfile="$mini_httpd_pidfile" -start_precmd='mini_httpd_precmd' -stop_cmd='mini_httpd_stop' +{ + if [ -n "$mini_httpd_devfs" ] ; then + mount -t devfs devfs "$mini_httpd_devfs" + devfs -m "$mini_httpd_devfs" rule -s 1 applyset + devfs -m "$mini_httpd_devfs" rule -s 2 applyset + fi +} run_rc_command "$1" diff --git a/version.h b/version.h index 22b8730..18441eb 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,7 @@ #ifndef _VERSION_H_ #define _VERSION_H_ -#define SERVER_SOFTWARE "mini_httpd/1.23 28Dec2015" +#define SERVER_SOFTWARE "mini_httpd/1.30 26Oct2018" #define SERVER_URL "http://www.acme.com/software/mini_httpd/" #endif /* _VERSION_H_ */ -- cgit v1.2.3