Annotation of embedaddon/libpdel/http/test/main.c, revision 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>