2 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * Sergey Lyubka wrote this file. As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return.
14 * Configuration parameters setters
17 set_int(struct shttpd_ctx *ctx, void *ptr, const char *string)
19 ctx = NULL; /* Unused */
20 * (int *) ptr = atoi(string);
24 set_str(struct shttpd_ctx *ctx, void *ptr, const char *string)
26 ctx = NULL; /* Unused */
27 * (char **) ptr = my_strdup(string);
31 set_log_file(struct shttpd_ctx *ctx, void *ptr, const char *string)
36 if ((*fp = fopen(string, "a")) == NULL)
37 elog(E_FATAL, NULL, "cannot open log file %s: %s",
38 string, strerror(errno));
43 * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
46 set_ssl(struct shttpd_ctx *ctx, void *arg, const char *pem)
52 arg = NULL; /* Unused */
54 /* Load SSL library dynamically */
55 if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL)
56 elog(E_FATAL, NULL, "set_ssl: cannot load %s", SSL_LIB);
58 for (fp = ssl_sw; fp->name != NULL; fp++)
59 if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL)
60 elog(E_FATAL, NULL,"set_ssl: cannot find %s", fp->name);
62 /* Initialize SSL crap */
65 if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
66 elog(E_FATAL, NULL, "SSL_CTX_new error");
67 else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
68 elog(E_FATAL, NULL, "cannot open %s", pem);
69 else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
70 elog(E_FATAL, NULL, "cannot open %s", pem);
76 set_mime(struct shttpd_ctx *ctx, void *arg, const char *string)
79 set_mime_types(ctx, string);
82 #define OFS(x) offsetof(struct shttpd_ctx, x)
83 #define BOOL_OPT "0|1"
84 const struct opt options[] = {
85 {'d', "document_root", "Web root directory", set_str,
86 OFS(document_root), "directory", NULL, OPT_DIR},
87 {'i', "index_files", "Index files", set_str, OFS(index_files),
88 "file_list", INDEX_FILES, OPT_ADVANCED},
89 {'p', "listen_ports", "Listening ports", set_str,
90 OFS(ports), "ports", LISTENING_PORTS, OPT_ADVANCED},
91 {'D', "list_directories", "Directory listing", set_int,
92 OFS(dirlist), BOOL_OPT, "1", OPT_BOOL | OPT_ADVANCED},
94 {'c', "cgi_extensions", "CGI extensions", set_str,
95 OFS(cgi_extensions), "ext_list", CGI_EXT, OPT_ADVANCED},
96 {'C', "cgi_interpreter", "CGI interpreter", set_str,
97 OFS(cgi_interpreter), "file", NULL, OPT_FILE | OPT_ADVANCED},
98 {'V', "cgi_envvar", "CGI envir variables", set_str,
99 OFS(cgi_vars), "X=Y,....", NULL, OPT_ADVANCED},
102 {'S', "ssi_extensions", "SSI extensions", set_str,
103 OFS(ssi_extensions), "ext_list", SSI_EXT, OPT_ADVANCED},
105 {'N', "auth_realm", "Authentication realm", set_str,
106 OFS(auth_realm), "auth_realm", REALM, OPT_ADVANCED},
107 {'l', "access_log", "Access log file", set_log_file,
108 OFS(access_log), "file", NULL, OPT_FILE | OPT_ADVANCED},
109 {'e', "error_log", "Error log file", set_log_file,
110 OFS(error_log), "file", NULL, OPT_FILE | OPT_ADVANCED},
111 {'m', "mime_types", "Mime types file", set_mime,
112 OFS(mime_file), "file", NULL, OPT_FILE | OPT_ADVANCED},
113 {'P', "global_htpasswd", "Global passwords file", set_str,
114 OFS(global_passwd_file), "file", NULL, OPT_FILE | OPT_ADVANCED},
116 {'s', "ssl_certificate", "SSL certificate file", set_ssl,
117 OFS(ssl_ctx), "pem_file", NULL, OPT_FILE | OPT_ADVANCED},
119 {'U', "put_auth", "PUT,DELETE auth file",set_str,
120 OFS(put_auth_file), "file", NULL, OPT_FILE | OPT_ADVANCED},
121 {'a', "aliases", "Aliases", set_str,
122 OFS(aliases), "X=Y,...", NULL, OPT_ADVANCED},
123 {'b', "io_buf_size", "IO buffer size", set_int, OFS(io_buf_size),
124 "bytes", DFLT_IO_SIZ, OPT_INT | OPT_ADVANCED},
126 {'B', "auto_start", "Autostart with Windows", set_int,
127 OFS(auto_start), BOOL_OPT, "1", OPT_BOOL},
129 {'I', "inetd_mode", "Inetd mode", set_int,
130 OFS(inetd_mode), BOOL_OPT, NULL, OPT_BOOL },
131 {'u', "runtime_uid", "Run as user", set_str,
132 OFS(uid), "user_name", NULL, 0 },
134 {0, NULL, NULL, NULL, 0, NULL, NULL, 0 }
137 static const struct opt *
138 find_option(int sw, const char *name)
140 const struct opt *opt;
142 for (opt = options; opt->sw != 0; opt++)
143 if (sw == opt->sw || (name && strcmp(opt->name, name) == 0))
150 set_option(const struct opt *opt, const char *val, char **tmpvars)
152 tmpvars += opt - options;
154 if (*tmpvars != NULL)
157 *tmpvars = my_strdup(val);
161 * Initialize shttpd context
164 initialize_context(struct shttpd_ctx *ctx, const char *config_file,
165 int argc, char *argv[], char **tmpvars)
167 char line[FILENAME_MAX], root[FILENAME_MAX],
168 var[sizeof(line)], val[sizeof(line)];
171 const struct opt *opt;
175 current_time = time(NULL);
176 tm = localtime(¤t_time);
179 tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
182 (void) memset(ctx, 0, sizeof(*ctx));
184 ctx->start_time = current_time;
185 InitializeCriticalSection(&ctx->mutex);
187 LL_INIT(&ctx->connections);
188 LL_INIT(&ctx->mime_types);
189 LL_INIT(&ctx->registered_uris);
190 LL_INIT(&ctx->uri_auths);
191 LL_INIT(&ctx->error_handlers);
194 LL_INIT(&ctx->ssi_funcs);
197 /* First pass: set the defaults */
198 for (opt = options; opt->sw != 0; opt++)
199 if (tmpvars[opt - options] == NULL && opt->def != NULL)
200 tmpvars[opt - options] = my_strdup(opt->def);
202 /* Second pass: load config file */
203 if (config_file != NULL && (fp = fopen(config_file, "r")) != NULL) {
204 DBG(("init_ctx: config file %s", config_file));
206 /* Loop through the lines in config file */
207 while (fgets(line, sizeof(line), fp) != NULL) {
209 /* Skip comments and empty lines */
210 if (line[0] == '#' || line[0] == '\n')
213 /* Trim trailing newline character */
214 line[strlen(line) - 1] = '\0';
216 if (sscanf(line, "%s %[^#\n]", var, val) != 2)
217 elog(E_FATAL,0,"init_ctx: bad line: [%s]",line);
219 if ((opt = find_option(0, var)) == NULL)
221 "set_option: unknown variable [%s]", var);
222 set_option(opt, val, tmpvars);
227 /* Third pass: process command line args */
228 for (i = 1; i < (size_t) argc && argv[i][0] == '-'; i++)
229 if ((opt = find_option(argv[i][1], NULL)) != NULL) {
230 arg = argv[i][2] ? &argv[i][2] : argv[++i];
235 set_option(opt, arg, tmpvars);
240 /* Call setters functions now */
241 for (i = 0; i < NELEMS(options); i++)
242 if (tmpvars[i] != NULL) {
243 options[i].setter(ctx,
244 ((char *) ctx) + options[i].ofs, tmpvars[i]);
248 /* If document_root is not set, set it to current directory */
249 if (ctx->document_root == NULL) {
250 (void) my_getcwd(root, sizeof(root));
251 ctx->document_root = my_strdup(root);
255 {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
258 DBG(("init_ctx: initialized context %p", (void *) ctx));
262 * Show usage string and exit.
265 usage(const char *prog)
267 const struct opt *opt;
269 (void) fprintf(stderr,
270 "SHTTPD version %s (c) Sergey Lyubka\n"
271 "usage: %s [OPTIONS] [config_file]\n"
272 "Note: config line keyword for every option is in the "
273 "round brackets\n", VERSION, prog);
275 #if !defined(NO_AUTH)
276 (void) fprintf(stderr, "-A <htpasswd_file> <realm> <user> <passwd>\n");
279 for (opt = options; opt->name != NULL; opt++)
280 (void) fprintf(stderr, "-%c <%s>\t\t%s (%s)\n",
281 opt->sw, opt->arg, opt->desc, opt->name);
287 init_from_argc_argv(const char *config_file, int argc, char *argv[])
289 struct shttpd_ctx *ctx;
290 char *tmpvars[NELEMS(options)];
293 /* Initialize all temporary holders to NULL */
294 for (i = 0; i < NELEMS(tmpvars); i++)
297 if ((ctx = malloc(sizeof(*ctx))) != NULL)
298 initialize_context(ctx, config_file, argc, argv, tmpvars);
304 shttpd_init(const char *config_file, ...)
306 struct shttpd_ctx *ctx;
308 const char *opt_name, *opt_value;
309 char *tmpvars[NELEMS(options)];
310 const struct opt *opt;
313 /* Initialize all temporary holders to NULL */
314 for (i = 0; i < NELEMS(tmpvars); i++)
317 if ((ctx = malloc(sizeof(*ctx))) != NULL) {
319 va_start(ap, config_file);
320 while ((opt_name = va_arg(ap, const char *)) != NULL) {
321 opt_value = va_arg(ap, const char *);
323 if ((opt = find_option(0, opt_name)) == NULL)
324 elog(E_FATAL, NULL, "shttpd_init: "
325 "unknown variable [%s]", opt_name);
326 set_option(opt, opt_value, tmpvars);
330 initialize_context(ctx, config_file, 0, NULL, tmpvars);