You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
4.5 KiB
180 lines
4.5 KiB
#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";
|
|
}
|
|
}
|
|
|