Changeset 5881
- Timestamp:
- 03/20/10 00:10:03 (3 years ago)
- Location:
- luci2/zhttpd
- Files:
-
- 6 added
- 10 modified
-
env.c (modified) (3 diffs)
-
env.h (modified) (1 diff)
-
handler (added)
-
handler/cgi.c (added)
-
handler/file.c (added)
-
http.c (modified) (3 diffs)
-
http.h (modified) (2 diffs)
-
Makefile (modified) (1 diff)
-
request.c (modified) (4 diffs)
-
request.h (modified) (1 diff)
-
tcp.h (modified) (1 diff)
-
test (added)
-
test/localhost.crt (added)
-
test/localhost.key (added)
-
zhttpd.c (modified) (8 diffs)
-
zhttpd.h (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
luci2/zhttpd/env.c
r5858 r5881 18 18 } 19 19 20 const char* zhttpd_env_get(uhtbl_t *tbl, const char *key) { 20 unsigned int zhttpd_env_count(uhtbl_t *tbl) { 21 return tbl->used; 22 } 23 24 char* zhttpd_env_next(uhtbl_t *tbl, uint32_t *iter, const char **key) { 25 zhttpd_env_bucket_t *bucket = (zhttpd_env_bucket_t*)uhtbl_next(tbl, iter); 26 if (bucket) { 27 uhtbl_key((uhtbl_bucket_t*)bucket, (void**)key, NULL); 28 return bucket->value; 29 } else { 30 return NULL; 31 } 32 } 33 34 char* zhttpd_env_get(uhtbl_t *tbl, const char *key) { 21 35 zhttpd_env_bucket_t *bucket = 22 (zhttpd_env_bucket_t*)uhtbl_get(tbl, (const void*)key, strlen(key));36 (zhttpd_env_bucket_t*)uhtbl_get(tbl, key, strlen(key)); 23 37 return (bucket) ? bucket->value : NULL; 24 38 } … … 31 45 32 46 if (!(ekey = strdup(key)) || !(evalue = malloc(len + 1)) 33 || !(bucket = (zhttpd_env_bucket_t*)uhtbl_set(tbl, ekey, strlen( key)))) {47 || !(bucket = (zhttpd_env_bucket_t*)uhtbl_set(tbl, ekey, strlen(ekey)))) { 34 48 free(ekey); 35 49 free(evalue); … … 42 56 } 43 57 58 void zhttpd_env_clear_custom(uhtbl_t *tbl) { 59 uint32_t iter = 0; 60 uhtbl_bucket_t *bucket; 61 while ((bucket = uhtbl_next(tbl, &iter))) { 62 void *key; 63 long len; 64 uhtbl_key(bucket, &key, &len); 65 if (!strncmp((char*)key, "HTTP_", 5)) { 66 uhtbl_unset(tbl, key, len); 67 } 68 } 69 } 70 44 71 int zhttpd_env_set_int(uhtbl_t *tbl, const char *key, long long value) { 45 72 char buf[32]; -
luci2/zhttpd/env.h
r5830 r5881 11 11 12 12 int zhttpd_env_init(uhtbl_t *tbl, uint32_t sizehint); 13 c onst char* zhttpd_env_get(uhtbl_t *tbl, const char *key);13 char* zhttpd_env_get(uhtbl_t *tbl, const char *key); 14 14 int zhttpd_env_set 15 15 (uhtbl_t *tbl, const char *name, const char *value, size_t len); 16 16 int zhttpd_env_set_int(uhtbl_t *tbl, const char *key, long long value); 17 17 int zhttpd_env_unset(uhtbl_t *tbl, const char *key); 18 char* zhttpd_env_next(uhtbl_t *tbl, uint32_t *iter, const char **key); 19 unsigned int zhttpd_env_count(uhtbl_t *tbl); 20 void zhttpd_env_clear_custom(uhtbl_t *tbl); 18 21 19 22 -
luci2/zhttpd/http.c
r5858 r5881 1 #define _XOPEN_SOURCE 2 #define _SVID_SOURCE 1 3 #include <time.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <ctype.h> 2 7 #include "http.h" 3 8 4 9 static zhttpd_error_t errors[] = { 10 {ZHTTPD_STATUS_OK, "OK"}, 11 {ZHTTPD_STATUS_NOT_MODIFIED, "Not Modified"}, 12 {ZHTTPD_STATUS_TEMPORARY_REDIRECT, "Temporary Redirect"}, 5 13 {ZHTTPD_STATUS_BAD_REQUEST, "Bad Request"}, 6 14 {ZHTTPD_STATUS_FORBIDDEN, "Forbidden"}, 7 15 {ZHTTPD_STATUS_NOT_FOUND, "Not Found"}, 8 16 {ZHTTPD_STATUS_METHOD_NOT_ALLOWED, "Method Not Allowed"}, 17 {ZHTTPD_STATUS_LENGTH_REQUIRED, "Length Required"}, 18 {ZHTTPD_STATUS_REQUEST_ENTITY_TOO_LARGE, "Request Entity Too Large"}, 19 {ZHTTPD_STATUS_REQUEST_URI_TOO_LONG, "Request-URI Too Long"}, 20 {ZHTTPD_STATUS_INTERNAL_SERVER_ERROR, "Internal Server Error"}, 9 21 {0, NULL} 10 22 }; … … 19 31 } 20 32 33 int zhttpd_http_urldecode(char *url) { 34 char *c = url; 35 unsigned char *d; 36 char dec[3] = "00"; 37 while ((d = (unsigned char*)strchr(c, '%'))) { 38 if (!isxdigit(d[1]) || !isxdigit(d[2])) { 39 return -1; 40 } 41 dec[0] = d[1]; 42 dec[1] = d[2]; 43 *d = (unsigned char)strtol(dec, NULL, 16); 44 memmove(d + 1, &d[3], strlen((char*)&d[3]) + 1); 45 c = (char*)d + 1; 46 } 47 return 0; 48 } 49 21 50 int zhttpd_http_date(time_t timestamp, char *buffer, size_t size) { 22 51 if (!timestamp) { … … 27 56 return strftime(buffer, size, "%a, %d %h %Y %T GMT", &t); 28 57 } 58 59 time_t zhttpd_http_timestamp(char *buffer) { 60 struct tm t; 61 return (strptime(buffer, "%a, %d %h %Y %T GMT", &t)) ? timegm(&t) : 0; 62 } -
luci2/zhttpd/http.h
r5858 r5881 2 2 #define ERROR_H_ 3 3 4 4 #define ZHTTPD_STATUS_OK 200 5 #define ZHTTPD_STATUS_NOT_MODIFIED 304 6 #define ZHTTPD_STATUS_TEMPORARY_REDIRECT 307 5 7 #define ZHTTPD_STATUS_BAD_REQUEST 400 6 8 #define ZHTTPD_STATUS_FORBIDDEN 403 7 9 #define ZHTTPD_STATUS_NOT_FOUND 404 8 10 #define ZHTTPD_STATUS_METHOD_NOT_ALLOWED 405 9 11 #define ZHTTPD_STATUS_LENGTH_REQUIRED 411 12 #define ZHTTPD_STATUS_REQUEST_ENTITY_TOO_LARGE 413 13 #define ZHTTPD_STATUS_REQUEST_URI_TOO_LONG 414 14 #define ZHTTPD_STATUS_INTERNAL_SERVER_ERROR 500 10 15 11 16 typedef struct zhttpd_error { … … 16 21 const char* zhttpd_http_status(int code); 17 22 int zhttpd_http_date(const time_t timestamp, char *buffer, size_t size); 23 time_t zhttpd_http_timestamp(char *buffer); 24 int zhttpd_http_urldecode(char *url); 18 25 19 26 #endif /* ERROR_H_ */ -
luci2/zhttpd/Makefile
r5858 r5881 19 19 all: $(BINARY) 20 20 21 $(BINARY): *.c 21 $(BINARY): *.c handler/*.c 22 22 $(CC) $(CFLAGS) $(TLSCFLAGS) $(SFLAGS) $(WFLAGS) $(LDFLAGS) -I.. -o $@ $+ 23 23 -
luci2/zhttpd/request.c
r5858 r5881 10 10 #include "env.h" 11 11 12 static int zhttpd_request_headers(zthread_t *thread); 13 static int zhttpd_request_dispatch(zthread_t *thread); 14 12 15 int zhttpd_request_magic(zthread_t *thread) { 13 16 char buffer[4096]; … … 52 55 goto error; 53 56 } 57 req->size += c - buffer; 54 58 55 59 zhttpd_env_set(&req->env, "REQUEST_METHOD", method, strlen(method)); … … 62 66 } 63 67 68 char *query = strchr(url, '?'); 69 if (query) { 70 *query = 0; 71 if (zhttpd_http_urldecode(url)) { 72 goto error; 73 } 74 zhttpd_env_set(&req->env, "SCRIPT_NAME", url, query - url); 75 zhttpd_env_set(&req->env, "QUERY_STRING", query + 1, strlen(query + 1)); 76 } else { 77 zhttpd_env_set(&req->env, "SCRIPT_NAME", url, strlen(url)); 78 zhttpd_env_unset(&req->env, "QUERY_STRING"); 79 } 80 64 81 thread->state = zhttpd_request_headers; 65 return ZTHREAD_READY;82 return zhttpd_request_headers(thread); 66 83 error: 67 84 return zhttpd_request_error(thread, ZHTTPD_STATUS_BAD_REQUEST); 68 85 } 69 86 70 int zhttpd_request_headers(zthread_t *thread) { 71 return ZTHREAD_DONE; 72 } 73 74 int zhttpd_request_status(zthread_t *thread, int status) { 87 static int zhttpd_request_headers(zthread_t *thread) { 88 char buffer[4096] = "HTTP_"; 89 zhttpd_request_t *req = thread->context; 90 91 while (fgets(buffer + 5, sizeof(buffer) - 5, req->streamin)) { 92 char *c = buffer + 5, *key = buffer, *value; 93 if (!isalnum(*c)) { 94 if (*c == '\r' || *c == '\n') { 95 return zhttpd_request_dispatch(thread); 96 } else { 97 goto error; 98 } 99 } 100 for (; isalnum(*c) || *c == '-'; c++) { 101 *c = (*c == '-') ? '_' : toupper(*c); 102 } 103 if (*c == ':') { 104 *c++ = 0; 105 } else { 106 goto error; 107 } 108 for(; isblank(*c); c++); 109 value = c; 110 for (c = value + strlen(value) - 1; isspace(*c); c--); 111 112 if ((req->size += c - buffer) > zhttpd.reqhlimit) { 113 return zhttpd_request_error(thread, 114 ZHTTPD_STATUS_REQUEST_ENTITY_TOO_LARGE); 115 } 116 117 if (!strcmp(key, "HTTP_CONNECTION")) { 118 if (req->flags & ZHTTPD_FLAG_RECYCLE && strstr(value, "close")) { 119 req->flags &= ~ZHTTPD_FLAG_RECYCLE; 120 } else if (req->flags & ZHTTPD_FLAG_RECYCLE 121 && (strstr(value, "keep-alive") || strstr(value, "Keep-Alive"))) { 122 req->flags |= ZHTTPD_FLAG_RECYCLE; 123 } 124 } else if (!strncmp(key, "HTTP_CONTENT_", 13)) { 125 key = buffer + 5; 126 } 127 zhttpd_env_set(&req->env, key, value, 1 + (c - value)); 128 } 129 130 return (errno == EAGAIN) ? ZTHREAD_BLOCKED : ZTHREAD_DONE; 131 error: 132 return zhttpd_request_error(thread, ZHTTPD_STATUS_BAD_REQUEST); 133 } 134 135 static int zhttpd_request_dispatch(zthread_t *thread) { 136 zhttpd_request_t *req = thread->context; 137 char *url = zhttpd_env_get(&req->env, "SCRIPT_NAME"); 138 size_t size = 0, matchlen = 0, urllen = strlen(url); 139 140 zhttpd_vfs_t *vfs = NULL; 141 for (zhttpd_vfs_t *c = zhttpd.vfs; c; c = c->next) { 142 matchlen = c->patternlen - 1; 143 if (size < c->patternlen && urllen >= matchlen 144 && !memcmp(url, c->pattern, matchlen) 145 && (url[matchlen] == c->pattern[matchlen] || !url[matchlen])) { 146 vfs = c; 147 size = c->patternlen; 148 } 149 } 150 151 if (!vfs) { 152 return zhttpd_request_error(thread, ZHTTPD_STATUS_NOT_FOUND); 153 } else { 154 matchlen = size - 1; 155 if (urllen > matchlen) { 156 zhttpd_env_set(&req->env, "PATH_INFO", url + matchlen + 1, 157 urllen - matchlen - 1); 158 } else { 159 zhttpd_env_set(&req->env, "PATH_INFO", "", 1); 160 } 161 req->virtual = vfs; 162 thread->state = vfs->handler->entrypoint; 163 return ZTHREAD_READY; 164 } 165 } 166 167 int zhttpd_request_status(zthread_t *thread, int status, const char *msg) { 75 168 char date[32]; 76 169 zhttpd_request_t *req = thread->context; 77 const char *http = zhttpd_env_get(&req->env, " HTTP_VERSION");170 const char *http = zhttpd_env_get(&req->env, "SERVER_PROTOCOL"); 78 171 if (!http) { 79 172 http = "HTTP/1.0"; 80 173 } 174 const char *statusmsg = (msg) ? msg : zhttpd_http_status(status); 175 zhttpd_http_date(0, date, sizeof(date)); 176 if (req->flags & ZHTTPD_FLAG_RECYCLE) { 177 return fprintf(req->streamout, "%s %i %s\r\nServer: %s\r\nDate: %s\r\n" 178 "Connection: Keep-Alive\r\nKeep-Alive: timeout=%i\r\n", 179 http, status, statusmsg, ZHTTPD_COPYMARK, date, zhttpd.timeout); 180 } else { 181 return fprintf(req->streamout, 182 "%s %i %s\r\nServer: %s\r\nDate: %s\r\nConnection: close\r\n", 183 http, status, statusmsg, ZHTTPD_COPYMARK, date); 184 } 185 } 186 187 int zhttpd_request_simple(zthread_t *thread, int status) { 188 zhttpd_request_t *req = thread->context; 189 zhttpd_request_status(thread, status, NULL); 190 fputs("\r\n", req->streamout); 191 thread->state = zhttpd_request_recycle; 192 return zhttpd_request_recycle(thread); 193 } 194 195 int zhttpd_request_error(zthread_t *thread, int status) { 196 zhttpd_request_t *req = thread->context; 197 zhttpd_request_status(thread, status, NULL); 81 198 const char *statusmsg = zhttpd_http_status(status); 82 zhttpd_http_date(0, date, sizeof(date)); 83 return fprintf(req->streamout, "%s %i %s\r\nServer: %s\r\nDate: %s\r\n", 84 http, status, statusmsg, ZHTTPD_COPYMARK, date); 85 } 86 87 int zhttpd_request_error(zthread_t *thread, int status) { 88 zhttpd_request_t *req = thread->context; 89 zhttpd_request_status(thread, status); 90 const char *statusmsg = zhttpd_http_status(status); 91 fprintf(req->streamout, "Connection: close\r\nContent-Type: text/plain\r\n" 199 fprintf(req->streamout, "Content-Type: text/plain\r\n" 92 200 "Content-Length: %i\r\n\r\n%s\r\n", (int)strlen(statusmsg) + 2, statusmsg); 93 201 thread->state = zhttpd_request_recycle; 94 return ZTHREAD_READY;202 return zhttpd_request_recycle(thread); 95 203 } 96 204 … … 103 211 if (req->flags & ZHTTPD_FLAG_RECYCLE) { 104 212 req->flags &= ~ZHTTPD_FLAG_RECYCLE; 213 if (req->handlergc) { 214 req->handlergc(req->handlercontext); 215 } 216 req->handlercontext = NULL; 217 req->handlergc = NULL; 218 zhttpd_env_clear_custom(&req->env); 105 219 thread->state = zhttpd_request_magic; 106 220 return ZTHREAD_READY; -
luci2/zhttpd/request.h
r5858 r5881 7 7 int zhttpd_request_error(zthread_t *thread, int status); 8 8 int zhttpd_request_recycle(zthread_t *thread); 9 int zhttpd_request_headers(zthread_t *thread); 9 int zhttpd_request_simple(zthread_t *thread, int status); 10 int zhttpd_request_status(zthread_t *thread, int status, const char *msg); 10 11 11 12 #endif /* REQUEST_H_ */ -
luci2/zhttpd/tcp.h
r5858 r5881 26 26 const char *tlskey, const char *tlscert, int pem); 27 27 int zhttpd_tcp_shutdown(zthread_t *thread); 28 ssize_t zhttpd_tcp_sendfile(zhttpd_request_t *req, int fdin, size_t count); 28 29 29 30 #endif /* TCP_H_ */ -
luci2/zhttpd/zhttpd.c
r5858 r5881 6 6 #include <sys/epoll.h> 7 7 #include <sys/types.h> 8 #include <sys/wait.h> 8 9 #include <sys/stat.h> 9 10 #include <fcntl.h> … … 11 12 #include "zhttpd.h" 12 13 #include "tcp.h" 14 #include "env.h" 13 15 14 16 static volatile int running; … … 41 43 42 44 static void sighandler(int signal) { 43 if (signal == SIGHUP) { 44 running = 2; 45 } else { 46 running = 0; 45 switch (signal) { 46 case SIGCHLD: 47 while (waitpid(-1, NULL, WNOHANG) > 0); 48 49 case SIGPIPE: 50 return; 51 52 case SIGHUP: 53 running = 2; 54 55 default: 56 running = 0; 47 57 } 48 58 } 49 59 50 60 static void configure() { 61 zhttpd_env_init(&zhttpd.mime, 16); 62 63 zhttpd_env_set(&zhttpd.mime, "htm", ZHTTPD_LITERAL_PTRSIZE("text/html")); 64 zhttpd_env_set(&zhttpd.mime, "html", ZHTTPD_LITERAL_PTRSIZE("text/html")); 65 zhttpd_env_set(&zhttpd.mime, "css", ZHTTPD_LITERAL_PTRSIZE("text/css")); 66 zhttpd_env_set(&zhttpd.mime, "js", ZHTTPD_LITERAL_PTRSIZE("text/javascript")); 67 zhttpd_env_set(&zhttpd.mime, "xml", ZHTTPD_LITERAL_PTRSIZE("application/xml")); 68 zhttpd_env_set(&zhttpd.mime, "xsl", ZHTTPD_LITERAL_PTRSIZE("application/xml")); 69 zhttpd_env_set(&zhttpd.mime, "gif", ZHTTPD_LITERAL_PTRSIZE("image/gif")); 70 zhttpd_env_set(&zhttpd.mime, "png", ZHTTPD_LITERAL_PTRSIZE("image/png")); 71 zhttpd_env_set(&zhttpd.mime, "jpg", ZHTTPD_LITERAL_PTRSIZE("image/jpeg")); 72 zhttpd_env_set(&zhttpd.mime, "jpeg", ZHTTPD_LITERAL_PTRSIZE("image/jpeg")); 73 zhttpd_env_set(&zhttpd.mime, "svg", ZHTTPD_LITERAL_PTRSIZE("image/svg+xml")); 74 75 zhttpd_options_t opt3 = {.key = (char*)"virtual", .value=(char*)"/", .next=NULL}; 76 zhttpd_options_t opt2 = {.key = (char*)"physical", .value=(char*)"/tmp", .next=&opt3}; 77 zhttpd_options_t opt1 = {.key = (char*)"handler", .value=(char*)"file", .next=&opt2}; 78 zhttpd_vfs_mount(&opt1); 79 80 zhttpd_options_t opt13 = {.key = (char*)"virtual", .value=(char*)"/cgi-bin", .next=NULL}; 81 zhttpd_options_t opt12 = {.key = (char*)"physical", .value=(char*)"/tmp", .next=&opt13}; 82 zhttpd_options_t opt11 = {.key = (char*)"handler", .value=(char*)"cgi", .next=&opt12}; 83 zhttpd_vfs_mount(&opt11); 84 51 85 zhttpd.threads = 32; 52 86 zhttpd.timeout = 5; 53 87 zhttpd.daemonize = 0; 88 zhttpd.reqhlimit = 8192; 54 89 55 90 zhttpd.threadpool = zthread_create(zhttpd.threads); … … 65 100 close(zhttpd.epollfd); 66 101 zthread_destroy(zhttpd.threadpool); 102 uhtbl_finalize(&zhttpd.mime); 67 103 zhttpd_vfs_t *d = NULL; 68 104 for (zhttpd_vfs_t *c = zhttpd.vfs; c; c = d) { … … 97 133 sigaction(SIGINT, &action, NULL); 98 134 sigaction(SIGTERM, &action, NULL); 99 action.sa_handler = SIG_IGN;100 135 sigaction(SIGPIPE, &action, NULL); 136 sigaction(SIGCHLD, &action, NULL); 101 137 102 138 zhttpd.pidfile = "/var/run/zhttpd.pid"; … … 114 150 } 115 151 116 int zhttpd_vfs_mount(const char *point, zhttpd_options_t *options) { 152 int zhttpd_vfs_mount(zhttpd_options_t *options) { 153 const char *handlername = zhttpd_options_get(options, "handler"); 154 const char *point = zhttpd_options_get(options, "virtual"); 155 if (!handlername || !point) { 156 return ZHTTPD_EINVAL; 157 } 158 117 159 size_t pointlen = strlen(point); 118 const char *handlername = zhttpd_options_get(options, "handler");119 if (!handlername) {120 return ZHTTPD_EINVAL;121 }122 123 160 zhttpd_handler_t *handler = NULL; 124 161 for (zhttpd_handler_t *c = zhttpd.handler; c; c = c->next) { … … 146 183 mount->context = handler->vfs_context_create(options); 147 184 mount->next = zhttpd.vfs; 185 186 if (!mount->context) { 187 free(mount); 188 return ZHTTPD_EINVAL; 189 } 190 148 191 zhttpd.vfs = mount; 149 192 … … 152 195 153 196 const char* zhttpd_options_get(zhttpd_options_t *options, const char *key) { 154 size_t keylen = strlen(key);155 197 for (; options; options = options->next) { 156 if (!strcmp(key, options-> option) && options->option[keylen] == '=') {157 return &options->option[keylen + 1];198 if (!strcmp(key, options->key)) { 199 return options->value; 158 200 } 159 201 } -
luci2/zhttpd/zhttpd.h
r5858 r5881 36 36 struct zhttpd_options { 37 37 zhttpd_options_t *next; 38 char option[]; 38 char *key; 39 char *value; 39 40 }; 40 41 … … 42 43 int flags; 43 44 int fd; 45 int size; 44 46 void *ioctx; 45 47 uhtbl_t env; … … 62 64 zhttpd_handler_t *next; 63 65 zthread_state_t *entrypoint; 64 zthread_state_t *cleanup;65 66 void* (*vfs_context_create)(zhttpd_options_t*); 66 67 void (*vfs_context_destroy)(void*); 67 char name[];68 char *name; 68 69 }; 69 70 … … 72 73 zthread_context_t *threadpool; 73 74 zhttpd_handler_t *handler; 75 uhtbl_t mime; 74 76 int epollfd; 75 77 int timeout; 76 78 int threads; 77 79 int daemonize; 80 int reqhlimit; 78 81 char *pidfile; 79 82 }; 80 83 81 #define ZHTTPD_REGISTER(handler) __attribute__((constructor (5))) \ 82 void __zhttpd_register() { zhttpd_register(handler); } 84 #define ZHTTPD_HANDLER_REGISTER(name, handler) \ 85 void __attribute__ ((constructor)) name##start(void) { \ 86 handler.next = zhttpd.handler; \ 87 zhttpd.handler = &handler; \ 88 } 89 90 #define ZHTTPD_LITERAL_PTRSIZE(x) x, (sizeof(x) - 1) 83 91 84 92 extern zhttpd_context_t zhttpd; 85 93 94 void zhttpd_register(zhttpd_handler_t *handler); 95 int zhttpd_vfs_mount(zhttpd_options_t *options); 86 96 const char* zhttpd_options_get(zhttpd_options_t *options, const char *key); 87 97
