Annotation of embedaddon/libpdel/http/test/main.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/stat.h>
42: #include <sys/param.h>
43:
44: #include <stdio.h>
45: #include <stdlib.h>
46: #include <signal.h>
47: #include <stdarg.h>
48: #include <string.h>
49: #include <unistd.h>
50: #include <errno.h>
51: #include <assert.h>
52: #include <netdb.h>
53: #include <err.h>
54: #include <regex.h>
55: #include <pthread.h>
56:
57: #include <netinet/in_systm.h>
58: #include <netinet/in.h>
59: #include <arpa/inet.h>
60:
61: #include <openssl/ssl.h>
62:
63: #include <pdel/structs/structs.h>
64: #include <pdel/structs/type/array.h>
65:
66: #include <pdel/tmpl/tmpl.h>
67: #include <pdel/util/typed_mem.h>
68: #include <pdel/util/pevent.h>
69:
70: #include <pdel/http/http_defs.h>
71: #include <pdel/http/http_server.h>
72: #include <pdel/http/http_servlet.h>
73: #include <pdel/http/servlet/tmpl.h>
74: #include <pdel/http/servlet/file.h>
75: #include <pdel/http/servlet/basicauth.h>
76: #include <pdel/http/servlet/redirect.h>
77: #include <pdel/http/servlet/cookieauth.h>
78:
79: #define DEMO_MEM_TYPE "demo"
80: #define DEMO_COOKIE_NAME "demo_cookie"
81: #define TMPL_MEM_TYPE "tmpl"
82: #define NUM_IN_CACHE 2
83: #define CACHE_TIMEOUT_SECS 10
84: #define NUM_CACHE_LOOP 10
85: #define PATH_KERNEL "/kernel"
86:
87: #ifndef MIN
88: #define MIN(a, b) ((a) > (b) ? (a) : (b))
89: #endif
90:
91: /*
92: * Servlets
93: */
94: static struct http_servlet *demo_servlet_create(void);
95: static struct http_servlet *cgi_servlet_create(void);
96: static struct http_servlet *getkernel_servlet_create(void);
97:
98: /*
99: * Internal functions
100: */
101:
102: static http_logger_t demo_logger;
103:
104: static tmpl_handler_t demo_tmpl_handler;
105: static tmpl_errfmtr_t demo_tmpl_errfmtr;
106:
107: static http_servlet_basicauth_t demo_basicauth;
108:
109: static http_servlet_cookieauth_reqd_t demo_auth_reqd;
110:
111: static void demo_file_upload(struct http_request *req,
112: struct http_response *resp, FILE *op);
113: static int demo_client(struct pevent_ctx *ctx, int nurls,
114: char **urls, int count);
115:
116: /* SSL typed_mem(3) wrappers */
117: static void *ssl_malloc(size_t size);
118: static void *ssl_realloc(void *mem, size_t size);
119: static void ssl_free(void *mem);
120:
121: static void usage(void);
122:
123: /*
124: * Internal variables
125: */
126:
127: /* SSL info */
128: static const struct http_server_ssl ssl_info = {
129: "demo.crt", /* SSL x509 certificate file */
130: "demo.key", /* SSL RSA private key file */
131: NULL /* no password for private key needed */
132: };
133:
134: static const char *redirect_url;
135: static const struct in_addr zero_ip;
136: static pid_t main_pid;
137:
138: static const u_char demo_id[] = { 'd', 'e', 'm', 'o' };
139:
140: static const char *vhost = NULL;
141: static const struct http_server_ssl *ssl = NULL;
142: static int port = 0;
143:
144: static struct http_servlet *cookieauth_servlet;
145:
146: /* Info for "demo.tmpl" template servlet */
147: static struct http_servlet_tmpl_info tmpl_servlet_info = {
148: "demo.tmpl", /* pathname of template file */
149: NULL, /* guess the mime type for me */
150: NULL, /* guess the mime encoding for me */
151: demo_logger, /* error logging routine */
152: { /* info required by tmpl library */
153: TMPL_SKIP_NL_WHITE, /* flags for tmpl_execute() */
154: TMPL_MEM_TYPE, /* tmpl string typed mem type */
155: demo_tmpl_handler, /* handler for custom @funcs */
156: demo_tmpl_errfmtr, /* handler for errors */
157: NULL, /* opaque user cookie */
158: }
159: };
160:
161: /* Info for "logon.tmpl" template servlet */
162: static struct http_servlet_tmpl_info logon_servlet_info = {
163: "logon.tmpl", /* pathname of template file */
164: NULL, /* guess the mime type for me */
165: NULL, /* guess the mime encoding for me */
166: demo_logger, /* error logging routine */
167: { /* info required by tmpl library */
168: TMPL_SKIP_NL_WHITE, /* flags for tmpl_execute() */
169: TMPL_MEM_TYPE, /* tmpl string typed mem type */
170: demo_tmpl_handler, /* handler for custom @funcs */
171: demo_tmpl_errfmtr, /* handler for errors */
172: NULL, /* opaque user cookie */
173: }
174: };
175:
176: /* Info for "vhost.tmpl" template servlet */
177: static struct http_servlet_tmpl_info vhost_servlet_info = {
178: "vhost.tmpl", /* pathname of template file */
179: NULL, /* guess the mime type for me */
180: NULL, /* guess the mime encoding for me */
181: demo_logger, /* error logging routine */
182: { /* info required by tmpl library */
183: TMPL_SKIP_NL_WHITE, /* flags for tmpl_execute() */
184: TMPL_MEM_TYPE, /* tmpl string typed mem type */
185: demo_tmpl_handler, /* handler for custom @funcs */
186: demo_tmpl_errfmtr, /* handler for errors */
187: NULL, /* opaque user cookie */
188: }
189: };
190:
191: /* Info for BIND docs file servlet */
192: static struct http_servlet_file_info bind_servlet_info = {
193: "/usr/share/doc/bind/html", /* document root for this servlet */
194: 0, /* don't allow escape from docroot */
195: NULL, /* derive filename from URL */
196: "/file", /* URL prefix to strip from pathname */
197: NULL, /* guess the mime type for me */
198: NULL, /* guess the mime encoding for me */
199: demo_logger, /* error logging routine */
200: NULL, /* don't hide any files */
201: { } /* don't support templates */
202: };
203:
204: /*
205: * Start a HTTP server.
206: */
207: int
208: main(int argc, char **argv)
209: {
210: struct pevent_ctx *ctx;
211: char hostname[255] = { '\0' };
212: struct http_servlet *servlet;
213: struct http_server *server;
214: int do_client = 0;
215: sigset_t sigs;
216: int count = 1;
217: int sig;
218: int ret;
219: int ch;
220:
221: /* Parse command line arguments */
222: while ((ch = getopt(argc, argv, "sp:c:r:h:v:")) != -1) {
223: switch (ch) {
224: case 'c':
225: count = atoi(optarg);
226: break;
227: case 'h':
228: snprintf(hostname, sizeof(hostname), "%s", optarg);
229: break;
230: case 's':
231: ssl = &ssl_info;
232: break;
233: case 'p':
234: port = atoi(optarg);
235: break;
236: case 'r':
237: redirect_url = optarg;
238: break;
239: case 'v':
240: vhost = optarg;
241: break;
242: default:
243: usage();
244: }
245: }
246: argc -= optind;
247: argv += optind;
248: switch (argc) {
249: default:
250: do_client = 1;
251: break;
252: case 0:
253: break;
254: }
255: if (port == 0)
256: port = (ssl != NULL) ? 443 : 80;
257: if (*hostname == '\0') {
258: if (gethostname(hostname, sizeof(hostname)) == -1)
259: err(1, "gethostname");
260: hostname[sizeof(hostname) - 1] = '\0';
261: }
262:
263: /* Make OpenSSL use our malloc/free wrappers */
264: if (ssl != NULL) {
265: ret = CRYPTO_set_mem_functions(ssl_malloc,
266: ssl_realloc, ssl_free);
267: assert(ret);
268: ret = CRYPTO_set_locked_mem_functions(ssl_malloc, ssl_free);
269: assert(ret);
270: }
271: main_pid = getpid();
272:
273: /* Enable typed memory */
274: if (typed_mem_enable() == -1)
275: err(1, "typed_mem_enable");
276:
277: /* Block SIGPIPE */
278: (void)signal(SIGPIPE, SIG_IGN);
279:
280: /* Get event context */
281: if ((ctx = pevent_ctx_create("demo_server.ctx", NULL)) == NULL)
282: err(1, "pevent_ctx_create");
283:
284: /* If client mode, do that */
285: if (do_client) {
286: demo_client(ctx, argc, argv, count);
287: goto shutdown;
288: }
289:
290: /* Start HTTP server */
291: printf("demo_server: starting http server on port %d, SSL %sabled\n",
292: port, ssl ? "en" : "dis");
293: if ((server = http_server_start(ctx, zero_ip,
294: port, ssl, "Demo/1.0", demo_logger)) == NULL)
295: err(1, "http_server_start");
296:
297: /* Register default virtual host servlet if vhost defined */
298: if (vhost != NULL) {
299: /* Register "vhost.tmpl" servlet */
300: if ((servlet = http_servlet_tmpl_create(
301: &vhost_servlet_info)) == NULL)
302: err(1, "http_servlet_tmpl_create");
303: if (http_server_register_servlet(server,
304: servlet, NULL, "^/", 0) == -1)
305: err(1, "http_server_register_servlet");
306: }
307:
308: /* Register redirect servlet */
309: if (redirect_url != NULL) {
310: if ((servlet = http_servlet_redirect_create(redirect_url,
311: HTTP_SERVLET_REDIRECT_NO_APPEND)) == NULL)
312: err(1, "redirect_servlet_create");
313: if (http_server_register_servlet(server,
314: servlet, vhost, "^/redirect", 0) == -1)
315: err(1, "http_server_register_servlet");
316: }
317:
318: /* Register cookie auth servlet */
319: {
320: char logurl[128];
321:
322: if ((ssl && port == 443) || (!ssl && port == 80)) {
323: snprintf(logurl, sizeof(logurl),
324: "http%s://%s/logon", ssl ? "s" : "", hostname);
325: } else {
326: snprintf(logurl, sizeof(logurl),
327: "http%s://%s:%u/logon", ssl ? "s" : "",
328: hostname, port);
329: }
330: if ((cookieauth_servlet = http_servlet_cookieauth_create(
331: logurl, HTTP_SERVLET_REDIRECT_APPEND_URL,
332: demo_auth_reqd, NULL, NULL, "demo.key", demo_id,
333: sizeof(demo_id), DEMO_COOKIE_NAME)) == NULL)
334: err(1, "http_servlet_cookieauth_create");
335: if (http_server_register_servlet(server,
336: cookieauth_servlet, vhost, "^/.*", -20) == -1)
337: err(1, "http_server_register_servlet");
338: }
339:
340: /* Register logon page */
341: if ((servlet = http_servlet_tmpl_create(&logon_servlet_info)) == NULL)
342: err(1, "http_servlet_tmpl_create");
343: if (http_server_register_servlet(server,
344: servlet, vhost, "^/logon$", 0) == -1)
345: err(1, "http_server_register_servlet");
346:
347: /* Register demo servlet */
348: if ((servlet = demo_servlet_create()) == NULL)
349: err(1, "demo_servlet_create");
350: if (http_server_register_servlet(server,
351: servlet, vhost, "^/$", 0) == -1)
352: err(1, "http_server_register_servlet");
353:
354: /* Register "demo.tmpl" servlet */
355: if ((servlet = http_servlet_tmpl_create(&tmpl_servlet_info)) == NULL)
356: err(1, "http_servlet_tmpl_create");
357: if (http_server_register_servlet(server,
358: servlet, vhost, "^/tmpl$", 0) == -1)
359: err(1, "http_server_register_servlet");
360:
361: /* Register authorization servlet */
362: if ((servlet = http_servlet_basicauth_create(
363: demo_basicauth, NULL, NULL)) == NULL)
364: err(1, "http_servlet_basicauth_create");
365: if (http_server_register_servlet(server,
366: servlet, vhost, "^/[^l].*$", -10) == -1)
367: err(1, "http_server_register_servlet");
368:
369: /* Register BIND docs servlet */
370: if ((servlet = http_servlet_file_create(&bind_servlet_info)) == NULL)
371: err(1, "http_servlet_file_create");
372: if (http_server_register_servlet(server,
373: servlet, vhost, "^/file", 0) == -1)
374: err(1, "http_server_register_servlet");
375:
376: /* Register CGI servlet, at two different URLs */
377: if ((servlet = cgi_servlet_create()) == NULL)
378: err(1, "cgi_servlet_create");
379: if (http_server_register_servlet(server,
380: servlet, vhost, "^/cgi/get$", 0) == -1)
381: err(1, "http_server_register_servlet");
382: if ((servlet = cgi_servlet_create()) == NULL)
383: err(1, "cgi_servlet_create");
384: if (http_server_register_servlet(server,
385: servlet, vhost, "^/cgi/post$", 0) == -1)
386: err(1, "http_server_register_servlet");
387:
388: /* Register kernel servlet */
389: if ((servlet = getkernel_servlet_create()) == NULL)
390: err(1, "getkernel_servlet_create");
391: if (http_server_register_servlet(server,
392: servlet, vhost, "^/kernel", 0) == -1)
393: err(1, "http_server_register_servlet");
394:
395: /* Wait for interrupt */
396: sigemptyset(&sigs);
397: sigaddset(&sigs, SIGINT);
398: sigaddset(&sigs, SIGTERM);
399: if (sigprocmask(SIG_BLOCK, &sigs, NULL) == -1)
400: err(1, "sigprocmask");
401: if (sigwait(&sigs, &sig) == -1)
402: err(1, "sigwait");
403:
404: /* Shut down server */
405: printf("Rec'd signal %d, shutting down http server...\n", sig);
406: http_server_stop(&server);
407:
408: shutdown:
409: /* Destroy event context */
410: pevent_ctx_destroy(&ctx);
411: usleep(100000);
412:
413: /* Done */
414: printf("Done. Displaying unfreed memory...\n");
415:
416: /* Show memory usage */
417: typed_mem_dump(stdout);
418: return (0);
419: }
420:
421: /***********************************************************************
422: SUPPORT ROUTINES
423: ***********************************************************************/
424:
425: /*
426: * Do client loop
427: */
428: static int
429: demo_client(struct pevent_ctx *ctx, int nurls, char **urls, int count)
430: {
431: struct http_client *client;
432: struct hostent *hent;
433: struct in_addr ip;
434: char buf[256];
435: regex_t reg;
436: int i, j;
437: int r;
438:
439: /* Compile URL pattern */
440: if ((r = regcomp(®,
441: "^(http|https)://([-.[:alnum:]]+)(:[[:digit:]]+)?(/.*)?$",
442: REG_EXTENDED)) != 0) {
443: regerror(r, ®, buf, sizeof(buf));
444: errx(1, "invalid URL pattern: %s", buf);
445: }
446:
447: /* Create client */
448: if ((client = http_client_create(ctx, "DemoClient/1.0",
449: 5, 3, 7, demo_logger)) == NULL)
450: err(1, "http_client_create");
451:
452: printf("Fetching %d URLs %d times...\n", nurls, count);
453: for (i = 0; i < count; i++) {
454: for (j = 0; j < nurls; j++) {
455: const char *const url = urls[j];
456: struct http_client_connection *cc;
457: struct http_request *req;
458: struct http_response *resp;
459: regmatch_t match[5];
460: char host[256];
461: char path[256];
462: int https = 0;
463: int port;
464:
465: /* Parse URL */
466: if ((r = regexec(®, url, sizeof(match) / sizeof(*match),
467: match, 0)) != 0) {
468: regerror(r, ®, buf, sizeof(buf));
469: errx(1, "invalid URL \"%s\": %s", url, buf);
470: }
471: if (match[1].rm_eo - match[1].rm_so == 4)
472: port = 80;
473: else {
474: port = 443;
475: https = 1;
476: }
477: if (match[3].rm_so != match[3].rm_eo) {
478: strncpy(buf, url + match[3].rm_so, sizeof(buf) - 1);
479: buf[sizeof(buf) - 1] = '\0';
480: if ((port = strtoul(buf + 1, NULL, 10)) == 0)
481: errx(1, "invalid port");
482: }
483: memset(&host, 0, sizeof(host));
484: strncpy(host, url + match[2].rm_so,
485: MIN(sizeof(host) - 1, (match[2].rm_eo - match[2].rm_so)));
486: if (match[4].rm_so != match[4].rm_eo) {
487: memset(&path, 0, sizeof(path));
488: strncpy(path, url + match[4].rm_so,
489: MIN(sizeof(path) - 1, (match[4].rm_eo
490: - match[4].rm_so)));
491: } else
492: strcpy(path, "/");
493: if (!inet_aton(host, &ip)) {
494: if ((hent = gethostbyname(host)) == NULL)
495: err(1, "%s: %s", host, hstrerror(h_errno));
496: ip = *((struct in_addr **)hent->h_addr_list)[0];
497: }
498: printf("\nFetching %s://%s:%d%s\n", https ? "https" : "http",
499: host, port, path);
500:
501: /* Create/get client connection */
502: if ((cc = http_client_connect(client, ip, port, https)) == NULL)
503: err(1, "http_client_connect");
504:
505: /* Set up request */
506: req = http_client_get_request(cc);
507: if (http_request_set_method(req, "GET") == -1)
508: err(1, "http_request_set_method");
509: if (http_request_set_path(req, path) == -1)
510: err(1, "%s(%s)", "http_request_set_path", path);
511: if (http_request_set_header(req, 0,
512: HTTP_HEADER_HOST, "%s:%u", host, port) == -1)
513: err(1, "http_request_set_header");
514:
515: /* Send request */
516: if ((resp = http_client_get_response(cc)) == NULL)
517: printf("Error: %s\n", http_client_get_reason(cc));
518: else {
519: FILE *fp;
520: int ch;
521: int lnum;
522:
523: printf("********** RESPONSE (first 20 lines): %d %s\n",
524: http_response_get_code(resp),
525: http_response_get_header(resp, HDR_REPLY_REASON));
526: if ((fp = http_response_get_input(resp)) == NULL)
527: err(1, "http_response_get_input");
528: for (lnum = 0; (ch = getc(fp)) != EOF; ) {
529: putchar(ch);
530: if (ch == '\n') {
531: if (++lnum == 20)
532: break;
533: }
534: }
535: printf("*********************************\n\n\n");
536: }
537:
538: /* Release client connection */
539: http_client_close(&cc);
540:
541: /* Pause */
542: sleep(1);
543: }
544: }
545:
546: /* Release client */
547: if (http_client_destroy(&client) == -1)
548: err(1, "http_client_free");
549: regfree(®);
550: return (0);
551: }
552:
553: /*
554: * Demo CGI file upload handler
555: */
556: static void
557: demo_file_upload(struct http_request *req, struct http_response *resp, FILE *fp)
558: {
559: static const char *hr = "-----------------------------------------\n";
560: struct mime_multipart *mp;
561: u_int count;
562: int i;
563:
564: /* Read multipart MIME */
565: if ((mp = http_request_read_mime_multipart(req)) == NULL) {
566: http_response_send_error(resp,
567: HTTP_STATUS_INTERNAL_SERVER_ERROR,
568: "Can't read multi-part MIME input: %s", strerror(errno));
569: return;
570: }
571:
572: /* Display parts */
573: count = http_mime_multipart_get_count(mp);
574: fprintf(fp, "Read %d parts:\n\n", count);
575: fprintf(fp, "%s", hr);
576: for (i = 0; i < count; i++) {
577: struct mime_part *const part
578: = http_mime_multipart_get_part(mp, i);
579: u_char *const data = http_mime_part_get_data(part);
580: const u_int dlen = http_mime_part_get_length(part);
581: const char *const cd = http_mime_part_get_header(part,
582: HTTP_HEADER_CONTENT_DISPOSITION);
583:
584: fprintf(fp, "PART #%u: %u bytes\n%s: %s\n%s",
585: i + 1, dlen, HTTP_HEADER_CONTENT_DISPOSITION,
586: cd == NULL ? "<< NONE >>" : cd, hr);
587: fwrite(data, 1, dlen, fp);
588: fprintf(fp, "\n%s", hr);
589: }
590:
591: /* Free multipart data */
592: http_mime_multipart_free(&mp);
593: }
594:
595: /*
596: * Exit after printing usage string
597: */
598: static void
599: usage(void)
600: {
601: (void)fprintf(stderr,
602: "Usage: demo_server [-s] [-p port] [-c count]\n"
603: "\t[-r redirect url] [-h hostname] [-v virtual-host] [url ...]\n");
604: exit(1);
605: }
606:
607: /***********************************************************************
608: HTTP CALLBACKS
609: ***********************************************************************/
610:
611: /*
612: * Logger for the HTTP server.
613: */
614: static void
615: demo_logger(int sev, const char *fmt, ...)
616: {
617: static char buf[512];
618: va_list args;
619:
620: snprintf(buf, sizeof(buf), "http_server: %s", fmt);
621: va_start(args, fmt);
622: vfprintf(stderr, buf, args);
623: fprintf(stderr, "\n");
624: va_end(args);
625: }
626:
627: /***********************************************************************
628: AUTHORIZOR SERVLETS
629: ***********************************************************************/
630:
631: static int
632: demo_auth_reqd(void *arg, struct http_request *req)
633: {
634: const char *path = http_request_get_path(req);
635:
636: return (strcmp(path, "/logon") != 0);
637: }
638:
639: static const char *
640: demo_basicauth(void *arg, struct http_request *req,
641: const char *username, const char *password)
642: {
643: if (strcmp(username, "demo") != 0 || strcmp(password, "demo") != 0)
644: return ("HTTP Server Demo");
645: return (NULL);
646: }
647:
648: /***********************************************************************
649: DEMO SERVLET
650: ***********************************************************************/
651:
652: static http_servlet_run_t demo_servlet_run;
653: static http_servlet_destroy_t demo_servlet_destroy;
654:
655: /*
656: * Demo servlet
657: */
658: static struct http_servlet *
659: demo_servlet_create(void)
660: {
661: struct http_servlet *servlet;
662:
663: if ((servlet = MALLOC(DEMO_MEM_TYPE, sizeof(*servlet))) == NULL)
664: return (NULL);
665: memset(servlet, 0, sizeof(*servlet));
666: servlet->run = demo_servlet_run;
667: servlet->destroy = demo_servlet_destroy;
668: return (servlet);
669: }
670:
671: static int
672: demo_servlet_run(struct http_servlet *servlet,
673: struct http_request *req, struct http_response *resp)
674: {
675: const time_t now = time(NULL);
676: char buf[32];
677: FILE *fp;
678: char *u;
679:
680: /* Get output stream */
681: if ((fp = http_response_get_output(resp, 1)) == NULL) {
682: http_response_send_error(resp,
683: HTTP_STATUS_INTERNAL_SERVER_ERROR,
684: "Can't get output stream");
685: return (1);
686: }
687:
688: /* Set content type */
689: http_response_set_header(resp, 0,
690: HTTP_HEADER_CONTENT_TYPE, "text/html");
691:
692: /* Tell browser not to cache me */
693: http_response_set_header(resp, 1, HTTP_HEADER_PRAGMA, "no-cache");
694: http_response_set_header(resp, 0,
695: HTTP_HEADER_CACHE_CONTROL, "no-cache");
696:
697: /* Send some output */
698: fprintf(fp, "<html><head><title>Demo Servlet</title></head>\n");
699: fprintf(fp, "<body bgcolor=\"#ffffff\">\n");
700: fprintf(fp, "<h3>Demo Servlet in C</h3>\n");
701: fprintf(fp, "This servlet is implemented directly in C code.\n");
702: fprintf(fp, "See http_servlet(3) for details.\n<br>\n");
703: fprintf(fp, "<p>The time is <code>%s</code>\n", ctime_r(&now, buf));
704: if ((u = http_servlet_cookieauth_user("demo.key", demo_id,
705: sizeof(demo_id), DEMO_COOKIE_NAME, req, TYPED_MEM_TEMP)) == NULL) {
706: if (errno == EACCES)
707: u = STRDUP(TYPED_MEM_TEMP, "(nobody)");
708: }
709: if (u != NULL) {
710: fprintf(fp, "<p>You are logged on as <b>%s</b>.", u);
711: FREE(TYPED_MEM_TEMP, u);
712: } else
713: fprintf(fp, "<p><b>Error with user: %s</b>.", strerror(errno));
714: fprintf(fp, "<p>Click <a href=\"tmpl\">HERE</a>"
715: " for tmpl servlet demo (login as <b>demo</b>"
716: " password <b>demo</b>)\n");
717: fprintf(fp, "</body></html>\n");
718: fclose(fp);
719: return (1);
720: }
721:
722: static void
723: demo_servlet_destroy(struct http_servlet *servlet)
724: {
725: FREE(DEMO_MEM_TYPE, servlet);
726: }
727:
728: /***********************************************************************
729: KERNEL SERVLET
730: ***********************************************************************/
731:
732: static http_servlet_run_t getkernel_servlet_run;
733: static http_servlet_destroy_t getkernel_servlet_destroy;
734:
735: /*
736: * Kernel servlet
737: */
738: static struct http_servlet *
739: getkernel_servlet_create(void)
740: {
741: struct http_servlet *servlet;
742:
743: if ((servlet = MALLOC(DEMO_MEM_TYPE, sizeof(*servlet))) == NULL)
744: return (NULL);
745: memset(servlet, 0, sizeof(*servlet));
746: servlet->run = getkernel_servlet_run;
747: servlet->destroy = getkernel_servlet_destroy;
748: return (servlet);
749: }
750:
751: static int
752: getkernel_servlet_run(struct http_servlet *servlet,
753: struct http_request *req, struct http_response *resp)
754: {
755: struct stat sb;
756: time_t timestamp;
757: char date[64];
758: struct tm tm;
759:
760: /* Make this "web page" not cachable */
761: http_response_set_header(resp, 1, HTTP_HEADER_PRAGMA, "no-cache");
762: http_response_set_header(resp, 0,
763: HTTP_HEADER_CACHE_CONTROL, "no-cache");
764:
765: /* Get timestamp of kernel file */
766: if (stat(PATH_KERNEL, &sb) != -1)
767: timestamp = sb.st_mtime;
768: else
769: timestamp = time(NULL); /* ok because servlet will fail too */
770:
771: /* Set MIME type */
772: http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE,
773: "application/octet-stream");
774:
775: /* Set filename (via Content-Disposition) based on date */
776: strftime(date, sizeof(date), "%Y-%m-%d", localtime_r(×tamp, &tm));
777: http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_DISPOSITION,
778: "application/octet-stream; filename=\"kernel-%s\"", date);
779:
780: /* Piggy-back off of file servlet routine */
781: http_servlet_file_serve(PATH_KERNEL, demo_logger, req, resp);
782: return (1);
783: }
784:
785: static void
786: getkernel_servlet_destroy(struct http_servlet *servlet)
787: {
788: FREE(DEMO_MEM_TYPE, servlet);
789: }
790:
791: /***********************************************************************
792: CGI SERVLET
793: ***********************************************************************/
794:
795: static http_servlet_run_t cgi_servlet_run;
796: static http_servlet_destroy_t cgi_servlet_destroy;
797:
798: /*
799: * Demo CGI
800: */
801: static struct http_servlet *
802: cgi_servlet_create(void)
803: {
804: struct http_servlet *servlet;
805:
806: if ((servlet = MALLOC(DEMO_MEM_TYPE, sizeof(*servlet))) == NULL)
807: return (NULL);
808: memset(servlet, 0, sizeof(*servlet));
809: servlet->run = cgi_servlet_run;
810: servlet->destroy = cgi_servlet_destroy;
811: return (servlet);
812: }
813:
814: static int
815: cgi_servlet_run(struct http_servlet *servlet,
816: struct http_request *req, struct http_response *resp)
817: {
818: FILE *fp;
819: int i;
820:
821: /* Set no cache */
822: http_response_set_header(resp, 1, "Pragma", "no-cache");
823: http_response_set_header(resp, 0, "Cache-Control", "no-cache");
824:
825: /* Set MIME type */
826: http_response_set_header(resp, 0,
827: HTTP_HEADER_CONTENT_TYPE, "text/plain; charset=iso-8859-1");
828:
829: /* Get output stream */
830: if ((fp = http_response_get_output(resp, 0)) == NULL) {
831: http_response_send_error(resp,
832: HTTP_STATUS_INTERNAL_SERVER_ERROR,
833: "Can't get output stream");
834: return (1);
835: }
836:
837: /* For POST, read and decode input */
838: if (strcmp(http_request_get_method(req), "POST") == 0) {
839: const char *hval;
840: const char *s;
841: int nval;
842:
843: /* Check type of encoding */
844: if ((hval = http_request_get_header(req,
845: HTTP_HEADER_CONTENT_TYPE)) == NULL) {
846: http_response_send_error(resp,
847: HTTP_STATUS_INTERNAL_SERVER_ERROR,
848: "Missing %s header", HTTP_HEADER_CONTENT_TYPE);
849: return (1);
850: }
851:
852: /* Special case form file upload */
853: if ((s = strchr(hval, ';')) != NULL
854: && strncasecmp(hval,
855: HTTP_CTYPE_MULTIPART_FORMDATA, s - hval) == 0) {
856: demo_file_upload(req, resp, fp);
857: return (1);
858: }
859:
860: /* Must be POST form data */
861: if (strcasecmp(hval, HTTP_CTYPE_FORM_URLENCODED) != 0) {
862: http_response_send_error(resp,
863: HTTP_STATUS_INTERNAL_SERVER_ERROR,
864: "Weird content-type \"%s\"", hval);
865: return (1);
866: }
867:
868: /* Read POST form data */
869: if ((nval = http_request_read_url_encoded_values(req)) == -1) {
870: http_response_send_error(resp,
871: HTTP_STATUS_INTERNAL_SERVER_ERROR,
872: "Can't read POST input");
873: return (1);
874: }
875: fprintf(fp, "Read %d values from input\n", nval);
876: }
877:
878: /* Get fields and display them */
879: for (i = 1; 1; i++) {
880: const char *value;
881: char fname[32];
882:
883: snprintf(fname, sizeof(fname), "field%d", i);
884: fprintf(fp, "FIELD \"%s\": ", fname);
885: if ((value = http_request_get_value(req, fname, 0)) == NULL) {
886: fprintf(fp, "<< NOT FOUND >>\n");
887: break;
888: } else
889: fprintf(fp, "value=\"%s\"\n", value);
890: }
891: return (1);
892: }
893:
894: static void
895: cgi_servlet_destroy(struct http_servlet *servlet)
896: {
897: FREE(DEMO_MEM_TYPE, servlet);
898: }
899:
900: /***********************************************************************
901: TMPL USER FUNCTIONS
902: ***********************************************************************/
903:
904: static tmpl_handler_t authname_handler;
905: static tmpl_handler_t authorize_handler;
906: static tmpl_handler_t date_handler;
907: static tmpl_handler_t get_header_handler;
908: static tmpl_handler_t get_port_handler;
909: static tmpl_handler_t get_ssl_handler;
910: static tmpl_handler_t query_handler;
911: static tmpl_handler_t query_string_handler;
912: static tmpl_handler_t redirect_handler;
913: static tmpl_handler_t remote_ip_handler;
914: static tmpl_handler_t remote_port_handler;
915: static tmpl_handler_t shutdown_handler;
916: static tmpl_handler_t sleep_handler;
917: static tmpl_handler_t vhost_handler;
918:
919: static const struct tmpl_func demo_tmpl_funcs[] = {
920: { "authname", 0, 0, authname_handler },
921: { "authorize", 0, 2, authorize_handler },
922: { "date", 0, 0, date_handler },
923: { "get_header", 1, 1, get_header_handler },
924: { "get_port", 0, 0, get_port_handler },
925: { "get_ssl", 0, 0, get_ssl_handler },
926: { "query", 1, 1, query_handler },
927: { "query_string", 0, 0, query_string_handler },
928: { "redirect", 0, 0, redirect_handler },
929: { "remote_ip", 0, 0, remote_ip_handler },
930: { "remote_port", 0, 0, remote_port_handler },
931: { "shutdown", 0, 0, shutdown_handler },
932: { "sleep", 1, 1, sleep_handler },
933: { "vhost", 0, 0, vhost_handler },
934: };
935:
936: static char *
937: demo_tmpl_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
938: {
939: return (tmpl_list_handler(ctx, demo_tmpl_funcs,
940: sizeof(demo_tmpl_funcs) / sizeof(*demo_tmpl_funcs),
941: errmsgp, ac, av));
942: }
943:
944: static char *
945: remote_ip_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
946: {
947: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
948: const char *const mtype = tmpl_ctx_get_mtype(ctx);
949:
950: return (STRDUP(mtype,
951: inet_ntoa(http_request_get_remote_ip(targ->req))));
952: }
953:
954: static char *
955: remote_port_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
956: {
957: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
958: const char *const mtype = tmpl_ctx_get_mtype(ctx);
959: char buf[32];
960:
961: snprintf(buf, sizeof(buf), "%u",
962: http_request_get_remote_port(targ->req));
963: return (STRDUP(mtype, buf));
964: }
965:
966: static char *
967: redirect_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
968: {
969: const char *const mtype = tmpl_ctx_get_mtype(ctx);
970:
971: return (STRDUP(mtype, redirect_url ? redirect_url : ""));
972: }
973:
974: static char *
975: date_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
976: {
977: const char *const mtype = tmpl_ctx_get_mtype(ctx);
978: const time_t now = time(NULL);
979: char buf[32];
980:
981: return (STRDUP(mtype, ctime_r(&now, buf)));
982: }
983:
984: static char *
985: sleep_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
986: {
987: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
988: const char *const mtype = tmpl_ctx_get_mtype(ctx);
989:
990: http_response_send_headers(targ->resp, 1);
991: sleep(atoi(av[1]));
992: return (STRDUP(mtype, ""));
993: }
994:
995: static char *
996: authorize_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
997: {
998: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
999: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1000:
1001: /* Login */
1002: if (ac > 2 && *av[2] != '\0') {
1003: const u_long expiry = strtoul(av[2], NULL, 10);
1004:
1005: if (http_servlet_cookieauth_login(targ->resp,
1006: "demo.key", av[1], 3600, expiry ? time(NULL) + expiry : 0,
1007: expiry == 0, demo_id, sizeof(demo_id), DEMO_COOKIE_NAME,
1008: "/", NULL, 0) == -1)
1009: return (NULL);
1010: return (STRDUP(mtype, ""));
1011: }
1012:
1013: /* Logout */
1014: if (http_servlet_cookieauth_logout(DEMO_COOKIE_NAME,
1015: "/", NULL, targ->resp) == -1)
1016: return (NULL);
1017: return (STRDUP(mtype, ""));
1018: }
1019:
1020: static char *
1021: authname_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1022: {
1023: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
1024: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1025: char *name;
1026:
1027: if ((name = http_servlet_cookieauth_user("demo.key", demo_id,
1028: sizeof(demo_id), DEMO_COOKIE_NAME, targ->req, mtype)) == NULL) {
1029: if (errno == EACCES)
1030: name = STRDUP(mtype, "");
1031: }
1032: if (name == NULL)
1033: return (NULL);
1034: return (name);
1035: }
1036:
1037: static char *
1038: query_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1039: {
1040: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
1041: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1042: const char *value;
1043:
1044: if ((value = http_request_get_value(targ->req, av[1], 0)) == NULL)
1045: value = "";
1046: return (STRDUP(mtype, value));
1047: }
1048:
1049: static char *
1050: query_string_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1051: {
1052: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
1053: const char *eqs = http_request_get_query_string(targ->req);
1054: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1055: char *dqs;
1056:
1057: /* URL-decode query string */
1058: if ((dqs = MALLOC(mtype, strlen(eqs) + 1)) == NULL)
1059: return (NULL);
1060: http_request_url_decode(eqs, dqs);
1061:
1062: /* Return it */
1063: return (dqs);
1064: }
1065:
1066: static char *
1067: get_header_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1068: {
1069: struct http_servlet_tmpl_arg *const targ = tmpl_ctx_get_arg(ctx);
1070: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1071: const char *value;
1072:
1073: if ((value = http_request_get_header(targ->req, av[1])) == NULL)
1074: value = "";
1075: return (STRDUP(mtype, value));
1076: }
1077:
1078: static char *
1079: get_port_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1080: {
1081: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1082: char buf[32];
1083:
1084: snprintf(buf, sizeof(buf), "%u", port);
1085: return (STRDUP(mtype, buf));
1086: }
1087:
1088: static char *
1089: get_ssl_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1090: {
1091: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1092:
1093: return (STRDUP(mtype, ssl != NULL ? "1" : "0"));
1094: }
1095:
1096: static char *
1097: vhost_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1098: {
1099: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1100:
1101: return (STRDUP(mtype, vhost == NULL ? "" : vhost));
1102: }
1103:
1104: static char *
1105: shutdown_handler(struct tmpl_ctx *ctx, char **errmsgp, int ac, char **av)
1106: {
1107: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1108:
1109: kill(main_pid, SIGTERM);
1110: return (STRDUP(mtype, ""));
1111: }
1112:
1113: /*
1114: * Error formatter for templates.
1115: */
1116: static char *
1117: demo_tmpl_errfmtr(struct tmpl_ctx *ctx, const char *errmsg)
1118: {
1119: static const char fmt[] =
1120: "<font color=\"#ff0000\"><strong>Error: %s</strong></font>";
1121: const char *const mtype = tmpl_ctx_get_mtype(ctx);
1122: char *string;
1123: int slen;
1124:
1125: slen = sizeof(fmt) + strlen(errmsg);
1126: if ((string = MALLOC(mtype, slen)) == NULL)
1127: return (NULL);
1128: snprintf(string, slen, fmt, errmsg);
1129: return (string);
1130: }
1131:
1132: /***********************************************************************
1133: SSL MEMORY WRAPPERS
1134: ***********************************************************************/
1135:
1136: /*
1137: * OpenSSL malloc() wrappers
1138: */
1139: static void
1140: *ssl_malloc(size_t size)
1141: {
1142: return (MALLOC("OpenSSL", size));
1143: }
1144:
1145: static void
1146: *ssl_realloc(void *mem, size_t size)
1147: {
1148: return (REALLOC("OpenSSL", mem, size));
1149: }
1150:
1151: static void
1152: ssl_free(void *mem)
1153: {
1154: return (FREE("OpenSSL", mem));
1155: }
1156:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>