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