#include "httpd-utils.h" #include "httpd-logging.h" const char *strnstr(const char *str, const char *substr, size_t n) { if (!str || !substr) { return NULL; } size_t substr_len = strlen(substr); if (0 == substr_len || substr_len > n) { return NULL; } const char *pEnd = str + n + 1 - substr_len; for (const char *p = str; p < pEnd; p++) { if (0 == strncmp(p, substr, substr_len)) { return p; } } return NULL; } char httpdHexNibble(uint8_t val) { val &= 0xf; if (val < 10) { return (char) ('0' + val); } return (char) ('A' + (val - 10)); } uint8_t httpdHexVal(char c) { if (c >= '0' && c <= '9') { return (uint8_t) (c - '0'); } if (c >= 'A' && c <= 'F') { return (uint8_t) (c - 'A' + 10); } if (c >= 'a' && c <= 'f') { return (uint8_t) (c - 'a' + 10); } return 0; } size_t httpdUrlDecode(const char *val, size_t valLen, char *buff, size_t buffLen) { size_t s = 0, d = 0; int esced = 0; uint8_t escVal = 0; while (s < valLen && d < buffLen) { if (esced == 1) { escVal = (uint8_t) (httpdHexVal(val[s]) << 4); esced = 2; } else if (esced == 2) { escVal |= httpdHexVal(val[s]); buff[d++] = (char) escVal; esced = 0; } else if (val[s] == '%') { esced = 1; } else if (val[s] == '+') { buff[d++] = ' '; } else { buff[d++] = val[s]; } s++; } if (d < buffLen) { buff[d] = 0; } return d; } int httpdFindArg(const char *line, const char *arg, char *buff, size_t buffLen) { const char *p, *e; if (line == NULL) { return -1; } const size_t arglen = strlen(arg); p = line; while (p != NULL && *p != '\n' && *p != '\r' && *p != 0) { router_dbg("findArg: %s", p); if (strstarts(p, arg) && p[arglen] == '=') { p += arglen + 1; //move p to start of value e = strstr(p, "&"); if (e == NULL) { e = p + strlen(p); } router_dbg("findArg: val %s len %d", p, (int) (e - p)); return (int) httpdUrlDecode(p, (size_t) (e - p), buff, buffLen); } p = strstr(p, "&"); if (p != NULL) { p += 1; } } router_error("Finding arg %s in %s: Not found :/", arg, line); return -1; //not found } //Struct to keep extension->mime data in typedef struct { const char *ext; const char *mimetype; } MimeMap; /** * The mappings from file extensions to mime types. If you need an extra mime type, * add it here. */ static const MimeMap MIME_TYPES[] = { {"htm", "text/html"}, {"html", "text/html"}, {"css", "text/css"}, {"js", "text/javascript"}, {"txt", "text/plain"}, {"csv", "text/csv"}, {"ico", "image/x-icon"}, {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, {"png", "image/png"}, {"gif", "image/gif"}, {"bmp", "image/bmp"}, {"svg", "image/svg+xml"}, {"xml", "text/xml"}, {"json", "application/json"}, }; const char *httpdGetMimetype(const char *url) { //Go find the extension const char *ext = url + (strlen(url) - 1); while (ext != url && *ext != '.') { ext--; } if (*ext == '.') { ext++; } for (size_t i = 0; i < array_len(MIME_TYPES); i++) { if (strcaseeq(ext, MIME_TYPES[i].ext)) { return MIME_TYPES[i].mimetype; } } return NULL; } const char *httpdMethodName(httpd_method m) { switch (m) { default: case HTTPD_METHOD_GET: return "GET"; case HTTPD_METHOD_POST: return "POST"; case HTTPD_METHOD_OPTIONS: return "OPTIONS"; case HTTPD_METHOD_PUT: return "PUT"; case HTTPD_METHOD_DELETE: return "DELETE"; case HTTPD_METHOD_PATCH: return "PATCH"; case HTTPD_METHOD_HEAD: return "HEAD"; } } const char *httpdStatusName(int code) { // TODO more codes switch (code) { case 200: return "OK"; case 301: return "Moved Permanently"; case 302: return "Found"; case 400: return "Bad Request"; case 401: return "Unauthorized"; case 403: return "Forbidden"; case 404: return "Not Found"; default: if (code >= 500) { return "Server Error"; } if (code >= 400) { return "Client Error"; } return "OK"; } }