root/openwsman/trunk/src/server/shttpd.c

Revision 2079, 57.9 kB (checked in by houliang, 3 years ago)

initial cim indication listener implementation

Line 
1 /*
2  * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22
23 /*
24  * Small and portable HTTP server, http://shttpd.sourceforge.net
25  *
26  * Compilation:
27  *    No win32 GUI:             -DNO_GUI
28  *    No CGI:                   -DNO_CGI
29  *    Override max request size -DIO_MAX=xxxx
30  *    Default config file:      -DCONFIG=\"/etc/shttpd.conf\"
31  *    Typedef socklen_t         -DNO_SOCKLEN_T
32  *    Use embedded:             -DEMBEDDED
33  */
34
35
36 #ifndef EMBEDDED
37 #define EMBEDDED
38 #endif
39 #include "u/libu.h"
40 #include "shttpd.h"
41
42 #ifdef HAVE_CONFIG_H
43 #include "wsman_config.h"
44 #endif
45
46
47 #define SHTTPD_VERSION          "1.35"          /* Version                      */
48 #ifndef CONFIG
49 #define CONFIG          "/usr/local/etc/shttpd.conf"    /* Configuration file           */
50 #endif /* CONFIG */
51 #define HTPASSWD        ".htpasswd"     /* Passwords file name          */
52 #define EXPIRE_TIME     3600            /* Expiration time, seconds     */
53 #define KEEP_ALIVE_TIME  2     /* keep connection, seconds */
54 #ifndef IO_MAX
55 #define IO_MAX          16384           /* Max request size             */
56 #endif /* IO_MAX */
57 #ifndef USER_MAX
58 #define USER_MAX        64              /* Remote user name maxsize     */
59 #endif /* USER_MAX */
60 #define AUTH_MAX        1024            /* Authorization line           */
61 #define NVAR_MAX        128             /* Maximum POST variables       */
62 #define PORT            "80"            /* Default listening port       */
63 #define INDEX_FILES     "index.html,index.php,index.cgi" /* Index files */
64 #define CGI_EXT         ".cgi"          /* Default CGI extention        */
65 #define REALM           "mydomain.com"  /* Default auth realm           */
66 #define ENV_MAX         4096            /* Size of environment block    */
67
68 #define NELEMS(ar)      (sizeof(ar) / sizeof(ar[0]))
69
70
71 #include <sys/wait.h>
72 #include <sys/socket.h>
73 #include <sys/select.h>
74 #include <sys/mman.h>
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 #ifdef TIME_WITH_SYS_TIME
78 #include <sys/time.h>
79 #endif
80
81
82 #include <pwd.h>
83 #include <unistd.h>
84 #include <dirent.h>
85 #include <dlfcn.h>
86 //#define       SSL_LIB                         "/usr/lib/libssl.so"
87 #define SSL_LIB             "libssl.so"
88 #define DIRSEP                          '/'
89 #define O_BINARY                        0
90 #define closesocket(a)                  close(a)
91 #define ERRNO                           errno
92 #define NO_GUI
93
94 #define InitializeCriticalSection(x)    /* FIXME UNIX version is not MT safe */
95 #define EnterCriticalSection(x)
96 #define LeaveCriticalSection(x)
97
98 #include <sys/types.h>          /* Common #includes (ANSI and SSL) */
99 #include <sys/stat.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <stdarg.h>
103 #include <assert.h>
104 #include <time.h>
105 #include <errno.h>
106 #include <signal.h>
107 #include <string.h>
108 #include <ctype.h>
109 #include <limits.h>
110 #include <stddef.h>
111 #include <fcntl.h>
112
113 #ifdef WITH_DMALLOC
114 #include <dmalloc.h>
115 #endif /* WITH_DMALLOC */
116
117
118
119 /*
120  * Darwin prior to 7.0 and Win32 do not have socklen_t
121  */
122 #ifdef NO_SOCKLEN_T
123 typedef int socklen_t;
124 #endif
125
126
127 /*
128  * Snatched from OpenSSL includes. I put the prototypes here to be independent
129  * from the OpenSSL source installation. Having this, shttpd + SSL can be
130  * built on any system with binary SSL libraries installed.
131  */
132
133 #ifdef HAVE_SSL
134 #include <openssl/ssl.h>
135 /*  bug #67
136 typedef struct ssl_st SSL;
137 typedef struct ssl_method_st SSL_METHOD;
138 typedef struct ssl_ctx_st SSL_CTX;
139 */
140 #endif
141
142 #if 0
143 #define SSL_ERROR_WANT_READ     2
144 #define SSL_ERROR_WANT_WRITE    3
145 #define SSL_FILETYPE_PEM        1
146 #endif
147 /*
148  * Unified socket address
149  */
150 struct usa {
151         socklen_t len;
152         union {
153                 struct sockaddr sa;
154                 struct sockaddr_in sin;
155         } u;
156 };
157
158 /*
159  * Mime type entry
160  */
161 struct mimetype {
162         struct mimetype *next;
163         char            *ext;           /* File extention       */
164         char            *mime;          /* Mime type            */
165         size_t          extlen;         /* Extention length     */
166 };
167
168 /*
169  * Known HTTP methods
170  */
171 enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD};
172
173 /*
174  * I/O buffer
175  */
176 struct io {
177         char    *buf;           /* Buffer               */
178         size_t  bufsize;
179         int     done;                   /* IO finished          */
180         size_t  head;                   /* Bytes read           */
181         size_t  tail;                   /* Bytes written        */
182 };
183 #define IO_SPACELEN(io)         ((io)->bufsize - (io)->head - 1)
184 #define IO_DATALEN(io)          ((io)->head - (io)->tail)
185
186 /*
187  * Connection descriptor
188  */
189 #define PROTO_SIZE      16
190 struct shttpd_ctx;
191 typedef void (*shttpd_watch_t)(struct shttpd_ctx *, void *);
192 struct conn {
193         struct conn     *next;          /* Connections chain            */
194         struct shttpd_ctx *ctx;         /* Context this conn belongs to */
195         struct usa      sa;             /* Remote socket address        */
196         time_t          birth;          /* Creation time                */
197         time_t          expire;         /* Expiration time              */
198         time_t          ims;            /* If-Modified-Since:           */
199         int             sock;           /* Remote socket                */
200 #ifdef HAVE_SSL
201         SSL             *ssl;           /* SSL descriptor               */
202 #endif
203         int             reqlen;         /* Request length               */
204         int             status;
205         int             http_method;    /* HTTP method                  */
206         void            *state;         /* Embedded. Callback state.    */
207         unsigned long   cclength;       /* Client Content-Length        */
208         unsigned long   sclength;       /* Server Content-Length        */
209         unsigned long   shlength;       /* Server headers length        */
210         unsigned long   nsent;          /* Bytes sent to client         */
211         shttpd_watch_t  watch;          /* IO readiness callback        */
212         void            *watch_data;    /* Callback data                */
213
214         struct io       local;          /* Local IO buffer              */
215         struct io       remote;         /* Remote IO buffer             */
216         void (*io)(struct conn *);      /* Local IO function            */
217
218         char            method[16];     /* Used method                  */
219         char            uri[IO_MAX];    /* Url-decoded URI              */
220         char            saved[IO_MAX];  /* Saved request                */
221         char            proto[PROTO_SIZE];      /* HTTP protocol        */
222
223         char            *user;          /* Remote user name             */
224         char            *auth;          /* Authorization                */
225         char            *useragent;     /* User-Agent:                  */
226         char            *path;          /* Path for get_dir             */
227         char            *referer;       /* Referer:                     */
228         char            *cookie;        /* Cookie:                      */
229         char            *ctype;         /* Content-Type:                */
230         char            *location;      /* Location:                    */
231         char            *query;         /* QUERY_STRING                 */
232         char            *range;         /* Range:                       */
233         char            *path_info;     /* PATH_INFO thing              */
234         char        *usr;       /* save username if basic authentication */
235         char        *pwd;       /* save password if basic authentication */
236
237         unsigned long   nposted;        /* Emb. POST bytes buffered     */
238         void            *userurl;       /* For embedded data            */
239         char            *vars[NVAR_MAX];        /* Variables            */
240
241         int             fd;             /* Local file descriptor        */
242         struct stat     st;             /* Stats of requested file      */
243         DIR             *dirp;          /* Opened directory             */
244         unsigned int    flags;          /* Flags                        */
245 #define FLAG_FINISHED           0x0001  /* Connection to be closed      */
246 #define FLAG_PARSED             0x0002  /* Request has been parsed      */
247 #define FLAG_CGIPARSED          0x0004  /* CGI output has been parsed   */
248 #define FLAG_SSLACCEPTED        0x0008  /* SSL_accept() succeeded       */
249 #define FLAG_ALWAYS_READY       0x0010  /* Local channel always ready for IO */
250         //#define       FLAG_USER_WATCH         0x0020  /* User watch                   */
251 #define FLAG_SOCK_READABLE      0x0040
252 #define FLAG_SOCK_WRITABLE      0x0080
253 #define FLAG_FD_READABLE        0x0100
254 #define FLAG_FD_WRITABLE        0x0200
255 #define FLAG_CGI                0x0400
256 #define FLAG_KEEP_CONNECTION    0x0800
257 #define FLAG_AUTHORIZED         0x1000  /* Already authorized */
258 #define FLAG_HAVE_TO_WRITE      0x2000  /* connection have something to write */
259 };
260
261 #define FLAG_IO_READY   (FLAG_SOCK_WRITABLE | FLAG_SOCK_READABLE | \
262                 FLAG_FD_READABLE | FLAG_FD_WRITABLE)
263
264 enum err_level  {ERR_DEBUG, ERR_INFO, ERR_FATAL};
265
266 #define elog(level, ...) \
267         do { \
268                 debug( __VA_ARGS__ ); \
269                 if (level == ERR_FATAL) exit(EXIT_FAILURE); \
270         } while (0)
271
272 enum hdr_type   {HDR_DATE, HDR_INT, HDR_STRING};
273
274 /*
275  * Known HTTP headers
276  */
277 #define OFFSET(x)       offsetof(struct conn, x)
278 struct header {
279         size_t          len;            /* Header name length           */
280         enum hdr_type   type;           /* Header type                  */
281         size_t          offset;         /* Where to store a header value*/
282         const char      *name;          /* Header name                  */
283 } headers[] = {
284         {12, HDR_STRING, OFFSET(useragent),     "User-Agent: "          },
285         {14, HDR_STRING, OFFSET(ctype),         "Content-Type: "        },
286         {16, HDR_INT,    OFFSET(cclength),      "Content-Length: "      },
287         {19, HDR_DATE,   OFFSET(ims),           "If-Modified-Since: "   },
288         {15, HDR_STRING, OFFSET(auth),          "Authorization: "       },
289         {9,  HDR_STRING, OFFSET(referer),       "Referer: "             },
290         {8,  HDR_STRING, OFFSET(cookie),        "Cookie: "              },
291         {10, HDR_STRING, OFFSET(location),      "Location: "            },
292         {8,  HDR_INT,    OFFSET(status),        "Status: "              },
293         {7,  HDR_STRING, OFFSET(range),         "Range: "               },
294         {0,  HDR_INT,    0,                     NULL                    }
295 };
296
297 union variant {
298         char            *value_str;
299         unsigned long   value_int;
300         time_t          value_time;
301         void            (*value_func)(void);
302         void            *value_void;
303 };
304
305
306 /*
307  * Mount points (Alias)
308  */
309 struct mountpoint {
310         struct mountpoint       *next;
311         char                    *path;
312         char                    *mountpoint;
313 };
314
315 /*
316  * Environment variables
317  */
318 struct envvar {
319         struct envvar           *next;
320         char                    *name;
321         char                    *value;
322 };
323
324 /*
325  * User-registered URI
326  */
327 struct userurl {
328         struct userurl          *next;
329         char            *url;
330         shttpd_callback_t       func;
331         int authnotneeded;
332         void                    *data;
333 };
334
335 /*
336  * User defined authorization file
337  */
338 struct userauth {
339         struct userauth         *next;
340         const char              *url;
341         const char              *filename;
342 };
343
344 /*
345  * SHTTPD context
346  */
347 struct shttpd_ctx {
348         time_t          start_time;             /* Start time */
349         int             nactive;                /* # of connections now */
350         unsigned int    nrequests;              /* Requests made */
351         unsigned int    kb_in, kb_out;          /* IN/OUT traffic counters */
352         struct mimetype *mimetypes;             /* Known mime types */
353         struct mountpoint *mountpoints;         /* Aliases */
354         struct envvar   *envvars;               /* CGI environment variables */
355         struct userurl  *urls;                  /* User urls */
356         struct userauth *auths;                 /* User auth files */
357         struct conn     *connections;           /* List of connections */
358 #ifdef HAVE_SSL
359         SSL_CTX         *ssl_ctx;               /* SSL context */
360 #endif
361         /*
362          * Configurable
363          */
364         FILE            *accesslog;             /* Access log stream */
365         FILE            *errorlog;              /* Error log stream */
366         char            *put_auth;              /* PUT auth file */
367         char            root[FILENAME_MAX];     /* Document root */
368         char            *index;                 /* Index files */
369         char            *ext;                   /* CGI extention */
370         char            *interp;                /* CGI script interpreter */
371         char            *realm;                 /* Auth realm */
372         char            *pass;                  /* Global passwords file */
373         char            *uid;                   /* Run as user */
374         int             port;                   /* Listening port */
375         int             dirlist;                /* Directory listing */
376         int             _debug;                 /* Debug flag */
377         int             gui;                    /* Show GUI flag */
378         shttpd_bauth_callback_t         bauthf; /* basic authorization callback */
379         shttpd_dauth_callback_t         dauthf; /* digest authorization callback */
380 };
381
382 typedef void (*optset_t)(struct shttpd_ctx *, void *ptr, const char *string);
383 struct opt {
384         int             sw;                     /* Command line switch */
385         const char      *name;                  /* Option name in config file */
386         const char      *desc;                  /* Description */
387         optset_t        setter;                 /* Option setter function */
388         size_t          ofs;                    /* Value offset in context */
389         const char      *arg;                   /* Argument format */
390         const char      *def;                   /* Default option value */
391         char            *tmp;                   /* Temporary storage */
392         unsigned int    flags;                  /* Flags */
393 #define OPT_FLAG_BOOL   1
394 #define OPT_FLAG_INT    2
395 #define OPT_FLAG_FILE   4
396 #define OPT_FLAG_DIR    8
397 };
398
399 /*
400  * Global variables
401  */
402 static time_t           current_time;   /* No need to keep per-context time */
403 static int              _debug;         /* Show _debug messages */
404 static int              exit_flag;      /* Exit flag */
405 static int              inetd;          /* Inetd flag */
406
407 /*
408  * Prototypes
409  */
410 static void     io_inc_tail(struct io *io, size_t n);
411 static int      casecmp(register const char *s1, register const char *s2);
412 static int      ncasecmp(register const char *, register const char *, size_t);
413 static void     disconnect(struct conn *c);
414 static int      writeremote(struct conn *c, const char *buf, size_t len);
415 static int      readremote(struct conn *c, char *buf, size_t len);
416 static int      nonblock(int fd);
417 static int      getreqlen(const char *buf, size_t buflen);
418 static void     log_access(FILE *fp, const struct conn *c);
419 static void     senderr(struct conn *c, int status, const char *descr,
420                 const char *headers, const char *fmt, ...);
421 static int      montoi(const char *s);
422 static time_t   datetosec(const char *s);
423 static void     urldecode(char *from, char *to);
424 static void     killdots(char *file);
425 static char     *fetch(const char *src, char *dst, size_t len);
426 static void     parse_headers(struct conn *c, char *s);
427 static void     parse_request(struct conn *c);
428 static void     handle(struct conn *c);
429 static void     serve(struct shttpd_ctx *,void *);
430 static void     mystrlcpy(register char *, register const char *, size_t);
431 static struct opt *swtoopt(int sw, const char *name);
432 static struct shttpd_ctx *do_init(const char *, int argc, char *argv[]);
433
434 static void
435 add_conn_to_ctx(struct shttpd_ctx *ctx, struct conn *c)
436 {
437         EnterCriticalSection(&ctx->mutex);
438
439         c->next = ctx->connections;
440         ctx->connections = c;
441         ctx->nactive++;
442         c->ctx = ctx;
443
444         LeaveCriticalSection(&ctx->mutex);
445 }
446
447 static void
448 del_conn_from_ctx(struct shttpd_ctx *ctx, struct conn *c)
449 {
450         struct conn     *tmp;
451
452         EnterCriticalSection(&ctx->mutex);
453
454         if (c == ctx->connections)
455                 ctx->connections = c->next;
456         else
457                 for (tmp = ctx->connections; tmp != NULL; tmp = tmp->next)
458                         if (tmp->next == c) {
459                                 tmp->next = c->next;
460                                 break;
461                         }
462
463         ctx->nactive--;
464         assert(ctx->nactive >= 0);
465
466         LeaveCriticalSection(&ctx->mutex);
467 }
468
469 const char *
470 shttpd_version(void)
471 {
472         return (SHTTPD_VERSION);
473 }
474
475 /*
476  * Add mime type to the known mime type list
477  */
478 void
479 shttpd_addmimetype(struct shttpd_ctx *ctx, const char *ext, const char *mime)
480 {
481         struct mimetype *p;
482
483         /* XXX possible resource leak  */
484         if ((p = calloc(1, sizeof(*p))) != NULL &&
485                         (p->ext = u_strdup(ext)) != NULL &&
486                         (p->mime = u_strdup(mime)) != NULL) {
487                 p->extlen       = strlen(p->ext);
488                 p->next         = ctx->mimetypes;
489                 ctx->mimetypes  = p;
490         }
491 }
492
493 /*
494  * Configuration parameters setters
495  */
496 static void
497 set_int(struct shttpd_ctx *ctx, void *ptr, const char *string)
498 {
499         ctx = NULL;     /* Unused */
500         * (int *) ptr = atoi(string);
501 }
502
503 static void
504 set__debug(struct shttpd_ctx *ctx, void *ptr, const char *string)
505 {
506         ctx = ptr = NULL;
507         _debug = atoi(string);
508 }
509
510 static void
511 set_inetd(struct shttpd_ctx *ctx, void *ptr, const char *string)
512 {
513         ctx = ptr = NULL;
514         inetd = atoi(string);
515 }
516
517 static void
518 set_str(struct shttpd_ctx *ctx, void *ptr, const char *string)
519 {
520         ctx = NULL;     /* Unused */
521         * (char **) ptr = strdup(string);
522 }
523
524 static void
525 set_root(struct shttpd_ctx *ctx, void *ptr, const char *string)
526 {
527         mystrlcpy(ptr, string, sizeof(ctx->root));
528 }
529
530 static void
531 set_access_log(struct shttpd_ctx *ctx, void *ptr, const char *string)
532 {
533         FILE    *fp;
534
535         assert(&ctx->accesslog == ptr);
536
537         if ((fp = fopen(string, "a")) == NULL)
538                 elog(ERR_INFO, "cannot open log file %s: %s",
539                                 string, strerror(errno));
540         else
541                 ctx->accesslog = fp;
542 }
543
544 static void
545 set_error_log(struct shttpd_ctx *ctx, void *ptr, const char *string)
546 {
547         ptr = NULL;
548         ctx = NULL;     /* Unused */
549         if (freopen(string, "w", stderr) == NULL)
550                 elog(ERR_INFO, "freopen(%s): %s", string, strerror(errno));
551 }
552
553 static void
554 set_mime(struct shttpd_ctx *ctx, void *arg, const char *string)
555 {
556         FILE    *fp;
557         char    line[512], ext[sizeof(line)], mime[sizeof(line)], *s;
558         static struct { const char *ext, *type; } *p, types[] = {
559                 {"svg",         "image/svg+xml"                 },
560                 {"torrent",     "application/x-bittorrent"      },
561                 {"wav",         "audio/x-wav"                   },
562                 {"mp3",         "audio/x-mp3"                   },
563                 {"mid",         "audio/mid"                     },
564                 {"m3u",         "audio/x-mpegurl"               },
565                 {"ram",         "audio/x-pn-realaudio"          },
566                 {"ra",          "audio/x-pn-realaudio"          },
567                 {"doc",         "application/msword",           },
568                 {"exe",         "application/octet-stream"      },
569                 {"zip",         "application/x-zip-compressed"  },
570                 {"xls",         "application/excel"             },
571                 {"tgz",         "application/x-tar-gz"          },
572                 {"tar.gz",      "application/x-tar-gz"          },
573                 {"tar",         "application/x-tar"             },
574                 {"gz",          "application/x-gunzip"          },
575                 {"arj",         "application/x-arj-compressed"  },
576                 {"rar",         "application/x-arj-compressed"  },
577                 {"rtf",         "application/rtf"               },
578                 {"pdf",         "application/pdf"               },
579                 {"jpeg",        "image/jpeg"                    },
580                 {"png",         "image/png"                     },
581                 {"mpg",         "video/mpeg"                    },
582                 {"mpeg",        "video/mpeg"                    },
583                 {"asf",         "video/x-ms-asf"                },
584                 {"avi",         "video/x-msvideo"               },
585                 {"bmp",         "image/bmp"                     },
586                 {"jpg",         "image/jpeg"                    },
587                 {"gif",         "image/gif"                     },
588                 {"ico",         "image/x-icon"                  },
589                 {"txt",         "text/plain"                    },
590                 {"css",         "text/css"                      },
591                 {"htm",         "text/html"                     },
592                 {"html",        "text/html"                     },
593                 {NULL,          NULL                            }
594         };
595
596         arg = NULL;
597
598         if (strcmp(string, "builtin") == 0) {
599                 for (p = types; p->ext != NULL; p++)
600                         shttpd_addmimetype(ctx, p->ext, p->type);
601                 return;
602         }
603
604         if ((fp = fopen(string, "r")) == NULL)
605                 elog(ERR_FATAL, "setmimetypes: fopen(%s): %s",
606                                 string, strerror(errno));
607
608         while (fgets(line, sizeof(line), fp) != NULL) {
609                 /* Skip empty lines */
610                 if (line[0] == '#' || line[0] == '\n')
611                         continue;
612                 if (sscanf(line, "%s", mime)) {
613                         s = line + strlen(mime);
614                         while (*s && *s != '\n' && sscanf(s, "%s", ext)) {
615                                 shttpd_addmimetype(ctx, ext, mime);
616                                 s += strlen(mime);
617                         }
618                 }
619         }
620
621         (void) fclose(fp);
622 }
623
624 #ifdef HAVE_SSL
625 static void
626 set_ssl(struct shttpd_ctx *ctx, void *arg, const char *pem)
627 {
628         SSL_CTX         *CTX;
629         //      void            *lib;
630         //      struct ssl_func *fp;
631
632         arg = NULL;     /* Unused */
633 #if 0
634         /* Load SSL library dynamically */
635         if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) {
636                 elog(ERR_FATAL, "set_ssl: cannot load %s", SSL_LIB);
637         }
638
639         for (fp = ssl_sw; fp->name != NULL; fp++)
640                 if ((fp->ptr.value_void = dlsym(lib, fp->name)) == NULL)
641                         elog(ERR_FATAL, "set_ssl: cannot find %s", fp->name);
642 #endif
643
644         /* Initialize SSL crap */
645         SSL_library_init();
646
647         if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
648                 elog(ERR_FATAL, "SSL_CTX_new error");
649         else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
650                 elog(ERR_FATAL, "cannot open certificate %s", pem);
651         ctx->ssl_ctx = CTX;
652 }
653
654 static void
655 set_ssl_priv_key(struct shttpd_ctx *ctx, void *arg, const char *pem)
656 {
657         if (ctx->ssl_ctx == NULL) {
658                 elog(ERR_FATAL, "SSL_CTX is not created");
659         }
660         if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0) {
661                 elog(ERR_FATAL, "cannot open private key %s", pem);
662         }
663 }
664 #endif
665
666 /*
667  * Setup aliases. Passed string must be in format
668  * "directory1=url1,directory2=url2,..."
669  */
670 static void
671 set_aliases(struct shttpd_ctx *ctx, void *arg, const char *string)
672 {
673         struct mountpoint       *mp, **head = arg;
674         char    *p, *s, *copy, dir[FILENAME_MAX], uri[IO_MAX];
675
676         ctx = NULL;     /* Unused */
677
678         for (s = p = copy = u_strdup(string); *s; s = p) {
679                 if ((p = strchr(s, ',')) != NULL)
680                         *p++ = '\0';
681                 else
682                         p = s + strlen(s);
683
684                 /* FIXME: overflow possible */
685                 if (sscanf(s, "%[^=]=%s", dir, uri) != 2)
686                         elog(ERR_DEBUG, "set_aliases: bad format: %s", string);
687                 else if ((mp = calloc(1, sizeof(*mp))) != NULL) {
688                         mp->mountpoint  = u_strdup(uri);
689                         mp->path        = u_strdup(dir);
690                         mp->next        = *head;
691                         *head           = mp;
692                         elog(ERR_DEBUG, "set_aliases: [%s]=[%s]", dir, uri);
693                 }
694         }
695
696         free(copy);
697 }
698
699 /*
700  * Setup CGI environment variables. Passed string must be in format
701  * "varname1=value1,varname2=value2,..."
702  */
703 static void
704 set_envvars(struct shttpd_ctx *ctx, void *arg, const char *string)
705 {
706         struct envvar   *ep, **head = arg;
707         char    *p, *s, *copy, name[IO_MAX], value[IO_MAX];
708
709         ctx = NULL;     /* Unused */
710
711         for (s = p = copy = u_strdup(string); *s; s = p) {
712                 if ((p = strchr(s, ',')) != NULL)
713                         *p++ = '\0';
714                 else
715                         p = s + strlen(s);
716
717                 /* FIXME: overflow possible */
718                 if (sscanf(s, "%[^=]=%s", name, value) != 2)
719                         elog(ERR_DEBUG, "set_envvars: bad format: %s", string);
720                 else if ((ep = calloc(1, sizeof(*ep))) != NULL) {
721                         ep->name        = u_strdup(name);
722                         ep->value       = u_strdup(value);
723                         ep->next        = *head;
724                         *head           = ep;
725                         elog(ERR_DEBUG, "set_envvars: [%s]=[%s]", name, value);
726                 }
727         }
728
729         free(copy);
730 }
731
732 #define OFS(x)  offsetof(struct shttpd_ctx, x)
733 #define BOOL_OPT        "0|1"
734 static struct opt options[] = {
735         {'d', "document_root", "Web root directory", set_root,
736                 OFS(root), "directory", NULL, NULL, OPT_FLAG_DIR},
737         {'i', "index_files", "Index files", set_str,
738                 OFS(index), "file_names", INDEX_FILES, NULL, 0  },
739         {'p', "listen_port", "Listening port", set_int,
740                 OFS(port), "port", PORT, NULL, OPT_FLAG_INT},
741         {'D', "list_directories", "Directory listing", set_int,
742                 OFS(dirlist), BOOL_OPT, "1", NULL, OPT_FLAG_BOOL},
743         {'c', "cgi_extention", "CGI extention", set_str,
744                 OFS(ext), "extention", CGI_EXT, NULL, 0         },
745         {'C', "cgi_interpreter", "CGI interpreter", set_str,
746                 OFS(interp), "file", NULL, NULL, OPT_FLAG_FILE  },
747         {'N', "auth_realm", "Authentication realm", set_str,
748                 OFS(realm), "auth_realm", REALM, NULL, 0        },
749         {'l', "access_log", "Access log file", set_access_log,
750                 OFS(accesslog), "file", NULL, NULL, OPT_FLAG_FILE},
751         {'e', "error_log", "Error log file", set_error_log,
752                 OFS(errorlog), "file", NULL, NULL, OPT_FLAG_FILE},
753         {'m', "mime_types", "Mime types file", set_mime,
754                 0, "file", "builtin", NULL, OPT_FLAG_FILE       },
755         {'P', "global_htpasswd", "Global passwords file", set_str,
756                 OFS(pass), "file", NULL, NULL, OPT_FLAG_FILE    },
757         {'v', "debug", "Debug mode", set__debug,
758                 0, BOOL_OPT, "0", NULL, OPT_FLAG_BOOL   },
759 #ifdef HAVE_SSL
760         {'s', "ssl_certificate", "SSL certificate file", set_ssl,
761                 OFS(ssl_ctx), "pem_file", NULL, NULL, OPT_FLAG_FILE},
762         {'k', "ssl_priv_key", "SSL pivate key file", set_ssl_priv_key,
763                 OFS(ssl_ctx), "pem_file", NULL, NULL, OPT_FLAG_FILE},
764 #endif
765         {'U', "put_auth", "PUT,DELETE auth file",set_str,
766                 OFS(put_auth), "file", NULL, NULL, OPT_FLAG_FILE},
767         {'V', "cgi_envvar", "CGI envir variables", set_envvars,
768                 OFS(envvars), "X=Y,....", NULL, NULL, 0         },
769         {'a', "aliases", "Aliases", set_aliases,
770                 OFS(mountpoints), "X=Y,...", NULL, NULL, 0      },
771         {'I', "inetd_mode", "Inetd mode", set_inetd,
772                 0, BOOL_OPT, "0", NULL, OPT_FLAG_BOOL   },
773         {'u', "runtime_uid", "Run as user", set_str,
774                 OFS(uid), "user_name", NULL, NULL, 0            },
775         {0,   NULL, NULL, NULL, 0, NULL, NULL, NULL, 0          }
776 };
777
778 static struct userurl *
779 isregistered(struct shttpd_ctx *ctx, const char *url)
780 {
781         struct userurl  *p;
782
783         for (p = ctx->urls; p != NULL; p = p->next) {
784 //              debug("*******registered url : %s**********", p->url);
785                 if (strcmp(p->url, url) == 0)
786                         return (p);
787         }
788
789         return (NULL);
790 }
791
792 char *shttp_reason_phrase(int code) {
793         struct http_code_map {
794                 int code;
795                 char *reason_phrase;
796         };
797         struct http_code_map maps[] = {
798                         {200, "OK"},
799                         {0, NULL}
800         };
801         int i = 0;
802         while(maps[i].code) {
803                 if(maps[i].code == code)
804                         return maps[i].reason_phrase;
805                 i++;
806         }
807         return NULL;
808 }
809
810
811 #ifdef EMBEDDED
812 /*
813  * The URI should be handled is user-registered callback function.
814  * In MT scenario, call user-defined function in dedicated thread (or process)
815  * and discard the return value.
816  * In nonMT scenario, call the user function. Return value should is the
817  * number of bytes copied to the local IO buffer. Mark local IO as done,
818  * and shttpd will take care about passing data back to client.
819  */
820 static void
821 do_embedded(struct conn *c)
822 {
823         struct shttpd_arg_t     arg;
824         const struct userurl    *url = c->userurl;
825         unsigned long           n;
826
827         arg.priv        = c;
828         arg.last        = 0;
829         arg.state       = c->state;
830         arg.user_data   = url->data;
831         arg.buf         = c->local.buf + c->local.head;
832         arg.buflen      = IO_SPACELEN(&c->local);
833
834         if (c->http_method == METHOD_POST && c->cclength) {
835
836                 if (c->query == NULL) {
837
838                         /* Allocate POST buffer */
839                         if ((c->query = malloc(c->cclength + 1)) == NULL) {
840                                 senderr(c, 413, "Too Large", "", "huge POST");
841                                 return;
842                         }
843
844                         /* Copy initial POST data into c->query */
845                         n = c->remote.head - c->reqlen;
846                         if ((size_t) n > c->cclength)
847                                 n = c->cclength;
848                         if (n > 0) {
849                                 (void) memcpy(c->query,
850                                                 c->remote.buf + c->reqlen, n);
851                                 c->nposted += n;
852                         }
853                         c->remote.head = c->remote.tail = 0;
854                         elog(ERR_DEBUG, "do_embedded 1: %u %u",
855                                         c->cclength, c->nposted);
856                 } else {
857                         /* Buffer in POST data */
858                         n = IO_DATALEN(&c->remote);
859                         if (n > c->cclength - c->nposted)
860                                 n = c->cclength - c->nposted;
861                         if (n > 0) {
862                                 (void) memcpy(c->query + c->nposted,
863                                                 c->remote.buf + c->remote.tail, n);
864                                 c->nposted += n;
865                         }
866                         c->remote.head = c->remote.tail = 0;
867                         elog(ERR_DEBUG, "do_embedded 2: %u %u",
868                                         c->cclength, c->nposted);
869                 }
870
871                 /* Return if not all POST data buffered */
872                 if (c->nposted < c->cclength || c->cclength == 0) {
873                         elog(ERR_DEBUG,"do_embedded: c->nposted = %d; cclength = %d",
874                                         c->nposted, c->cclength);
875                         return;
876                 }
877                 /* Null-terminate query data */
878                 c->query[c->cclength] = '\0';
879         }
880 #if 0
881         printf("         c->query body\n");
882         char *b = c->query;
883         int i, slen;
884         while (b < c->query + c->cclength) {
885                 slen = strlen(b);
886                 printf("   %s\n", b);
887                 b += slen + 1;
888         }
889         printf("         end of c->query body\n");
890 #endif
891
892         /* Now, when all POST data is read, we can call user callback */
893         c->local.head += url->func(&arg);
894         c->state = arg.state;
895         assert(c->local.head <= c->local.bufsize);
896
897         if (arg.last) {
898                 c->local.done++;
899                 c->io = NULL;
900                 c->flags &= ~FLAG_HAVE_TO_WRITE;
901         } else {
902                 c->flags |= FLAG_HAVE_TO_WRITE;
903                 // debug("c->flags |= FLAG_HAVE_TO_WRITE");
904         }
905 }
906
907 const char *
908 shttpd_get_header(struct shttpd_arg_t *arg, const char *header_name)
909 {
910         struct conn     *c = arg->priv;
911         size_t          len;
912         char            *p, *s, *e;
913
914         p = strchr(c->saved, '\n') + 1;
915         e = c->saved + c->reqlen;
916
917         len = strlen(header_name);
918
919         while (p < e) {
920                 if ((s = strchr(p, '\n')) != NULL)
921                         s[s[-1] == '\r' ? -1 : 0] = '\0';
922                 if (ncasecmp(header_name, p, len) == 0)
923                         return (p + len + 2);
924
925                 p += strlen(p) + 1;
926         }
927
928         return (NULL);
929 }
930
931
932 static void
933 free_headers_hnode(hnode_t *n, void *arg) {
934         u_free(n->hash_key);
935         u_free(n);
936 }
937
938 hash_t *
939 shttpd_get_all_headers(struct shttpd_arg_t *arg)
940 {
941         struct conn *c = arg->priv;
942         char        *p, *s, *e;
943         char *name, *value;
944         hash_t *hash = hash_create(HASHCOUNT_T_MAX, 0, 0);
945
946         hash_set_allocator(hash, NULL, free_headers_hnode, NULL);
947
948         p = strchr(c->saved, '\n') + 1;
949         e = c->saved + c->reqlen;
950         while (p < e) {
951                 name = p;
952                 if ((s = strchr(p, '\n')) != NULL) {
953                         if (s > p && s[-1] == '\r') {
954                                 s[-1] = '\0';
955                         }
956                         *s = '\0';
957                         p = s + 1;
958                 } else {
959                         p += strlen(p);
960                 }
961                 if ((p < e) && (*p == '\0')) {
962                         p++;
963                 }
964                 value = strchr(name, ':');
965                 if ((value == NULL) || ((value + 2) >= e) ) {
966                         continue;
967                 }
968                 *value = '\0';
969                 name = strdup(name);
970                 *value = ':';
971                 debug("%s: %s", name, value + 2);
972                 if (!hash_alloc_insert(hash, name, value + 2)) {
973                         u_free(name);
974                 }
975         }
976
977         return hash;
978 }
979
980
981
982 const char *
983 shttpd_get_env(struct shttpd_arg_t *arg, const char *env_name)
984 {
985         struct conn     *c = arg->priv;
986
987         if (strcmp(env_name, "REQUEST_METHOD") == 0)
988                 return (c->method);
989         else if (strcmp(env_name, "REMOTE_USER") == 0)
990                 return (c->user);
991         else if (strcmp(env_name, "REMOTE_ADDR") == 0)
992                 return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
993
994         return (NULL);
995 }
996
997 void
998 shttpd_register_url(struct shttpd_ctx *ctx,
999                 const char *url, shttpd_callback_t cb,
1000                 int authnotneeded, void *data)
1001 {
1002         struct userurl  *p;
1003
1004         if ((p = calloc(1, sizeof(*p))) != NULL) {
1005                 p->func         = cb;
1006                 p->data         = data;
1007                 p->authnotneeded = authnotneeded;
1008                 p->url          = u_strdup(url);
1009                 p->next         = ctx->urls;
1010                 ctx->urls       = p;
1011         }
1012 }
1013
1014 static void
1015 setopt(const char *var, const char *val)
1016 {
1017         struct opt      *opt;
1018
1019         if ((opt = swtoopt(0, var)) == NULL)
1020                 elog(ERR_FATAL, "setopt: unknown variable [%s]", var);
1021
1022         if (opt->tmp != NULL)
1023                 free(opt->tmp);
1024         opt->tmp = u_strdup(val);
1025 }
1026
1027
1028
1029 struct shttpd_ctx *
1030 shttpd_init(const char *config_file, ...)
1031 {
1032         va_list         ap;
1033         const char      *opt_name, *opt_value;
1034
1035         va_start(ap, config_file);
1036         while ((opt_name = va_arg(ap, const char *)) != NULL) {
1037                 opt_value = va_arg(ap, const char *);
1038                 setopt(opt_name, opt_value);
1039         }
1040         va_end(ap);
1041         (void) signal(SIGPIPE, SIG_IGN);
1042
1043         return (do_init(config_file, 0, NULL));
1044 }
1045
1046 void
1047 shttpd_protect_url(struct shttpd_ctx *ctx, const char *url, const char *file)
1048 {
1049         struct userauth *p;
1050
1051         if ((p = calloc(1, sizeof(*p))) != NULL) {
1052                 p->url          = u_strdup(url);
1053                 p->filename     = u_strdup(file);
1054                 p->next         = ctx->auths;
1055                 ctx->auths      = p;
1056         }
1057 }
1058
1059 const char *
1060 shttpd_get_var(struct shttpd_arg_t *arg, const char *var)
1061 {
1062         struct conn     *c = arg->priv;
1063         char            *p, *s, *e;
1064         size_t          len, i;
1065
1066         if ((p = c->query) == NULL)
1067                 return (NULL);
1068
1069         /* If the buffer has not been scanned yet, do it now */
1070         if (c->vars[0] == NULL)
1071                 for (i = 0; *p && i < NELEMS(c->vars); i++, p = e) {
1072                         c->vars[i] = p;
1073                         if ((s = strchr(p, '=')) == NULL)
1074                                 break;
1075                         *s++ = '\0';
1076                         if ((e = strchr(s, '&')) != NULL)
1077                                 *e++ = '\0';
1078                         else
1079                                 e = s + strlen(s);
1080                         urldecode(s, s);
1081                 }
1082
1083         /* Now, loop over all variables, find the right one, return value */
1084         len = strlen(var);
1085         for (i = 0; i < NELEMS(c->vars) && c->vars[i] != NULL; i++)
1086                 if (memcmp(var, c->vars[i], len) == 0)
1087                         return (c->vars[i] + len + 1);
1088
1089         return (NULL);
1090 }
1091
1092 int
1093 shttpd_get_post_query_len(struct shttpd_arg_t *arg)
1094 {
1095         struct conn     *c = arg->priv;
1096         return c->cclength;
1097 }
1098
1099
1100 char *
1101 shttpd_get_post_query(struct shttpd_arg_t *arg)
1102 {
1103         struct conn     *c = arg->priv;
1104         return c->query;
1105         /*
1106            char                 *p = c->query;
1107            int len;
1108
1109            if (p == NULL) {
1110            return -1;
1111            }
1112            if (length > c->cclength) {
1113            len = c->cclength;
1114            } else {
1115            len = length;
1116            }
1117
1118            memcpy(to, p, len);
1119
1120            return len;
1121            */
1122 }
1123
1124 int
1125 shttpd_get_http_version(struct shttpd_arg_t *arg)
1126 {
1127         struct conn     *c = arg->priv;
1128         char            b[PROTO_SIZE];
1129         char            *p, *q;
1130         int ver = 0, rev = 0;
1131
1132         p = b;
1133         q = c->proto;
1134         while(*q) {
1135                 *p++ = toupper(*q++);
1136         }
1137         *p = 0;
1138
1139         sscanf(b, "HTTP/%d.%d", &rev, &ver);
1140
1141         return ver;
1142 }
1143
1144
1145
1146
1147
1148
1149
1150 const char *
1151 shttpd_get_uri(struct shttpd_arg_t *arg)
1152 {
1153         struct conn     *c = arg->priv;
1154         return c->uri;
1155 }
1156
1157
1158 #else
1159 static void do_embedded(struct conn *c) { c->local.done++; }
1160 #endif /* EMBEDDED */
1161
1162 /*
1163  * strncpy() variant, that always nul-terminates destination.
1164  */
1165 static void
1166 mystrlcpy(register char *dst, register const char *src, size_t n)
1167 {
1168         for (; *src != '\0' && n > 1; n--)
1169                 *dst++ = *src++;
1170         *dst = '\0';
1171 }
1172
1173 /*
1174  * Sane snprintf(). Acts like snprintf(), but never return -1 or the
1175  * value bigger than supplied buffer.
1176  * Thanks Adam Zeldis to pointing snprintf()-caused vulnerability
1177  * in his audit report.
1178  */
1179 static int
1180 Snprintf(char *buf, size_t buflen, const char *fmt, ...)
1181 {
1182         va_list         ap;
1183         int             n;
1184
1185
1186         if (buflen == 0)
1187                 return (0);
1188
1189         va_start(ap, fmt);
1190         n = vsnprintf(buf, buflen, fmt, ap);
1191         va_end(ap);
1192
1193         if (n < 0 || n > (int) buflen - 1) {
1194                 elog(ERR_DEBUG, "vsnprintf returned %d (%s)", n, fmt);
1195                 n = buflen - 1;
1196         }
1197         buf[n] = '\0';
1198
1199         return (n);
1200 }
1201
1202 /*
1203  * Increment tail counter. If it becomes == head, flush both to 0
1204  */
1205 static void
1206 io_inc_tail(struct io *io, size_t n)
1207 {
1208         // debug("tail = %d; head = %d", io->tail,io->head);
1209         assert(io->tail <= io->head);
1210         assert(io->head <= io->bufsize);
1211         io->tail += n;
1212         assert(io->tail <= io->head);
1213         if (io->tail == io->head)
1214                 io->head = io->tail = 0;
1215 }
1216
1217
1218 /*
1219  * Case-insensitive string comparison, a-la strcmp()
1220  */
1221 static int
1222 casecmp(register const char *s1, register const char *s2)
1223 {
1224         for (; *s1 != '\0' && *s2 != '\0'; s1++, s2++)
1225                 if (tolower(*s1) != tolower(*s2))
1226                         break;
1227
1228         return (*s1 - *s2);
1229 }
1230
1231 /* Case insensitive memory comparison, strncasecmp() */
1232 static int
1233 ncasecmp(register const char *s1, register const char *s2, size_t len)
1234 {
1235         register const char     *e = s1 + len - 1;
1236         int                     ret;
1237
1238         for (; s1 < e && *s1 != '\0' && *s2 != '\0' &&
1239                         tolower(*s1) == tolower(*s2); s1++, s2++) ;
1240         ret = tolower(*s1) - tolower(*s2);
1241
1242         return (ret);
1243 }
1244
1245
1246 /*
1247  * Disconnect from remote side, free resources
1248  */
1249
1250
1251 static void
1252 free_parsed_data(struct conn *c)
1253 {
1254         /* If parse_headers() allocated any data, free it */
1255         if (c->useragent) {
1256                 free(c->useragent);
1257                 c->useragent = NULL;
1258         }
1259         if (c->user) {
1260                 free(c->user);
1261                 c->user = NULL;
1262         }
1263         if (c->cookie) {
1264                 free(c->cookie);
1265                 c->cookie = NULL;
1266         }
1267         if (c->ctype) {
1268                 free(c->ctype);
1269                 c->ctype = NULL;
1270         }
1271         if (c->referer) {
1272                 free(c->referer);
1273                 c->referer = NULL;
1274         }
1275         if (c->location) {
1276                 free(c->location);
1277                 c->location = NULL;
1278         }
1279         if (c->auth) {
1280                 free(c->auth);
1281                 c->auth = NULL;
1282         }
1283         if (c->path) {
1284                 free(c->path);
1285                 c->path = NULL;
1286         }
1287
1288         c->nposted = 0;
1289         if (c->range) {
1290                 free(c->range);
1291                 c->range = NULL;
1292         }
1293
1294         if (c->query) {
1295                 free(c->query);
1296                 c->query = NULL;
1297         }
1298         c->nposted = 0;
1299         c->cclength = 0;
1300 }
1301
1302
1303
1304 static void
1305 disconnect(struct conn *c)
1306 {
1307         int keep_alive = (c->flags & FLAG_KEEP_CONNECTION);
1308
1309         elog(ERR_DEBUG, "disconnecting %p", c);
1310
1311         free_parsed_data(c);
1312
1313         if (c->remote.buf) {
1314                 free(c->remote.buf);
1315                 c->remote.buf = NULL;
1316         }
1317         c->remote.head = 0;
1318         c->remote.tail = 0;
1319         c->remote.done = 0;
1320
1321         if (c->local.buf) {
1322                 free(c->local.buf);
1323                 c->local.buf = NULL;
1324         }
1325         c->local.head = 0;
1326         c->local.tail = 0;
1327         c->local.done = 0;
1328         if (keep_alive) {
1329                 c->flags &= (FLAG_SSLACCEPTED | FLAG_AUTHORIZED);
1330                 c->expire = current_time + KEEP_ALIVE_TIME;
1331                 elog(ERR_DEBUG, "connection %p is keeping alive for %d secs",
1332                                 c, KEEP_ALIVE_TIME);
1333                 return;
1334         }
1335         del_conn_from_ctx(c->ctx, c);
1336
1337         if (c->ctx->accesslog != NULL)
1338                 log_access(c->ctx->accesslog, c);
1339
1340         /* In inetd mode, exit if request is finished. */
1341         if (c->usr) {
1342                 free(c->usr);
1343                 c->usr = NULL;
1344         }
1345         if (c->pwd) {
1346                 free(c->pwd);
1347                 c->pwd = NULL;
1348         }
1349         if (inetd)
1350                 exit_flag++;
1351         /* Free resources */
1352         if (c->fd != -1) {
1353                 if (c->flags & FLAG_CGI)
1354                         (void) closesocket(c->fd);
1355                 else
1356                         (void) close(c->fd);
1357         }
1358         if (c->dirp)            (void) closedir(c->dirp);
1359 #ifdef HAVE_SSL
1360         if (c->ssl)             SSL_free(c->ssl);
1361 #endif
1362         (void) shutdown(c->sock, 2);
1363         (void) closesocket(c->sock);
1364         free(c);
1365 }
1366
1367 #ifdef HAVE_SSL
1368 /*
1369  * Perform SSL handshake
1370  */
1371 static void
1372 handshake(struct conn *c)
1373 {
1374         int     n;
1375         if ((n = SSL_accept(c->ssl)) == 0) {
1376                 n = SSL_get_error(c->ssl, n);
1377                 if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE)
1378                         c->flags |= FLAG_FINISHED;
1379                 elog(ERR_INFO, "handshake: SSL_accept error %d", n);
1380         } else {
1381                 elog(ERR_DEBUG, "handshake: SSL accepted. sock %d", c->sock);
1382                 c->flags |= FLAG_SSLACCEPTED;
1383         }
1384 }
1385 #endif
1386
1387 #define INCREMENT_KB(nbytes, static_counter, kbytes)            \
1388         do {                                                            \
1389                 static_counter += nbytes;                               \
1390                 if (static_counter > 1024) {                            \
1391                         kbytes += static_counter / 1024;                \
1392                         static_counter %= 1024;                         \
1393                 }                                                       \
1394         } while (0)
1395
1396 /*
1397  * Send data to a remote end. Return bytes sent.
1398  */
1399 static int
1400 writeremote(struct conn *c, const char *buf, size_t len)
1401 {
1402         static int      out;
1403         int             n;
1404
1405         /* Make sure we will not send more than needed */
1406         if (c->sclength && c->nsent + len > c->sclength + c->shlength)
1407                 len = c->sclength + c->shlength - c->nsent;
1408
1409         /* Send the data via socket or SSL connection */
1410 #ifdef HAVE_SSL
1411         if (c->ssl) {
1412                 n = SSL_write(c->ssl, buf, len);
1413         }
1414         else
1415 #endif
1416                 n = send(c->sock, buf, len, 0);
1417
1418         if (n > 0) {
1419                 c->nsent += n;
1420                 INCREMENT_KB(n, out, c->ctx->kb_out);
1421         }
1422
1423         if (n == 0 || (n < 0 && ERRNO != EWOULDBLOCK) ||
1424                         (c->sclength > 0 && c->nsent >= c->sclength + c->shlength)) {
1425                 c->remote.done = 1;
1426         }
1427
1428         elog(ERR_DEBUG, "writeremote: %d %d %u %u %u %d [%d: %s]",
1429                         n, len, c->nsent, c->sclength, c->shlength,
1430                         c->remote.done, errno, strerror(errno));
1431
1432         return (n);
1433 }
1434
1435 /*
1436  * Read data from the remote end. Return bytes read.
1437  */
1438 static int
1439 readremote(struct conn *c, char *buf, size_t len)
1440 {
1441         static int      in;
1442         int             n = -1;
1443 #ifdef HAVE_SSL
1444         int ssl_err;
1445         if (c->ssl) {
1446                 if (!(c->flags & FLAG_SSLACCEPTED)) {
1447                         handshake(c);
1448                 }
1449                 if (c->flags & FLAG_FINISHED) {
1450                         return -1;
1451                 }
1452                 n = SSL_read(c->ssl, buf, len);
1453                 if (n < 0) {
1454                         ssl_err = SSL_get_error(c->ssl, n);
1455                         if (ssl_err == SSL_ERROR_WANT_READ) {
1456                                 return -1;
1457                         }
1458                 }
1459         } else
1460 #endif
1461                 n = recv(c->sock, buf, len, 0);
1462         if (n > 0)
1463                 INCREMENT_KB(n, in, c->ctx->kb_in);
1464
1465         if (n == 0 || (n < 0 &&
1466                                 ((ERRNO != EWOULDBLOCK))))
1467                 c->remote.done = 1;
1468         return (n);
1469 }
1470
1471
1472 /*
1473  * Put given file descriptor in blocking (block == 1)
1474  * or non-blocking (block == 0) mode.
1475  * Return 0 if success, or -1
1476  */
1477 static int
1478 nonblock(int fd)
1479 {
1480         int     ret = -1;
1481         int     flags;
1482
1483         if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
1484                 elog(ERR_INFO, "nonblock: fcntl(F_GETFL): %d", ERRNO);
1485         else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0)
1486                 elog(ERR_INFO, "nonblock: fcntl(F_SETFL): %d", ERRNO);
1487         else
1488                 ret = 0;        /* Success */
1489
1490         return (ret);
1491 }
1492
1493 /*
1494  * Setup listening socket on given port, return socket
1495  */
1496 int
1497 shttpd_open_port(int port)
1498 {
1499         int             sock, on = 1;
1500         struct usa      sa;
1501
1502
1503         sa.len                          = sizeof(sa.u.sin);
1504         sa.u.sin.sin_family             = AF_INET;
1505         sa.u.sin.sin_port               = htons((uint16_t) port);
1506         sa.u.sin.sin_addr.s_addr        = htonl(INADDR_ANY);
1507
1508         if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == -1)
1509                 elog(ERR_FATAL, "shttpd_open_port: socket: %s",strerror(ERRNO));
1510         else if (nonblock(sock) != 0)
1511                 elog(ERR_FATAL, "shttpd_open_port: nonblock");
1512         else if (setsockopt(sock, SOL_SOCKET,
1513                                 SO_REUSEADDR,(char *) &on, sizeof(on)) != 0)
1514                 elog(ERR_FATAL, "shttpd_open_port: setsockopt");
1515         else if (bind(sock, &sa.u.sa, sa.len) < 0)
1516                 elog(ERR_FATAL, "shttpd_open_port: bind(%d): %s",
1517                                 port, strerror(ERRNO));
1518         else if (listen(sock, 128) != 0)
1519                 elog(ERR_FATAL, "shttpd_open_port: listen: %s",strerror(ERRNO));
1520         (void) fcntl(sock, F_SETFD, FD_CLOEXEC);
1521
1522         return (sock);
1523 }
1524
1525 /*
1526  * Check whether full request is buffered
1527  * Return request length, or 0
1528  */
1529 static int
1530 getreqlen(const char *buf, size_t buflen)
1531 {
1532         const char      *s, *e;
1533         int             len = 0;
1534
1535         for (s = buf, e = s + buflen - 1; len == 0 && s < e; s++)
1536                 if (!isprint(*(unsigned char *) s) && *s != '\r' && *s != '\n')
1537                         len = -1;
1538                 else if (s[0] == '\n' && s[1] == '\n')
1539                         len = s - buf + 2;
1540                 else if (s[0] == '\n' && &s[1] < e &&
1541                                 s[1] == '\r' && s[2] == '\n')
1542                         len = s - buf + 3;
1543
1544         return (len);
1545 }
1546
1547 /*
1548  * Write an HTTP access log into a file `logfile'
1549  */
1550 static void
1551 log_access(FILE *fp, const struct conn *c)
1552 {
1553         char    date[64];
1554
1555         strftime(date, sizeof(date), "%d/%b/%Y %H:%M:%S", localtime(&current_time));
1556         (void) fprintf(fp, "%s - %s [%s] \"%s %s %s\" %d %lu ",
1557                         inet_ntoa(c->sa.u.sin.sin_addr), c->user ? c->user : "-",
1558                         date, c->method, c->uri, c->proto, c->status,
1559                         c->nsent > c->shlength ? c->nsent - c->shlength : 0);
1560
1561         if (c->referer)
1562                 (void) fprintf(fp, "\"%s\"", c->referer);
1563         else
1564                 (void) fputc('-', fp);
1565         (void) fputc(' ', fp);
1566
1567         if (c->useragent)
1568                 (void) fprintf(fp, "\"%s\" ", c->useragent);
1569         else
1570                 (void) fputc('-', fp);
1571
1572         (void) fputc('\n', fp);
1573         (void) fflush(fp);
1574 }
1575
1576 /*
1577  * Send an error back to a client.
1578  */
1579 static void
1580 senderr(struct conn *c, int status, const char *descr,
1581                 const char *headers, const char *fmt, ...)
1582 {
1583         va_list ap;
1584         char    msg[c->local.bufsize];
1585         int     n;
1586
1587         c->shlength = n = Snprintf(msg, sizeof(msg),
1588                         "HTTP/1.1 %d %s\r\nConnection: close\r\n%s%s\r\n%d ",
1589                         //       "HTTP/1.1 %d %s\r\n%s%s\r\n%d ",
1590                         status, descr, headers, headers[0] == '\0' ? "" : "\r\n", status);
1591         va_start(ap, fmt);
1592         n += vsnprintf(msg + n, sizeof(msg) - n, fmt, ap);
1593         if (n > (int) sizeof(msg))
1594                 n = sizeof(msg);
1595         va_end(ap);
1596         mystrlcpy(c->local.buf, msg, c->local.bufsize);
1597         c->local.head = n;
1598         c->local.tail = 0;
1599         c->flags &= ~FLAG_KEEP_CONNECTION;
1600         elog(ERR_DEBUG, "%s: [%s]", "senderr", c->local.buf);
1601         c->status = status;
1602         c->local.done++;
1603 }
1604
1605 /*
1606  * Convert month to the month number. Return -1 on error, or month number
1607  */
1608 static int
1609 montoi(const char *s)
1610 {
1611         static const char *ar[] = {
1612                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1613                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1614         };
1615         size_t  i;
1616
1617         for (i = 0; i < NELEMS(ar); i++)
1618                 if (casecmp(s, ar[i]) == 0)
1619                         return (i);
1620
1621         return (-1);
1622 }
1623
1624 /*
1625  * Parse date-time string, and return the corresponding time_t value
1626  */
1627 static time_t
1628 datetosec(const char *s)
1629 {
1630         struct tm       tm;
1631         char            mon[32];
1632         int             sec, min, hour, mday, month, year;
1633
1634         (void) memset(&tm, 0, sizeof(tm));
1635         sec = min = hour = mday = month = year = 0;
1636
1637         if (((sscanf(s, "%d/%3s/%d %d:%d:%d",
1638                                                 &mday, mon, &year, &hour, &min, &sec) == 6) ||
1639                                 (sscanf(s, "%d %3s %d %d:%d:%d",
1640                                         &mday, mon, &year, &hour, &min, &sec) == 6) ||
1641                                 (sscanf(s, "%*3s, %d %3s %d %d:%d:%d",
1642                                         &mday, mon, &year, &hour, &min, &sec) == 6) ||
1643                                 (sscanf(s, "%d-%3s-%d %d:%d:%d",
1644                                         &mday, mon, &year, &hour, &min, &sec) == 6)) &&
1645                         (month = montoi(mon)) != -1) {
1646                 tm.tm_mday      = mday;
1647                 tm.tm_mon       = month;
1648                 tm.tm_year      = year;
1649                 tm.tm_hour      = hour;
1650                 tm.tm_min       = min;
1651                 tm.tm_sec       = sec;
1652         }
1653
1654         if (tm.tm_year > 1900)
1655                 tm.tm_year -= 1900;
1656         else if (tm.tm_year < 70)
1657                 tm.tm_year += 100;
1658
1659         return (mktime(&tm));
1660 }
1661
1662
1663
1664 /*
1665  * Decode urlencoded string. from and to may point to the same location
1666  */
1667 static void
1668 urldecode(char *from, char *to)
1669 {
1670         int     i, a, b;
1671 #define HEXTOI(x)  (isdigit(x) ? x - '0' : x - 'W')
1672         for (i = 0; *from != '\0'; i++, from++) {
1673                 if (from[0] == '%' &&
1674                                 isxdigit((unsigned char) from[1]) &&
1675                                 isxdigit((unsigned char) from[2])) {
1676                         a = tolower(from[1]);
1677                         b = tolower(from[2]);
1678                         to[i] = (HEXTOI(a) << 4) | HEXTOI(b);
1679                         from += 2;
1680                 } else if (from[0] == '+') {
1681                         to[i] = ' ';
1682                 } else {
1683                         to[i] = from[0];
1684                 }
1685         }
1686         to[i] = '\0';
1687 }
1688
1689 /*
1690  * Protect from document root traversal using "../../"
1691  */
1692 static void
1693 killdots(char *file)
1694 {
1695         char    *s = file, *dup = malloc(strlen(file) + 1), *p = dup;
1696
1697         if (dup == NULL)
1698                 return;
1699
1700         while (*s != '\0') {
1701                 *p++ = *s++;
1702                 if (s[-1] == '/')
1703                         while (*s == '.' || *s == '/')
1704                                 s++;
1705         }
1706         *p = '\0';
1707         (void) strcpy(file, dup);
1708         free(dup);
1709 }
1710
1711 /*
1712  * Fetch header value into specified destination
1713  */
1714 static char *
1715 fetch(const char *src, char *dst, size_t len)
1716 {
1717         const char      *p;
1718
1719         *dst = '\0';
1720         if ((p = strchr(src, '\r')) || (p = strchr(src, '\n'))) {
1721                 len--;  /* For terminating '\0' */
1722                 if (p - src < (int) len)
1723                         len = p - src;
1724                 (void) memcpy(dst, src, len);
1725                 dst[len] = '\0';
1726         }
1727
1728         return (dst);
1729 }
1730
1731 /*
1732  * Parse HTTP headers, filling values in struct conn
1733  */
1734 static void
1735 parse_headers(struct conn *c, char *s)
1736 {
1737         char            val[IO_MAX];
1738         struct header   *header;
1739         union variant   *v;
1740
1741         /* Loop through all headers in the request */
1742         while (s != NULL && s[0] != '\n' && s[0] != '\r') {
1743                 /* Is this header known to us ? */
1744                 for (header = headers; header->len != 0; header++)
1745                         if (ncasecmp(s, header->name, header->len) == 0)
1746                                 break;
1747
1748                 /* If the header is known to us, store its value */
1749                 if (header->len != 0) {
1750
1751                         /* Fetch the header value into val */
1752                         fetch(s + header->len, val, sizeof(val));
1753
1754                         /* Find place in a connection structure to store it */
1755                         v = (union variant *) ((char *) c + header->offset);
1756
1757                         /* Fetch header value into the connection structure */
1758                         if (header->type == HDR_STRING) {
1759                                 if (v->value_str == NULL)
1760                                         v->value_str = u_strdup(val);
1761                         } else if (header->type == HDR_INT) {
1762                                 v->value_int = strtoul(val, NULL, 10);
1763                         } else if (header->type == HDR_DATE) {
1764                                 v->value_time = datetosec(val);
1765                         }
1766                 }
1767
1768                 /* Shift to the next header */
1769                 if ((s = strchr(s, '\n')) != NULL)
1770                         s++;
1771         }
1772
1773         return;
1774
1775 }
1776
1777
1778
1779
1780
1781 /*
1782  * HTTP digest authentication
1783  */
1784
1785 void
1786 shttpd_register_bauth_callback(struct shttpd_ctx *ctx,
1787                 shttpd_bauth_callback_t bauthf)
1788 {
1789         ctx->bauthf = bauthf;
1790 }
1791
1792 void
1793 shttpd_register_dauth_callback(struct shttpd_ctx *ctx,
1794                 shttpd_dauth_callback_t dauthf)
1795 {
1796         ctx->dauthf = dauthf;
1797 }
1798
1799
1800 static void
1801 fetchfield(const char **from, char *to, int len, int shift)
1802 {
1803         int             n;
1804         char            fmt[20];
1805         const char      *p = *from + shift;
1806
1807         *from = p;
1808
1809         if (*p == '"') {
1810                 Snprintf(fmt, sizeof(fmt), "%%%d[^\"]%%n", len - 1);
1811                 p++;
1812         } else {
1813                 Snprintf(fmt, sizeof(fmt), "%%%d[^ \t,]%%n", len - 1);
1814         }
1815
1816         //elog(ERR_DEBUG, "fetchfield: [%s] [%s]", fmt, p);
1817
1818         if (sscanf(p, fmt, to, &n)) {
1819                 p += n;
1820                 *from = p;
1821         }
1822 }
1823
1824 /*
1825  * Fetch a password provided by user.
1826  * Return 1 if success, 0 otherwise.
1827  */
1828 static int
1829 getauth(struct conn *c, struct digest *dig)
1830 {
1831         const char      *p = c->auth, *e = p + strlen(c->auth);
1832
1833         if (ncasecmp(p, "Digest ", 7) != 0)
1834                 return (0);
1835
1836         (void) memset(dig, 0, sizeof(dig));
1837
1838         for (p += 7; p < e; p++)
1839                 if (ncasecmp(p, "username=", 9) == 0)
1840                         fetchfield(&p, dig->user, sizeof(dig->user), 9);
1841                 else if (ncasecmp(p, "nonce=", 6) == 0)
1842                         fetchfield(&p, dig->nonce, sizeof(dig->nonce), 6);
1843                 else if (ncasecmp(p, "response=", 9) == 0)
1844                         fetchfield(&p, dig->resp, sizeof(dig->resp), 9);
1845                 else if (ncasecmp(p, "uri=", 4) == 0)
1846                         fetchfield(&p, dig->uri, sizeof(dig->uri), 4);
1847                 else if (ncasecmp(p, "qop=", 4) == 0)
1848                         fetchfield(&p, dig->qop, sizeof(dig->qop), 4);
1849                 else if (ncasecmp(p, "cnonce=", 7) == 0) {
1850                         if (*(p + 7) != '"') {
1851                                 return 0;
1852                         }
1853                         char *pp = strchr(p+8, '"');
1854                         if (pp == NULL) {
1855                                 return 0;
1856                         }
1857                         size_t L = (pp - p) - 7;
1858                         char *bb = malloc(L + 1);
1859                         if (bb == NULL) {
1860                                 return 0;
1861                         }
1862                         fetchfield(&p, bb, L + 1, 7);
1863                         //            p = pp + L;
1864                         dig->cnonce = bb;
1865                 } else if (ncasecmp(p, "nc=", 3) == 0) {
1866                         fetchfield(&p, dig->nc, sizeof(dig->nc), 3);
1867                 }
1868
1869         elog(ERR_DEBUG, "[%s] [%s] [%s] [%s] [%s] [%s]",
1870                         dig->user, dig->uri, dig->resp, dig->qop, dig->cnonce, dig->nc);
1871         if (dig->cnonce == NULL) {
1872                 return 0;
1873         }
1874         return (1);
1875 }
1876
1877
1878
1879 /*
1880  * Check authorization. Return 1 if not needed or authorized, 0 otherwise
1881  */
1882 static int
1883 checkauth(struct conn *c, const char *path)
1884 {
1885         struct digest   di;
1886         char *p, *pp;
1887         int  l;
1888         int res;
1889         struct shttpd_ctx *ctx = c->ctx;
1890
1891         if (c->flags & FLAG_AUTHORIZED) {
1892                 return 1;
1893         }
1894         if (!ctx->bauthf && !ctx->dauthf) {
1895                 return 1;
1896         }
1897         if (c->auth == NULL) {
1898                 return 0;
1899         }
1900
1901         if (ncasecmp(c->auth, "Digest ", 7) == 0) {
1902                 if (ctx->dauthf == NULL) {
1903                         return 0;
1904                 }
1905                 if (getauth(c, &di) == 0) {
1906                         return 0;
1907                 }
1908                 res = ctx->dauthf(ctx->realm, c->method, &di);
1909                 if (res) {
1910                         c->flags |= FLAG_AUTHORIZED;
1911                 }
1912                 u_free(di.cnonce);
1913                 return res;
1914         }
1915
1916         if (ncasecmp(c->auth, "Basic ", 6) != 0) {
1917                 return 0;
1918         }
1919
1920         if (ctx->bauthf == NULL) {
1921                 return 0;
1922         }
1923
1924         p = c->auth + 5;
1925         while ((*p == ' ') || (*p == '\t')) {
1926                 p++;
1927         }
1928         pp = p;
1929         while ((*p != ' ') && (*p != '\t') && (*p != '\r')
1930                         && (*p != '\n') && (*p != 0)) {
1931                 p++;
1932         }
1933
1934         if (pp == p) {
1935                 return 0;
1936         }
1937         *p = 0;
1938
1939         // use di.uri as a bufer. It's big ehough
1940         l = ws_base64_decode(pp, p - pp, di.uri);
1941         if (l <= 0) {
1942                 return 0;
1943         }
1944
1945         di.uri[l] = 0;
1946         p = di.uri;
1947         pp = p;
1948         p = strchr(p, ':');
1949         if (p == NULL) {
1950                 return 0;
1951         }
1952         *p++ = 0;
1953
1954         res = ctx->bauthf(pp, p);
1955         if (res) {
1956                 //authorized(net_0)
1957                 c->usr = strdup(pp);
1958                 c->pwd = strdup(p);
1959                 c->flags |= FLAG_AUTHORIZED;
1960         }
1961
1962         return res;
1963 }
1964
1965 void      shttpd_get_credentials(struct shttpd_arg_t *arg,
1966                 char **user, char **pwd)
1967 {
1968         struct conn *c = (struct conn *)arg->priv;
1969
1970         *user = c->usr;
1971         *pwd =  c->pwd;
1972 }
1973
1974
1975 static void
1976 send_authorization_request(struct conn *c)
1977 {
1978         char    buf[512];
1979         int n = 0;
1980
1981
1982         if (c->ctx->dauthf) {
1983                 n = Snprintf(buf, sizeof(buf),
1984                                 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
1985                                 "nonce=\"%lu\"", c->ctx->realm, (unsigned long) current_time);
1986                 if (c->ctx->bauthf) {
1987                         n += Snprintf(buf +n, sizeof(buf) - n, "\r\n");
1988                 }
1989         }
1990         if (c->ctx->bauthf) {
1991                 (void) Snprintf(buf + n, sizeof(buf) - n,
1992                                 "WWW-Authenticate: Basic realm=\"%s\"", c->ctx->realm);
1993         }
1994         senderr(c, 401, "Unauthorized", buf, "Authorization required");
1995         //    c->flags |= FLAG_KEEP_CONNECTION;
1996 }
1997
1998
1999
2000 /*
2001  * Handle request
2002  */
2003 static void
2004 handle(struct conn *c)
2005 {
2006         char                    path[FILENAME_MAX + IO_MAX];
2007         struct userurl          *userurl;
2008         char *p;
2009
2010         elog(ERR_DEBUG, "handle: [%s]", c->remote.buf);
2011
2012         if ((p = strchr(c->uri, '?')) != NULL) {
2013                 *p++ = '\0';
2014         }
2015         if (c->http_method != METHOD_POST) {
2016                 senderr(c, 405, "Method not allowed", "", "Must be POST");
2017                 return;
2018         }
2019
2020         c->query = NULL;
2021         urldecode(c->uri, c->uri);
2022         killdots(c->uri);
2023         (void) Snprintf(path, sizeof(path), "%s%s", c->ctx->root, c->uri);
2024
2025         if ((userurl = isregistered(c->ctx, c->uri)) == NULL) {
2026                 senderr(c, 405, "Unknown uri", "", c->uri);
2027                 return;
2028         }
2029         if (!userurl->authnotneeded && checkauth(c, path) != 1) {
2030                 send_authorization_request(c);
2031                 return;
2032         }
2033         c->userurl = userurl;
2034         c->io = do_embedded;
2035         c->flags |= FLAG_ALWAYS_READY;
2036 }
2037
2038 /*
2039  * Parse HTTP request
2040  */
2041 static void
2042 parse_request(struct conn *c)
2043 {
2044         char    fmt[32];
2045         char    *s = c->remote.buf;
2046
2047
2048         (void) snprintf(fmt, sizeof(fmt), "%%%us %%%us %%%us",
2049                         (unsigned) sizeof(c->method) - 1, (unsigned) sizeof(c->uri) - 1,
2050                         (unsigned) sizeof(c->proto) - 1);
2051
2052         /* Get the request line */
2053         if (sscanf(s, fmt, c->method, c->uri, c->proto) != 3) {
2054                 senderr(c, 404, "Bad Request","", "Bad Request");
2055         } else if (c->uri[0] != '/') {
2056                 senderr(c, 404, "Bad Request","", "Bad Request");
2057         } else if (ncasecmp(c->proto, "HTTP", 4) != 0) {
2058                 senderr(c, 501, "Bad Protocol","", "Procotol Not Supported");
2059         } else if (ncasecmp(c->method, "GET", 3) == 0) {
2060                 c->http_method = METHOD_GET;
2061         } else if (ncasecmp(c->method, "POST", 4) == 0) {
2062                 c->http_method = METHOD_POST;
2063         } else if (ncasecmp(c->method, "HEAD", 4) == 0) {
2064                 c->http_method = METHOD_HEAD;
2065         } else if (ncasecmp(c->method, "PUT", 3) == 0) {
2066                 c->http_method = METHOD_PUT;
2067         } else if (ncasecmp(c->method, "DELETE", 6) == 0) {
2068                 c->http_method = METHOD_DELETE;
2069         } else {
2070                 senderr(c, 501, "Not Implemented", "","Method Not Implemented");
2071         }
2072
2073         /* XXX senderr() should set c->local.done flag! */
2074         if (c->local.done != 0) {
2075                 return;
2076         }
2077         (void) strcpy(c->saved, s);     /* Save whole request */
2078         parse_headers(c, strchr(s, '\n') + 1);
2079         handle(c);
2080         c->flags |= FLAG_PARSED;
2081 }
2082
2083 /*
2084  * Process given connection
2085  */
2086 static void
2087 serve(struct shttpd_ctx *ctx, void *ptr)
2088 {
2089         struct conn     *c = ptr;
2090         int             n, len;
2091
2092         assert(ctx == c->ctx);
2093         if (c->remote.buf == NULL) {
2094                 c->remote.buf = malloc(c->remote.bufsize);
2095                 if (c->remote.buf == NULL) {
2096                         elog(ERR_DEBUG, "No memory");
2097                         c->flags = FLAG_FINISHED;
2098                         return;
2099                 }
2100                 memset(c->remote.buf, 'b', c->remote.bufsize);
2101                 c->remote.buf[c->remote.bufsize - 1] = 0;
2102                 c->flags |= FLAG_KEEP_CONNECTION;
2103         }
2104         if (c->local.buf == NULL) {
2105                 c->local.buf = malloc(c->remote.bufsize);
2106                 if (c->local.buf == NULL) {
2107                         elog(ERR_DEBUG, "No memory");
2108                         c->flags = FLAG_FINISHED;
2109                         return;
2110                 }
2111                 c->flags |= FLAG_KEEP_CONNECTION;
2112         }
2113
2114 #if 1
2115         elog(ERR_DEBUG, "serve: enter %p: local %d.%d.%d, remote %d.%d.%d", c,
2116                         c->local.done, c->local.head, c->local.tail,
2117                         c->remote.done, c->remote.head, c->remote.tail);
2118 #endif
2119         /* Read from remote end */
2120         assert(c->sock != -1);
2121         if (c->flags & FLAG_SOCK_READABLE) {
2122                 len = IO_SPACELEN(&c->remote);
2123                 n = readremote(c, c->remote.buf + c->remote.head, len);
2124                 if (n > 0) {
2125                         c->remote.head += n;
2126                         c->remote.buf[c->remote.head] = '\0';
2127                         c->expire += EXPIRE_TIME;
2128                 } else if (!(c->flags & FLAG_PARSED) && c->remote.done) {
2129                         if (n == 0) {
2130                                 // connection closed by peer
2131                                 c->flags &= ~FLAG_KEEP_CONNECTION;
2132                         }
2133                         c->flags |= FLAG_FINISHED;
2134                 }
2135                 if (n < 0 ) {
2136                         c->flags &= ~FLAG_KEEP_CONNECTION;
2137                 }
2138                 elog(ERR_DEBUG, "serve: readremote returned %d", n);
2139         }
2140
2141         if (c->flags & FLAG_FINISHED) {
2142                 return;
2143         }
2144
2145         /* Try to parse the request from remote endpoint */
2146         if (!(c->flags & FLAG_PARSED)) {
2147                 c->reqlen = getreqlen(c->remote.buf, c->remote.head);
2148                 if (c->reqlen == -1) {
2149                         senderr(c, 400, "Bad Request", "", "Bad request");
2150                 } else if (c->reqlen == 0 && IO_SPACELEN(&c->remote) <= 1) {
2151                         senderr(c, 400, "Bad Request", "","Request is too big");
2152                 } else if (c->reqlen > 0) {
2153                         parse_request(c);
2154                 }
2155         }
2156
2157         /* Read from the local endpoint */
2158         if (!(c->flags & FLAG_FINISHED) && c->io &&
2159                         (c->flags & (FLAG_FD_READABLE | FLAG_SOCK_READABLE |
2160                                      FLAG_HAVE_TO_WRITE))) {
2161                 c->io(c);
2162                 c->expire += EXPIRE_TIME;
2163         }
2164
2165         if (c->flags & FLAG_SOCK_WRITABLE) {
2166                 len = IO_DATALEN(&c->local);
2167                 n = writeremote(c, c->local.buf + c->local.tail, len);
2168                 if (n > 0)
2169                         io_inc_tail(&c->local, n);
2170                 elog(ERR_DEBUG, "serve: writeremote returned %d", n);
2171         }
2172
2173         if ((c->remote.done && c->remote.head == 0) ||
2174                         (c->local.done && c->local.head == 0)) {
2175                 c->flags |= FLAG_FINISHED;
2176         }
2177 #if 1
2178         elog(ERR_DEBUG, "serve: exit %p: local %d.%d.%d, remote %d.%d.%d", c,
2179                         c->local.done, c->local.head, c->local.tail,
2180                         c->remote.done, c->remote.head, c->remote.tail);
2181 #endif
2182 }
2183
2184 void
2185 shttpd_add(struct shttpd_ctx *ctx, int sock)
2186 {
2187         struct conn     *c;
2188         struct usa      sa;
2189 #ifdef HAVE_SSL
2190         SSL             *ssl = NULL;
2191 #endif
2192         sa.len = sizeof(sa.u.sin);
2193         (void) nonblock(sock);
2194
2195         if (getpeername(sock, &sa.u.sa, &sa.len)) {
2196                 elog(ERR_INFO, "shttpd_add: %s", strerror(errno));
2197 #ifdef HAVE_SSL
2198         } else if (ctx->ssl_ctx && (ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
2199                 elog(ERR_INFO, "shttpd_add: SSL_new: %s", strerror(ERRNO));
2200                 (void) closesocket(sock);
2201         } else if (ctx->ssl_ctx && SSL_set_fd(ssl, sock) == 0) {
2202                 elog(ERR_INFO, "shttpd_add: SSL_set_fd: %s", strerror(ERRNO));
2203                 (void) closesocket(sock);
2204                 SSL_free(ssl);
2205 #endif
2206         } else if ((c = calloc(1, sizeof(*c))) == NULL) {
2207                 (void) closesocket(sock);
2208                 elog(ERR_INFO, "shttpd_add: calloc: %s", strerror(ERRNO));
2209         } else {
2210                 c->sa           = sa;
2211                 c->sock         = sock;
2212                 c->watch        = serve;
2213                 c->watch_data   = c;
2214                 c->fd           = -1;
2215 #ifdef HAVE_SSL
2216                 c->ssl          = ssl;
2217 #endif
2218                 c->birth        = current_time;
2219                 c->expire       = current_time + EXPIRE_TIME;
2220                 c->local.bufsize = IO_MAX;
2221                 c->remote.bufsize = IO_MAX;
2222                 (void) fcntl(sock, F_SETFD, FD_CLOEXEC);
2223 #ifdef HAVE_SSL
2224                 if (ssl)
2225                         handshake(c);
2226 #endif
2227                 ctx->nrequests++;
2228
2229                 add_conn_to_ctx(ctx, c);
2230
2231                 elog(ERR_DEBUG, "shttpd_add: ctx %p, sock %d, conn %p",
2232                                 ctx, sock, c);
2233         }
2234 }
2235
2236 int
2237 shttpd_active(struct shttpd_ctx *ctx)
2238 {
2239         return (ctx->nactive);
2240 }
2241
2242 static void
2243 do_accept(struct shttpd_ctx *ctx, void *ptr)
2244 {
2245         int             sock;
2246         struct usa      sa;
2247
2248         sa.len = sizeof(sa.u.sin);
2249
2250         sock = inetd ? fileno(stdin) : accept((int)((char *)ptr - (char *)NULL), &sa.u.sa, &sa.len);
2251         if (sock == -1)
2252                 elog(ERR_INFO, "do_accept(%d): %s", (int)((char *)ptr - (char *)NULL), strerror(ERRNO));
2253         else
2254                 shttpd_add(ctx, sock);
2255 }
2256
2257 /*
2258  * Setup user watch. If func is NULL, remove it
2259  */
2260 void
2261 shttpd_listen(struct shttpd_ctx *ctx, int sock)
2262 {
2263         struct conn     *c;
2264
2265         if ((c = calloc(1, sizeof(*c))) == NULL)
2266                 elog(ERR_FATAL, "shttpd_listen: cannot allocate connection");
2267
2268         c->watch        = do_accept;
2269         c->watch_data   = (void *)((char *)NULL + sock);
2270         c->sock         = sock;
2271         c->fd           = -1;
2272         c->local.bufsize = IO_MAX;
2273         c->remote.bufsize = IO_MAX;
2274         c->expire       = (time_t) LONG_MAX;    /* Never expires */
2275         add_conn_to_ctx(ctx, c);
2276
2277         elog(ERR_DEBUG, "shttpd_listen: ctx %p, sock %d, conn %p", ctx,sock,c);
2278 }
2279
2280 int
2281 shttpd_accept(int lsn_sock, int milliseconds)
2282 {
2283         struct timeval  tv;
2284         struct usa      sa;
2285         fd_set          read_set;
2286         int             sock = -1;
2287
2288         tv.tv_sec       = milliseconds / 1000;
2289         tv.tv_usec      = milliseconds % 1000;
2290         sa.len          = sizeof(sa.u.sin);
2291         FD_ZERO(&read_set);
2292         FD_SET(lsn_sock, &read_set);
2293
2294         if (select(lsn_sock + 1, &read_set, NULL, NULL, &tv) == 1)
2295                 sock = accept(lsn_sock, &sa.u.sa, &sa.len);
2296
2297         return (sock);
2298 }
2299
2300 /*
2301  * One iteration of server loop.
2302  */
2303 void
2304 shttpd_poll(struct shttpd_ctx *ctx, int milliseconds)
2305 {
2306         struct conn     *c, *nc;
2307         struct timeval  tv;                     /* Timeout for select() */
2308         fd_set          read_set, write_set;
2309         int             max_fd = 0, msec = milliseconds;
2310
2311         current_time = time(0);
2312         FD_ZERO(&read_set);
2313         FD_ZERO(&write_set);
2314
2315         for (c = ctx->connections; c != NULL; c = c->next) {
2316                 c->flags &= ~FLAG_IO_READY;
2317
2318 #define MERGEFD(fd,set) \
2319                 do {FD_SET(fd, set); if (fd > max_fd) max_fd = fd;} while (0)
2320
2321                 /* If there is space to read, do it */
2322                 if (IO_SPACELEN(&c->remote))
2323                         MERGEFD(c->sock, &read_set);
2324
2325                 /* If there is data in local buffer, add to write set */
2326                 if ((c->flags & FLAG_HAVE_TO_WRITE) ||
2327                                 (IO_DATALEN(&c->local))) {
2328                         elog(ERR_DEBUG, "sock %d ready to write from %d to %d",
2329                                         c->sock, c->local.tail, c->local.head);
2330                         MERGEFD(c->sock, &write_set);
2331                 }
2332 #if 0
2333                 /* If not selectable, continue */
2334                 if (c->flags & FLAG_ALWAYS_READY) {
2335                         msec = 0;
2336                 } else {
2337                         /* If there is space left in local buffer, read more */
2338                         if (IO_SPACELEN(&c->local) && c->fd != -1)
2339                                 MERGEFD(c->fd, &read_set);
2340
2341                         /* Any data to be passed to the remote end ? */
2342                         if (IO_DATALEN(&c->remote) && c->fd != -1)
2343                                 MERGEFD(c->fd, &write_set);
2344                 }
2345 #endif
2346         }
2347
2348         tv.tv_sec = msec / 1000;
2349         tv.tv_usec = msec % 1000;
2350
2351         /* Check IO readiness */
2352         if (select(max_fd + 1, &read_set, &write_set, NULL, &tv) < 0) {
2353                 elog(ERR_DEBUG, "select: %s", strerror(errno));
2354                 return;
2355         }
2356
2357         /* Set IO readiness flags */
2358         for (c = ctx->connections; c != NULL; c = c->next) {
2359                 if (FD_ISSET(c->sock, &read_set)) {
2360                         elog(ERR_DEBUG, "%d readable", c->sock);
2361                         c->flags |= FLAG_SOCK_READABLE;
2362                 }
2363                 if (FD_ISSET(c->sock, &write_set)) {
2364                         c->flags |= FLAG_SOCK_WRITABLE;
2365                         //            c->flags &= ~FLAG_HAVE_TO_WRITE;
2366                 }
2367 #if 0
2368                 if (IO_SPACELEN(&c->local) && ((c->flags & FLAG_ALWAYS_READY) ||
2369                                         (c->fd != -1 && FD_ISSET(c->fd, &read_set))))
2370                         c->flags |= FLAG_FD_READABLE;
2371                 if (IO_DATALEN(&c->remote) && ((c->flags & FLAG_ALWAYS_READY) ||
2372                                         (c->fd != -1 && FD_ISSET(c->fd, &write_set))))
2373                         c->flags |= FLAG_FD_WRITABLE;
2374 #endif
2375         }
2376
2377         /* Loop through all connections, handle if IO ready */
2378         for (c = ctx->connections; c != NULL; c = nc) {
2379                 nc = c->next;
2380
2381                 if (c->flags & FLAG_IO_READY)
2382                         c->watch(c->ctx, c->watch_data);
2383
2384                 if ((c->flags & FLAG_FINISHED) || c->expire < current_time)
2385                         disconnect(c);
2386         }
2387 }
2388
2389 /*
2390  * Convert command line switch to the option structure
2391  */
2392 static struct opt *
2393 swtoopt(int sw, const char *name)
2394 {
2395         struct opt      *opt;
2396
2397         for (opt = options; opt->sw != 0; opt++)
2398                 if (sw == opt->sw || (name && strcmp(opt->name, name) == 0))
2399                         return (opt);
2400
2401         return (NULL);
2402 }
2403
2404 /*
2405  * Initialize shttpd
2406  */
2407 struct shttpd_ctx *
2408 do_init(const char *config_file, int argc, char *argv[])
2409 {
2410         struct shttpd_ctx       *ctx;
2411         struct opt      *opt;
2412
2413         current_time = time(NULL);
2414
2415         if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
2416                 elog(ERR_FATAL, "do_init: cannot allocate context");
2417
2418         ctx->start_time = current_time;
2419
2420         /*
2421          * setopt() may already set some vars, we do not override them
2422          * with the default value if they are set.
2423          */
2424         for (opt = options; opt->sw != 0; opt++)
2425                 if (opt->tmp == NULL && opt->def != NULL)
2426                         opt->tmp = u_strdup(opt->def);
2427
2428         /* Now, every option must hold its config in 'tmp' node. Call setters */
2429         for (opt = options; opt->sw != 0; opt++)
2430                 if (opt->tmp != NULL)
2431                         opt->setter(ctx, ((char *) ctx) + opt->ofs, opt->tmp);
2432
2433 #ifdef HAVE_SSL
2434         /* If SSL is wanted and port is not overridden, set it to 443 */
2435         if (ctx->port == atoi(PORT) && ctx->ssl_ctx != NULL)
2436                 ctx->port = 443;
2437 #endif
2438         /* If document_root is not set, set it to current directory */
2439         if (ctx->root[0] == '\0')
2440                 (void) getcwd(ctx->root, sizeof(ctx->root));
2441
2442         debug("do_init: initialized context %p", ctx);
2443
2444         return (ctx);
2445 }
2446
2447 /*
2448  * Deallocate shttpd object, free up the resources
2449  */
2450 void
2451 shttpd_fini(struct shttpd_ctx *ctx)
2452 {
2453         struct mimetype *p, *tmp;
2454         struct conn     *c, *nc;
2455         struct userurl *u, *u1;
2456
2457         /* TODO: Free configuration */
2458
2459         /* Free allocated mime-types */
2460         for (p = ctx->mimetypes; p != NULL; p = tmp) {
2461                 tmp = p->next;
2462                 free(p->ext);
2463                 free(p->mime);
2464                 free(p);
2465         }
2466
2467         /* Free all connections */
2468         for (c = ctx->connections; c != NULL; c = nc) {
2469                 nc = c->next;
2470                 c->flags = 0;
2471                 disconnect(c);
2472         }
2473
2474         /* Free allocated userurls */
2475         for (u = ctx->urls; u != NULL; u = u1) {
2476                 u1 = u->next;
2477                 free(u->url);
2478                 free(u);
2479         }
2480
2481         if (ctx->index) {
2482                 free(ctx->index);
2483                 ctx->index = NULL;
2484         }
2485         if (ctx->ext) {
2486                 free(ctx->ext);
2487                 ctx->ext = NULL;
2488         }
2489         if (ctx->interp) {
2490                 free(ctx->interp);
2491                 ctx->interp = NULL;
2492         }
2493         if (ctx->realm) {
2494                 free(ctx->realm);
2495                 ctx->realm = NULL;
2496         }
2497
2498         if (ctx->pass) {
2499                 free(ctx->pass);
2500                 ctx->pass = NULL;
2501         }
2502         if (ctx->put_auth) {
2503                 free(ctx->put_auth);
2504                 ctx->put_auth = NULL;
2505         }
2506         if (ctx->uid) {
2507                 free(ctx->uid);
2508                 ctx->uid = NULL;
2509         }
2510
2511         if (ctx->accesslog)     (void) fclose(ctx->accesslog);
2512         free(ctx);
2513 }
2514
2515
2516