2008-08-05 15:08:32 +00:00
|
|
|
|
2008-10-02 19:46:06 +00:00
|
|
|
|
|
|
|
#include "base.h"
|
|
|
|
#include "plugin_core.h"
|
2008-08-05 15:08:32 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2008-09-18 07:14:57 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
2008-08-05 15:08:32 +00:00
|
|
|
void fatal(const gchar* msg) {
|
|
|
|
fprintf(stderr, "%s\n", msg);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void fd_init(int fd) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
int i = 1;
|
|
|
|
#endif
|
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
/* close fd on exec (cgi) */
|
|
|
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
|
|
#endif
|
|
|
|
#ifdef O_NONBLOCK
|
|
|
|
fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
|
|
|
|
#elif defined _WIN32
|
|
|
|
ioctlsocket(fd, FIONBIO, &i);
|
|
|
|
#endif
|
|
|
|
}
|
2008-08-06 18:46:42 +00:00
|
|
|
|
|
|
|
void ev_io_add_events(struct ev_loop *loop, ev_io *watcher, int events) {
|
|
|
|
if ((watcher->events & events) == events) return;
|
|
|
|
ev_io_stop(loop, watcher);
|
|
|
|
ev_io_set(watcher, watcher->fd, watcher->events | events);
|
|
|
|
ev_io_start(loop, watcher);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ev_io_rem_events(struct ev_loop *loop, ev_io *watcher, int events) {
|
|
|
|
if (0 == (watcher->events & events)) return;
|
|
|
|
ev_io_stop(loop, watcher);
|
|
|
|
ev_io_set(watcher, watcher->fd, watcher->events & ~events);
|
|
|
|
ev_io_start(loop, watcher);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ev_io_set_events(struct ev_loop *loop, ev_io *watcher, int events) {
|
|
|
|
if (events == (watcher->events & (EV_READ | EV_WRITE))) return;
|
|
|
|
ev_io_stop(loop, watcher);
|
|
|
|
ev_io_set(watcher, watcher->fd, (watcher->events & ~(EV_READ | EV_WRITE)) | events);
|
|
|
|
ev_io_start(loop, watcher);
|
|
|
|
}
|
2008-08-09 15:20:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* converts hex char (0-9, A-Z, a-z) to decimal.
|
|
|
|
* returns -1 on invalid input.
|
|
|
|
*/
|
|
|
|
static int hex2int(unsigned char hex) {
|
|
|
|
int res;
|
|
|
|
if (hex >= 'A') { /* 'A' < 'a': hex >= 'A' --> hex >= 'a' */
|
|
|
|
if (hex >= 'a') {
|
|
|
|
res = hex - 'a' + 10;
|
|
|
|
} else {
|
|
|
|
res = hex - 'A' + 10;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
res = hex - '0';
|
|
|
|
}
|
|
|
|
if (res > 15)
|
|
|
|
res = -1;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void url_decode(GString *path) {
|
|
|
|
char *src, *dst, c;
|
|
|
|
src = dst = path->str;
|
|
|
|
for ( ; *src; src++) {
|
|
|
|
c = *src;
|
|
|
|
if (c == '%') {
|
|
|
|
if (src[1] && src[2]) {
|
|
|
|
int a = hex2int(src[1]), b = hex2int(src[2]);
|
|
|
|
if (a != -1 && b != -1) {
|
|
|
|
c = (a << 4) | b;
|
|
|
|
if (c < 32 || c == 127) c = '_';
|
|
|
|
*(dst++) = c;
|
|
|
|
}
|
|
|
|
src += 2;
|
|
|
|
} else {
|
|
|
|
/* end of string */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (c < 32 || c == 127) c = '_';
|
|
|
|
*(dst++) = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_string_set_size(path, dst - path->str);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove "/../", "//", "/./" parts from path.
|
|
|
|
*
|
|
|
|
* /blah/.. gets /
|
|
|
|
* /blah/../foo gets /foo
|
|
|
|
* /abc/./xyz gets /abc/xyz
|
|
|
|
* /abc//xyz gets /abc/xyz
|
|
|
|
*
|
|
|
|
* NOTE: src and dest can point to the same buffer, in which case
|
|
|
|
* the operation is performed in-place.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void path_simplify(GString *path) {
|
|
|
|
int toklen;
|
|
|
|
char c, pre1;
|
|
|
|
char *start, *slash, *walk, *out;
|
|
|
|
unsigned short pre;
|
|
|
|
|
|
|
|
if (path == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
walk = start = out = slash = path->str;
|
|
|
|
while (*walk == ' ') {
|
|
|
|
walk++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pre1 = *(walk++);
|
|
|
|
c = *(walk++);
|
|
|
|
pre = pre1;
|
|
|
|
if (pre1 != '/') {
|
|
|
|
pre = ('/' << 8) | pre1;
|
|
|
|
*(out++) = '/';
|
|
|
|
}
|
|
|
|
*(out++) = pre1;
|
|
|
|
|
|
|
|
if (pre1 == '\0') {
|
|
|
|
g_string_set_size(path, out - start);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (c == '/' || c == '\0') {
|
|
|
|
toklen = out - slash;
|
|
|
|
if (toklen == 3 && pre == (('.' << 8) | '.')) {
|
|
|
|
out = slash;
|
|
|
|
if (out > start) {
|
|
|
|
out--;
|
|
|
|
while (out > start && *out != '/') {
|
|
|
|
out--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\0')
|
|
|
|
out++;
|
|
|
|
} else if (toklen == 1 || pre == (('/' << 8) | '.')) {
|
|
|
|
out = slash;
|
|
|
|
if (c == '\0')
|
|
|
|
out++;
|
|
|
|
}
|
|
|
|
|
|
|
|
slash = out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\0')
|
|
|
|
break;
|
|
|
|
|
|
|
|
pre1 = c;
|
|
|
|
pre = (pre << 8) | pre1;
|
|
|
|
c = *walk;
|
|
|
|
*out = pre1;
|
|
|
|
|
|
|
|
out++;
|
|
|
|
walk++;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_set_size(path, out - start);
|
|
|
|
}
|
2008-08-13 00:18:35 +00:00
|
|
|
|
2008-10-02 15:38:57 +00:00
|
|
|
#define SET_LEN_AND_RETURN_STR(x) \
|
|
|
|
do { \
|
|
|
|
*len = sizeof(x) - 1; \
|
|
|
|
return x; \
|
|
|
|
} while(0)
|
|
|
|
gchar *http_status_string(guint status_code, guint *len) {
|
2008-08-13 00:18:35 +00:00
|
|
|
/* RFC 2616 (as well as RFC 2518, RFC 2817, RFC 2295, RFC 2774, RFC 4918) */
|
|
|
|
switch (status_code) {
|
|
|
|
/* 1XX information */
|
2008-10-02 15:38:57 +00:00
|
|
|
case 100: SET_LEN_AND_RETURN_STR("Continue");
|
|
|
|
case 101: SET_LEN_AND_RETURN_STR("Switching Protocols");
|
|
|
|
case 102: SET_LEN_AND_RETURN_STR("Processing");
|
2008-08-13 00:18:35 +00:00
|
|
|
/* 2XX successful operation */
|
2008-10-02 15:38:57 +00:00
|
|
|
case 200: SET_LEN_AND_RETURN_STR("OK");
|
|
|
|
case 201: SET_LEN_AND_RETURN_STR("Created");
|
|
|
|
case 202: SET_LEN_AND_RETURN_STR("Accepted");
|
|
|
|
case 203: SET_LEN_AND_RETURN_STR("Non-Authoritative Information");
|
|
|
|
case 204: SET_LEN_AND_RETURN_STR("No Content");
|
|
|
|
case 205: SET_LEN_AND_RETURN_STR("Reset Content");
|
|
|
|
case 206: SET_LEN_AND_RETURN_STR("Partial Content");
|
|
|
|
case 207: SET_LEN_AND_RETURN_STR("Multi-Status");
|
2008-08-13 00:18:35 +00:00
|
|
|
/* 3XX redirect */
|
2008-10-02 15:38:57 +00:00
|
|
|
case 300: SET_LEN_AND_RETURN_STR("Multiple Choice");
|
|
|
|
case 301: SET_LEN_AND_RETURN_STR("Moved Permanently");
|
|
|
|
case 302: SET_LEN_AND_RETURN_STR("Found");
|
|
|
|
case 303: SET_LEN_AND_RETURN_STR("See Other");
|
|
|
|
case 304: SET_LEN_AND_RETURN_STR("Not Modified");
|
|
|
|
case 305: SET_LEN_AND_RETURN_STR("Use Proxy");
|
|
|
|
case 306: SET_LEN_AND_RETURN_STR("(reserved)");
|
|
|
|
case 307: SET_LEN_AND_RETURN_STR("Temporary Redirect");
|
2008-08-13 00:18:35 +00:00
|
|
|
/* 4XX client error */
|
2008-10-02 15:38:57 +00:00
|
|
|
case 400: SET_LEN_AND_RETURN_STR("Bad Request");
|
|
|
|
case 401: SET_LEN_AND_RETURN_STR("Unauthorized");
|
|
|
|
case 402: SET_LEN_AND_RETURN_STR("Payment Required");
|
|
|
|
case 403: SET_LEN_AND_RETURN_STR("Forbidden");
|
|
|
|
case 404: SET_LEN_AND_RETURN_STR("Not Found");
|
|
|
|
case 405: SET_LEN_AND_RETURN_STR("Method Not Allowed");
|
|
|
|
case 406: SET_LEN_AND_RETURN_STR("Not Acceptable");
|
|
|
|
case 407: SET_LEN_AND_RETURN_STR("Proxy Authentication Required");
|
|
|
|
case 408: SET_LEN_AND_RETURN_STR("Request Time-out");
|
|
|
|
case 409: SET_LEN_AND_RETURN_STR("Conflict");
|
|
|
|
case 410: SET_LEN_AND_RETURN_STR("Gone");
|
|
|
|
case 411: SET_LEN_AND_RETURN_STR("Length Required");
|
|
|
|
case 412: SET_LEN_AND_RETURN_STR("Precondition Failed");
|
|
|
|
case 413: SET_LEN_AND_RETURN_STR("Request Entity Too Large");
|
|
|
|
case 414: SET_LEN_AND_RETURN_STR("Request-URI Too Long");
|
|
|
|
case 415: SET_LEN_AND_RETURN_STR("Unsupported Media Type");
|
|
|
|
case 416: SET_LEN_AND_RETURN_STR("Request range not satisfiable");
|
|
|
|
case 417: SET_LEN_AND_RETURN_STR("Expectation Failed");
|
|
|
|
case 421: SET_LEN_AND_RETURN_STR("There are too many connections from your internet address");
|
|
|
|
case 422: SET_LEN_AND_RETURN_STR("Unprocessable Entity");
|
|
|
|
case 423: SET_LEN_AND_RETURN_STR("Locked");
|
|
|
|
case 424: SET_LEN_AND_RETURN_STR("Failed Dependency");
|
|
|
|
case 425: SET_LEN_AND_RETURN_STR("Unordered Collection");
|
|
|
|
case 426: SET_LEN_AND_RETURN_STR("Upgrade Required");
|
2008-08-13 00:18:35 +00:00
|
|
|
/* 5XX server error */
|
2008-10-02 15:38:57 +00:00
|
|
|
case 500: SET_LEN_AND_RETURN_STR("Internal Server Error");
|
|
|
|
case 501: SET_LEN_AND_RETURN_STR("Not Implemented");
|
|
|
|
case 502: SET_LEN_AND_RETURN_STR("Bad Gateway");
|
|
|
|
case 503: SET_LEN_AND_RETURN_STR("Service Unavailable");
|
|
|
|
case 504: SET_LEN_AND_RETURN_STR("Gateway Time-out");
|
|
|
|
case 505: SET_LEN_AND_RETURN_STR("HTTP Version not supported");
|
|
|
|
case 506: SET_LEN_AND_RETURN_STR("Variant Also Negotiates");
|
|
|
|
case 507: SET_LEN_AND_RETURN_STR("Insufficient Storage");
|
|
|
|
case 509: SET_LEN_AND_RETURN_STR("Bandwidth Limit Exceeded");
|
|
|
|
case 510: SET_LEN_AND_RETURN_STR("Not Extended");
|
2008-08-13 00:18:35 +00:00
|
|
|
|
|
|
|
/* unknown */
|
2008-10-02 15:38:57 +00:00
|
|
|
default: SET_LEN_AND_RETURN_STR("unknown status");
|
2008-08-13 00:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
2008-10-02 15:38:57 +00:00
|
|
|
#undef SET_LEN_AND_RETURN_STR
|
|
|
|
|
|
|
|
void http_status_to_str(gint status_code, gchar status_str[]) {
|
2008-10-02 15:43:05 +00:00
|
|
|
status_str[2] = status_code % 10 + '0';
|
|
|
|
status_code /= 10;
|
|
|
|
status_str[1] = status_code % 10 + '0';
|
|
|
|
status_code /= 10;
|
|
|
|
status_str[0] = status_code + '0';
|
2008-10-02 15:38:57 +00:00
|
|
|
}
|
2008-08-13 23:05:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
gchar counter_format(guint64 *count, guint factor) {
|
|
|
|
gchar suffix = 0;
|
|
|
|
|
2008-08-15 18:38:20 +00:00
|
|
|
if (*count >= factor) { *count /= factor; suffix = 'k';
|
|
|
|
if (*count >= factor) { *count /= factor; suffix = 'm';
|
|
|
|
if (*count >= factor) { *count /= factor; suffix = 'g';
|
|
|
|
if (*count >= factor) { *count /= factor; suffix = 't';
|
|
|
|
if (*count >= factor) { *count /= factor; suffix = 'p';
|
|
|
|
if (*count >= factor) { *count /= factor; suffix = 'e'; }
|
2008-08-13 23:05:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return suffix;
|
|
|
|
}
|
2008-08-15 16:21:21 +00:00
|
|
|
|
2008-11-03 14:10:25 +00:00
|
|
|
GString *counter_format2(guint64 count, counter_type t, gint accuracy) {
|
|
|
|
GString *str = g_string_sized_new(64);
|
|
|
|
|
|
|
|
if (t == COUNTER_TIME) {
|
|
|
|
if (accuracy && count > (3600*24)) {
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " day%s", count / (3600*24), (count / (3600*24)) > 1 ? "s":"");
|
|
|
|
count %= 3600*24;
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > 3600) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " hour%s", count / 3600, (count / 3600) > 1 ? "s":"");
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " hour%s", count / 3600, (count / 3600) > 1 ? "s":"");
|
|
|
|
count %= 3600;
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > 60) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " min", count / 60);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " min", count / 60);
|
|
|
|
count %= 60;
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && (count || !str->len)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " s", count);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " s", count);
|
|
|
|
}
|
|
|
|
} else if (t == COUNTER_UNITS) {
|
|
|
|
if (accuracy && count > 1000000) {
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " m", count / 1000000);
|
|
|
|
count %= 1000000;
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > 1000) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " k", count / 1000);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " k", count / 1000);
|
|
|
|
count %= 1000;
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && (count || !str->len)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT, count);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT, count);
|
|
|
|
}
|
|
|
|
} else if (t == COUNTER_BYTES) {
|
|
|
|
if (accuracy && count > (1024*1024*1024*G_GUINT64_CONSTANT(1024))) {
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " TiB", count / (1024*1024*1024*G_GUINT64_CONSTANT(1024)));
|
|
|
|
count %= (1024*1024*1024*G_GUINT64_CONSTANT(1024));
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > (1024*1024*1024)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " GiB", count / (1024*1024*1024));
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " GiB", count / (1024*1024*1024));
|
|
|
|
count %= (1024*1024*1024);
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > (1024*1024)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " MiB", count / (1024*1024));
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " MiB", count / (1024*1024));
|
|
|
|
count %= (1024*1024);
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > 1024) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " KiB", count / 1024);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " KiB", count / 1024);
|
|
|
|
count %= 1024;
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && (count || !str->len)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " B", count);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " B", count);
|
|
|
|
}
|
|
|
|
} else if (t == COUNTER_BITS) {
|
|
|
|
if (accuracy && count > (1000*1000*1000)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " gb", count / (1000*1000*1000));
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " gbit", count / (1000*1000*1000));
|
|
|
|
count %= (1024*1024*1024);
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > (1024*1024)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " mbit", count / (1024*1024));
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " ", count / (1024*1024));
|
|
|
|
count %= (1024*1024);
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && count > 1024) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " KiB", count / 1024);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " KiB", count / 1024);
|
|
|
|
count %= 1024;
|
|
|
|
accuracy--;
|
|
|
|
}
|
|
|
|
if (accuracy && (count || !str->len)) {
|
|
|
|
if (str->len)
|
|
|
|
g_string_append_printf(str, " %" G_GUINT64_FORMAT " B", count);
|
|
|
|
else
|
|
|
|
g_string_append_printf(str, "%" G_GUINT64_FORMAT " B", count);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
g_string_append_len(str, CONST_STR_LEN("unknown counter type"));
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2008-08-15 16:21:21 +00:00
|
|
|
gchar *ev_backend_string(guint backend) {
|
|
|
|
switch (backend) {
|
2008-08-15 18:38:20 +00:00
|
|
|
case EVBACKEND_SELECT: return "select";
|
|
|
|
case EVBACKEND_POLL: return "poll";
|
|
|
|
case EVBACKEND_EPOLL: return "epoll";
|
|
|
|
case EVBACKEND_KQUEUE: return "kqueue";
|
|
|
|
case EVBACKEND_DEVPOLL: return "devpoll";
|
|
|
|
case EVBACKEND_PORT: return "port";
|
|
|
|
default: return "unknown";
|
2008-08-15 16:21:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-24 21:55:20 +00:00
|
|
|
void string_destroy_notify(gpointer str) {
|
|
|
|
g_string_free((GString*)str, TRUE);
|
|
|
|
}
|
2008-10-02 00:33:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
guint hash_ipv4(gconstpointer key) {
|
2008-10-02 00:37:36 +00:00
|
|
|
return *((guint*)key);
|
2008-10-02 00:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
guint hash_ipv6(gconstpointer key) {
|
|
|
|
guint *i = ((guint*)key);
|
|
|
|
return i[0] ^ i[1] ^ i[2] ^ i[3];
|
|
|
|
}
|
2008-10-02 19:46:06 +00:00
|
|
|
|
|
|
|
|
2008-10-25 16:01:02 +00:00
|
|
|
GString *mimetype_get(vrequest *vr, GString *filename) {
|
2008-10-02 19:46:06 +00:00
|
|
|
/* search in mime_types option for the first match */
|
|
|
|
GArray *arr;
|
|
|
|
|
2008-10-25 16:01:02 +00:00
|
|
|
if (!vr || !filename || !filename->len)
|
2008-10-02 19:46:06 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
arr = CORE_OPTION(CORE_OPTION_MIME_TYPES).list;
|
|
|
|
|
|
|
|
for (guint i = 0; i < arr->len; i++) {
|
|
|
|
value *tuple = g_array_index(arr, value*, i);
|
|
|
|
GString *ext = g_array_index(tuple->data.list, value*, 0)->data.string;
|
|
|
|
if (ext->len > filename->len)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* "" extension matches everything, used for default mimetype */
|
|
|
|
if (!ext->len)
|
|
|
|
return g_array_index(tuple->data.list, value*, 1)->data.string;
|
|
|
|
|
|
|
|
gint k = filename->len - 1;
|
|
|
|
gint j = ext->len - 1;
|
|
|
|
for (; j >= 0; j--) {
|
|
|
|
if (ext->str[j] != filename->str[k])
|
|
|
|
break;
|
|
|
|
k--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == -1)
|
|
|
|
return g_array_index(tuple->data.list, value*, 1)->data.string;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-11-03 14:10:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
GString *sockaddr_to_string(sock_addr *saddr, GString *dest) {
|
|
|
|
gchar *p;
|
|
|
|
guint8 len = 0;
|
|
|
|
guint8 tmp;
|
|
|
|
guint8 tmplen;
|
|
|
|
guint8 oct;
|
|
|
|
|
|
|
|
switch (saddr->plain.sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
/* ipv4 */
|
|
|
|
if (!dest)
|
|
|
|
dest = g_string_sized_new(16);
|
|
|
|
else
|
|
|
|
g_string_set_size(dest, 16);
|
|
|
|
|
|
|
|
p = dest->str;
|
|
|
|
|
|
|
|
for (guint i = 0; i < 4; i++) {
|
|
|
|
oct = ((guint8*)&saddr->ipv4.sin_addr.s_addr)[i];
|
|
|
|
for (tmplen = 1, tmp = oct; tmp > 9; tmp /= 10)
|
|
|
|
tmplen++;
|
|
|
|
|
|
|
|
len += tmplen + 1;
|
|
|
|
tmp = tmplen;
|
|
|
|
|
|
|
|
p[tmplen] = '.';
|
|
|
|
|
|
|
|
for (p += tmplen-1; tmplen; tmplen--) {
|
|
|
|
*p = '0' + (oct % 10);
|
|
|
|
p--;
|
|
|
|
oct /= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
p += tmp + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest->str[len-1] = 0;
|
|
|
|
dest->len = len-1;
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
/* ipv6 - not yet implemented with own function */
|
|
|
|
if (!dest)
|
|
|
|
dest = g_string_sized_new(INET6_ADDRSTRLEN);
|
|
|
|
else
|
|
|
|
g_string_set_size(dest, INET6_ADDRSTRLEN);
|
|
|
|
|
|
|
|
inet_ntop(AF_INET6, saddr->ipv6.sin6_addr.s6_addr, dest->str, INET6_ADDRSTRLEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
2008-11-12 01:09:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
void waitqueue_init(waitqueue *queue, struct ev_loop *loop, waitqueue_cb callback, gdouble delay, gpointer data) {
|
|
|
|
ev_timer_init(&queue->timer, callback, delay, delay);
|
|
|
|
ev_timer_start(loop, &queue->timer);
|
|
|
|
|
|
|
|
queue->timer.data = data;
|
|
|
|
queue->head = queue->tail = NULL;
|
|
|
|
queue->loop = loop;
|
|
|
|
queue->delay = delay;
|
|
|
|
}
|
|
|
|
|
|
|
|
void waitqueue_stop(waitqueue *queue) {
|
|
|
|
ev_timer_stop(queue->loop, &queue->timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void waitqueue_update(waitqueue *queue) {
|
|
|
|
ev_tstamp repeat;
|
|
|
|
|
|
|
|
if (queue->head) {
|
|
|
|
repeat = queue->head->ts + queue->delay - ev_now(queue->loop);
|
|
|
|
} else
|
|
|
|
repeat = queue->delay;
|
|
|
|
|
|
|
|
if (queue->timer.repeat != repeat)
|
|
|
|
{
|
|
|
|
queue->timer.repeat = repeat;
|
|
|
|
ev_timer_again(queue->loop, &queue->timer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void waitqueue_push(waitqueue *queue, waitqueue_elem *elem) {
|
|
|
|
elem->ts = ev_now(queue->loop);
|
|
|
|
|
|
|
|
if (!elem->queued) {
|
|
|
|
elem->queued = TRUE;
|
|
|
|
/* not in the queue yet, insert at the end */
|
|
|
|
if (!queue->head) {
|
|
|
|
/* queue is empty */
|
|
|
|
queue->head = elem;
|
|
|
|
queue->tail = elem;
|
|
|
|
elem->prev = NULL;
|
|
|
|
elem->next = NULL;
|
|
|
|
} else {
|
|
|
|
/* queue not empty */
|
|
|
|
elem->prev = queue->tail;
|
|
|
|
elem->next = NULL;
|
|
|
|
queue->tail->next = elem;
|
|
|
|
queue->tail = elem;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* already queued, move to end */
|
|
|
|
if (elem == queue->tail)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (elem == queue->head) {
|
|
|
|
queue->head = elem->next;
|
|
|
|
if (elem->next)
|
|
|
|
elem->next->prev = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
elem->prev = queue->tail;
|
|
|
|
elem->next = NULL;
|
|
|
|
queue->tail->next = elem;
|
|
|
|
queue->tail = elem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
waitqueue_elem *waitqueue_pop(waitqueue *queue) {
|
|
|
|
waitqueue_elem *elem = queue->head;
|
|
|
|
ev_tstamp now = ev_now(queue->loop);
|
|
|
|
|
|
|
|
if (!elem || (elem->ts + queue->delay) >= now) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (elem != queue->tail)
|
|
|
|
elem->next->prev = NULL;
|
|
|
|
|
|
|
|
queue->head = elem->next;
|
|
|
|
|
|
|
|
elem->queued = FALSE;
|
|
|
|
|
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
|
|
|
|
void waitqueue_remove(waitqueue *queue, waitqueue_elem *elem) {
|
|
|
|
if (!elem->queued)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (elem == queue->head)
|
|
|
|
queue->head = elem->next;
|
|
|
|
else
|
|
|
|
elem->prev->next = elem->next;
|
|
|
|
|
|
|
|
if (elem == queue->tail)
|
|
|
|
queue->tail = elem->prev;
|
|
|
|
else
|
|
|
|
elem->next->prev = elem->prev;
|
|
|
|
|
|
|
|
elem->queued = FALSE;
|
|
|
|
}
|