#include "utils.h" #include #include 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 } 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); } /* 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); } gchar *http_status_string(guint status_code) { /* RFC 2616 (as well as RFC 2518, RFC 2817, RFC 2295, RFC 2774, RFC 4918) */ switch (status_code) { /* 1XX information */ case 100: return "Continue"; case 101: return "Switching Protocols"; case 102: return "Processing"; /* 2XX successful operation */ case 200: return "OK"; case 201: return "Created"; case 202: return "Accepted"; case 203: return "Non-Authoritative Information"; case 204: return "No Content"; case 205: return "Reset Content"; case 206: return "Partial Content"; case 207: return "Multi-Status"; /* 3XX redirect */ case 300: return "Multiple Choice"; case 301: return "Moved Permanently"; case 302: return "Found"; case 303: return "See Other"; case 304: return "Not Modified"; case 305: return "Use Proxy"; case 306: return "(reserved)"; case 307: return "Temporary Redirect"; /* 4XX client error */ case 400: return "Bad Request"; case 401: return "Unauthorized"; case 402: return "Payment Required"; case 403: return "Forbidden"; case 404: return "Not Found"; case 405: return "Method Not Allowed"; case 406: return "Not Acceptable"; case 407: return "Proxy Authentication Required"; case 408: return "Request Time-out"; case 409: return "Conflict"; case 410: return "Gone"; case 411: return "Length Required"; case 412: return "Precondition Failed"; case 413: return "Request Entity Too Large"; case 414: return "Request-URI Too Long"; case 415: return "Unsupported Media Type"; case 416: return "Request range not satisfiable"; case 417: return "Expectation Failed"; case 421: return "There are too many connections from your internet address"; case 422: return "Unprocessable Entity"; case 423: return "Locked"; case 424: return "Failed Dependency"; case 425: return "Unordered Collection"; case 426: return "Upgrade Required"; /* 5XX server error */ case 500: return "Internal Server Error"; case 501: return "Not Implemented"; case 502: return "Bad Gateway"; case 503: return "Service Unavailable"; case 504: return "Gateway Time-out"; case 505: return "HTTP Version not supported"; case 506: return "Variant Also Negotiates"; case 507: return "Insufficient Storage"; case 509: return "Bandwidth Limit Exceeded"; case 510: return "Not Extended"; /* unknown */ default: return "unknown status"; } } gchar counter_format(guint64 *count, guint factor) { gchar suffix = 0; 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'; } } } } } } return suffix; } gchar *ev_backend_string(guint backend) { switch (backend) { 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"; } }