summaryrefslogtreecommitdiff
path: root/cgitcgi/http.c
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2023-03-24 03:51:10 +0300
committerkx <kx@radix.pro>2023-03-24 03:51:10 +0300
commit05d292b208dfe01324826b4c87bbc4da3389a0d5 (patch)
treeb10a2269e9320785f3b61189e75f6778fa167986 /cgitcgi/http.c
parent40ab18a661ff6ada40e73969be293918d346a2f5 (diff)
downloadcgit-ui-05d292b208dfe01324826b4c87bbc4da3389a0d5.tar.xz
Version 0.1.7
Diffstat (limited to 'cgitcgi/http.c')
-rw-r--r--cgitcgi/http.c298
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 );
+}