5 kx
5 kx #ifdef HAVE_CONFIG_H
5 kx #include <config.h>
5 kx #endif
5 kx
5 kx #include <stdlib.h>
5 kx #include <stdio.h>
5 kx #include <sys/sysinfo.h>
5 kx #include <sys/types.h>
5 kx #include <stdint.h>
5 kx #include <dirent.h>
5 kx #include <sys/stat.h> /* chmod(2) */
5 kx #include <sys/file.h>
5 kx #include <sys/mman.h>
5 kx #include <fcntl.h>
5 kx #include <limits.h>
5 kx #include <string.h> /* strdup(3) */
5 kx #include <libgen.h> /* basename(3) */
5 kx #include <ctype.h> /* tolower(3) */
5 kx #include <errno.h>
5 kx #include <time.h>
5 kx #include <sys/time.h>
5 kx #include <pwd.h>
5 kx #include <grp.h>
5 kx #include <stdarg.h>
5 kx #include <unistd.h>
5 kx
5 kx #include <defs.h>
5 kx #include <fatal.h>
5 kx #include <http.h>
5 kx #include <html.h>
5 kx #include <strbuf.h>
5 kx
5 kx
5 kx const signed char hexval_table[256] = {
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */
5 kx 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
5 kx 8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */
5 kx -1, 10, 11, 12, 13, 14, 15, -1, /* 40-47 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */
5 kx -1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */
5 kx -1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
5 kx };
5 kx
5 kx
5 kx static char *
5 kx url_decode_internal( const char **query, int len,
5 kx const char *stop_at, struct strbuf *out,
5 kx int decode_plus )
5 kx {
5 kx const char *q = *query;
5 kx
5 kx while( len )
5 kx {
5 kx unsigned char c = *q;
5 kx
5 kx if( !c )
5 kx break;
5 kx if( stop_at && strchr( stop_at, c ) )
5 kx {
5 kx ++q;
5 kx --len;
5 kx break;
5 kx }
5 kx
5 kx if( c == '%' && (len < 0 || len >= 3) )
5 kx {
5 kx int val = hex2chr( q + 1 );
5 kx if( 0 < val )
5 kx {
5 kx strbuf_addch( out, val );
5 kx q += 3;
5 kx len -= 3;
5 kx continue;
5 kx }
5 kx }
5 kx
5 kx if( decode_plus && c == '+' )
5 kx strbuf_addch( out, ' ' );
5 kx else
5 kx strbuf_addch( out, c );
5 kx ++q;
5 kx --len;
5 kx }
5 kx *query = q;
5 kx
5 kx return strbuf_detach( out, NULL );
5 kx }
5 kx
5 kx char *url_decode_mem( const char *url, int len )
5 kx {
5 kx struct strbuf out = STRBUF_INIT;
5 kx const char *colon = memchr( url, ':', len );
5 kx
5 kx /* Skip protocol part if present */
5 kx if( colon && url < colon )
5 kx {
5 kx strbuf_add( &out, url, colon - url );
5 kx len -= colon - url;
5 kx url = colon;
5 kx }
5 kx return url_decode_internal( &url, len, NULL, &out, 0 );
5 kx }
5 kx
5 kx char *url_percent_decode( const char *encoded )
5 kx {
5 kx struct strbuf out = STRBUF_INIT;
5 kx return url_decode_internal( &encoded, strlen(encoded), NULL, &out, 0 );
5 kx }
5 kx
5 kx char *url_decode_parameter_name( const char **query )
5 kx {
5 kx struct strbuf out = STRBUF_INIT;
5 kx return url_decode_internal( query, -1, "&=", &out, 1 );
5 kx }
5 kx
5 kx char *url_decode_parameter_value( const char **query )
5 kx {
5 kx struct strbuf out = STRBUF_INIT;
5 kx return url_decode_internal( query, -1, "&", &out, 1 );
5 kx }
5 kx
5 kx void http_parse_querystring( const char *txt, void (*fn)(const char *name, const char *value) )
5 kx {
5 kx const char *t = txt;
5 kx
5 kx while( t && *t )
5 kx {
5 kx char *name = url_decode_parameter_name( &t );
5 kx if( *name )
5 kx {
5 kx char *value = url_decode_parameter_value( &t );
5 kx fn( name, value );
5 kx free( value );
5 kx }
5 kx free( name );
5 kx }
5 kx }
5 kx
5 kx
5 kx
5 kx #define HTTP_ERRMSG_SIZE 4096
5 kx
5 kx void http_error( const char *fmt, ... )
5 kx {
5 kx va_list arg_ptr;
5 kx char buf[HTTP_ERRMSG_SIZE];
5 kx char msg[HTTP_ERRMSG_SIZE];
5 kx char *format = "%s: %s\n";
5 kx
5 kx va_start( arg_ptr, fmt );
5 kx
5 kx vsnprintf( msg, HTTP_ERRMSG_SIZE, (const void *)fmt, arg_ptr );
5 kx
5 kx va_end( arg_ptr ); /* Reset variable arguments. */
5 kx
5 kx snprintf( buf, HTTP_ERRMSG_SIZE, format, "http", msg );
5 kx
5 kx (void)write( STDERR_FILENO, buf, strlen( buf ) );
5 kx
5 kx exit( 1 );
5 kx }
5 kx
5 kx http_errfunc http_fatal = http_error;
5 kx
5 kx
5 kx static struct
5 kx {
5 kx int code;
5 kx const char *desc;
5 kx }
5 kx status[] =
5 kx {
5 kx { 100, "Continue" },
5 kx { 101, "Switching Protocols" },
5 kx { 200, "OK" },
5 kx { 201, "Created" },
5 kx { 202, "Accepted" },
5 kx { 203, "Non-Authoritative Information" },
5 kx { 204, "No Content" },
5 kx { 205, "Reset Content" },
5 kx { 206, "Partial Content" },
5 kx { 300, "Multiple Choices" },
5 kx { 301, "Moved Permanently" },
5 kx { 302, "Found" },
5 kx { 303, "See Other" },
5 kx { 304, "Not Modified" },
5 kx { 305, "Use Proxy" },
5 kx { 307, "Temporary Redirect" },
5 kx { 400, "Bad Request" },
5 kx { 401, "Unauthorized" },
5 kx { 402, "Payment Required" },
5 kx { 403, "Forbidden" },
5 kx { 404, "Not Found" },
5 kx { 405, "Method Not Allowed" },
5 kx { 406, "Not Acceptable" },
5 kx { 407, "Proxy Authentication Required" },
5 kx { 408, "Request Timeout" },
5 kx { 409, "Conflict" },
5 kx { 410, "Gone" },
5 kx { 411, "Length Required" },
5 kx { 412, "Precondition Failed" },
5 kx { 413, "Request Entity Too Large" },
5 kx { 414, "Request-URI Too Long" },
5 kx { 415, "Unsupported Media Type" },
5 kx { 416, "Requested Range Not Satisfiable" },
5 kx { 417, "Expectation Failed" },
5 kx { 418, "I'm a teapot" },
5 kx { 500, "Internal Server Error" },
5 kx { 501, "Not Implemented" },
5 kx { 502, "Bad Gateway" },
5 kx { 503, "Service Unavailable" },
5 kx { 504, "Gateway Timeout" },
5 kx { 505, "HTTP Version Not Supported" },
5 kx { 0, NULL }
5 kx };
5 kx
5 kx const char *http_status( int status_code )
5 kx {
5 kx int i = 0, code;
5 kx
5 kx while( (code = status[i].code) )
5 kx {
5 kx if( code == status_code ) return status[i].desc;
5 kx ++i;
5 kx }
5 kx return NULL;
5 kx }
5 kx
5 kx char *fmt( const char *format, ... )
5 kx {
5 kx static char buf[8][1024];
5 kx static int bufidx;
5 kx int len;
5 kx va_list args;
5 kx
5 kx bufidx++;
5 kx bufidx &= 7;
5 kx
5 kx va_start( args, format );
5 kx len = vsnprintf( buf[bufidx], sizeof(buf[bufidx]), format, args );
5 kx va_end(args);
5 kx if( len > sizeof(buf[bufidx]) ) {
5 kx http_fatal( "string truncated: %s", format );
5 kx }
5 kx return buf[bufidx];
5 kx }
5 kx
5 kx char *fmtalloc( const char *format, ... )
5 kx {
5 kx struct strbuf sb = STRBUF_INIT;
5 kx va_list args;
5 kx
5 kx va_start( args, format );
5 kx strbuf_vaddf( &sb, format, args );
5 kx va_end( args );
5 kx
5 kx return strbuf_detach( &sb, NULL );
5 kx }
5 kx
5 kx
5 kx char *http_date( time_t t )
5 kx {
5 kx static char day[][4] =
5 kx { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
5 kx static char month[][4] =
5 kx { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
5 kx "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
5 kx struct tm *tm = gmtime(&t);
5 kx return fmt( "%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday],
5 kx tm->tm_mday, month[tm->tm_mon], 1900 + tm->tm_year,
5 kx tm->tm_hour, tm->tm_min, tm->tm_sec );
5 kx }