A small http server written in C
git clone git://git.janzachar.dev/shttp.git
0#include "super.h"12#include <time.h>3#include <stdio.h>4#include <string.h>56struct code {7 int code;8 char *message;9} codes[] = {10 {100, "Continue"},11 {101, "Switching protocols"},1213 {200, "OK"},14 {201, "Created"},15 {202, "Accepted"},16 {203, "Non-Authoritative Information"},17 {204, "No Content"},18 {205, "Reset Content"},19 {206, "Partial Content"},2021 {300, "Multiple Choices"},22 {301, "Moved Permanently"},23 {302, "Found"},24 {303, "See Other"},25 {304, "Not Modified"},26 {305, "Use Proxy"},27 // 306 is outdated, according to rfc911028 {307, "Temporary Redirect"},29 {308, "Permanent Redirect"},3031 {400, "Bad Request"},32 {401, "Unauthorized"},33 {402, "Payment Required"},34 {403, "Forbidden"},35 {404, "Not Found"},36 {405, "Method Not Allowed"},37 {406, "Not Acceptable"},38 {407, "Proxy Authentication Required"},39 {408, "Request Timeout"},40 {409, "Conflict"},41 {410, "Gone"},42 {411, "Length Required"},43 {412, "Precondition Failed"},44 {413, "Content Too Large"},45 {414, "URI Too Long"},46 {415, "Unsupported Media Type"},47 {416, "Range Not Satisfiable"},48 {417, "Expectation Failed"},49 {418, "I'm a teapot"},50 {421, "Misdirected Request"},51 {422, "Unprocessable Content"},52 {426, "Upgrade Required"},535455 {500, "Internal Server Error"},56 {501, "Not Implemented"},57 {502, "Bad Gateway"},58 {503, "Service Unavailable"},59 {504, "Gateway Timeout"},60 {505, "HTTP Version Not Supported"},6162 {0, NULL}63};6465const char *get_date()66{67 static char date[32];68 static time_t last = 0;6970 time_t t = time(NULL);71 if (t != last) {72 struct tm tm;73 gmtime_r(&t, &tm);74 strftime(date, sizeof(date), TIMESTAMP_FORMAT, &tm);75 last = t;76 }7778 return date;79}8081int __build_reply(char buff[], int len, int code, struct header hd[])82{83 char *ptr = buff;84 memset(buff, 0, len);8586 push(len, "HTTP/1.1 ");8788 int flag = 1;89 for (struct code *p = codes; p->code; p++) {90 if (code != p->code) continue;9192 push(len, "%d %s\r\n", p->code, p->message);9394 flag = 0;95 break;96 }97 if (flag) return -1;9899 push(len, "Date: %s\r\n", get_date());100 push(len, "Connection: close\r\n");101 if (hd) while (hd->key) {102 push(len, "%s: %s\r\n", hd->key, hd->value);103 hd++;104 }105106 return ptr-buff;107}108109int reply(int fd, int code, struct header hd[])110{111 char buff[64 * 1024];112 char *ptr = buff;113114 int r = __build_reply(buff, sizeof(buff), code, hd);115 if (r < 0) return -1;116 ptr += r;117118 push(sizeof(buff), "\r\n");119 if (send(fd, buff, ptr-buff, 0) != ptr-buff) return 1;120 return 0;121}122123int freply(int fd, int code, struct header hd[], FILE *fp)124{125 char buff[64 * 1024];126 char *ptr = buff;127128 int r = __build_reply(buff, sizeof(buff), code, hd);129 if (r < 0) return -1;130 ptr += r;131132 if (fp) {133 long siz = getsize(fp);134 if (siz == -1) return 1;135 push(sizeof(buff), "Content-Length: %ld\r\n", siz);136 } else push(sizeof(buff), "Content-Length: 0\r\n");137 push(sizeof(buff), "\r\n");138139 if (send(fd, buff, ptr-buff, 0) != ptr-buff) return 1;140141 if (fp) {142 while (1) {143 int c = fread(buff, 1, sizeof(buff), fp);144 if (send(fd, buff, c, 0) != c) return 1;145 if (c != sizeof(buff)) break;146 }147 }148 return 0;149}150151int sreply(int fd, int code, struct header hd[], char *out, int siz)152{153 char buff[64 * 1024];154 char *ptr = buff;155156 int r = __build_reply(buff, sizeof(buff), code, hd);157 if (r < 0) return -1;158 ptr += r;159160 push(sizeof(buff), "Content-Length: %d\r\n", (out == NULL ? 0 : siz));161 push(sizeof(buff), "\r\n");162163 if (send(fd, buff, ptr-buff, 0) != ptr-buff) return 1;164165 if (out != NULL && send(fd, out, siz, 0) != siz) return 1;166 return 0;167}168