Add the config directive compression-level
[privoxy.git] / loadcfg.c
1 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.112 2011/03/03 14:38:36 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
5  *
6  * Purpose     :  Loads settings from the configuration file into
7  *                global variables.  This file contains both the
8  *                routine to load the configuration and the global
9  *                variables it writes to.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001-2009 the
12  *                Privoxy team. http://www.privoxy.org/
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  *********************************************************************/
37
38
39 #include "config.h"
40
41 #include <stdio.h>
42 #include <sys/types.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <signal.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <ctype.h>
49 #include <assert.h>
50
51 #ifdef _WIN32
52
53 # ifndef STRICT
54 #  define STRICT
55 # endif
56 # include <windows.h>
57
58 # include "win32.h"
59 # ifndef _WIN_CONSOLE
60 #  include "w32log.h"
61 # endif /* ndef _WIN_CONSOLE */
62
63 #else /* ifndef _WIN32 */
64
65 #ifndef __OS2__
66 # include <unistd.h>
67 # include <sys/wait.h>
68 #endif
69 # include <sys/time.h>
70 # include <sys/stat.h>
71 # include <signal.h>
72
73 #endif
74
75 #include "loadcfg.h"
76 #include "list.h"
77 #include "jcc.h"
78 #include "filters.h"
79 #include "loaders.h"
80 #include "miscutil.h"
81 #include "errlog.h"
82 #include "ssplit.h"
83 #include "encode.h"
84 #include "urlmatch.h"
85 #include "cgi.h"
86 #include "gateway.h"
87
88 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
89
90 /*
91  * Fix a problem with Solaris.  There should be no effect on other
92  * platforms.
93  * Solaris's isspace() is a macro which uses it's argument directly
94  * as an array index.  Therefore we need to make sure that high-bit
95  * characters generate +ve values, and ideally we also want to make
96  * the argument match the declared parameter type of "int".
97  */
98 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
99 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
100
101 #ifdef FEATURE_TOGGLE
102 /* Privoxy is enabled by default. */
103 int global_toggle_state = 1;
104 #endif /* def FEATURE_TOGGLE */
105
106 /* The filename of the configfile */
107 const char *configfile  = NULL;
108
109 /*
110  * CGI functions will later need access to the invocation args,
111  * so we will make argc and argv global.
112  */
113 int Argc = 0;
114 char * const * Argv = NULL;
115
116 static struct file_list *current_configfile = NULL;
117
118
119 /*
120  * This takes the "cryptic" hash of each keyword and aliases them to
121  * something a little more readable.  This also makes changing the
122  * hash values easier if they should change or the hash algorthm changes.
123  * Use the included "hash" program to find out what the hash will be
124  * for any string supplied on the command line.  (Or just put it in the
125  * config file and read the number from the error message in the log).
126  *
127  * Please keep this list sorted alphabetically (but with the Windows
128  * console and GUI specific options last).
129  */
130
131 #define hash_actions_file                1196306641ul /* "actionsfile" */
132 #define hash_accept_intercepted_requests 1513024973ul /* "accept-intercepted-requests" */
133 #define hash_admin_address               4112573064ul /* "admin-address" */
134 #define hash_allow_cgi_request_crunching  258915987ul /* "allow-cgi-request-crunching" */
135 #define hash_buffer_limit                1881726070ul /* "buffer-limit */
136 #define hash_compression_level           2464423563ul /* "compression-level" */
137 #define hash_confdir                        1978389ul /* "confdir" */
138 #define hash_connection_sharing          1348841265ul /* "connection-sharing" */
139 #define hash_debug                            78263ul /* "debug" */
140 #define hash_default_server_timeout      2530089913ul /* "default-server-timeout" */
141 #define hash_deny_access                 1227333715ul /* "deny-access" */
142 #define hash_enable_edit_actions         2517097536ul /* "enable-edit-actions" */
143 #define hash_enable_remote_toggle        2979744683ul /* "enable-remote-toggle" */
144 #define hash_enable_remote_http_toggle    110543988ul /* "enable-remote-http-toggle" */
145 #define hash_enforce_blocks              1862427469ul /* "enforce-blocks" */
146 #define hash_filterfile                   250887266ul /* "filterfile" */
147 #define hash_forward                        2029845ul /* "forward" */
148 #define hash_forward_socks4              3963965521ul /* "forward-socks4" */
149 #define hash_forward_socks4a             2639958518ul /* "forward-socks4a" */
150 #define hash_forward_socks5              3963965522ul /* "forward-socks5" */
151 #define hash_forwarded_connect_retries    101465292ul /* "forwarded-connect-retries" */
152 #define hash_handle_as_empty_returns_ok  1444873247ul /* "handle-as-empty-doc-returns-ok" */
153 #define hash_hostname                      10308071ul /* "hostname" */
154 #define hash_keep_alive_timeout          3878599515ul /* "keep-alive-timeout" */
155 #define hash_listen_address              1255650842ul /* "listen-address" */
156 #define hash_logdir                          422889ul /* "logdir" */
157 #define hash_logfile                        2114766ul /* "logfile" */
158 #define hash_max_client_connections      3595884446ul /* "max-client-connections" */
159 #define hash_permit_access               3587953268ul /* "permit-access" */
160 #define hash_proxy_info_url              3903079059ul /* "proxy-info-url" */
161 #define hash_single_threaded             4250084780ul /* "single-threaded" */
162 #define hash_socket_timeout              1809001761ul /* "socket-timeout" */
163 #define hash_split_large_cgi_forms        671658948ul /* "split-large-cgi-forms" */
164 #define hash_suppress_blocklists         1948693308ul /* "suppress-blocklists" */
165 #define hash_templdir                      11067889ul /* "templdir" */
166 #define hash_toggle                          447966ul /* "toggle" */
167 #define hash_trust_info_url               430331967ul /* "trust-info-url" */
168 #define hash_trustfile                     56494766ul /* "trustfile" */
169 #define hash_usermanual                  1416668518ul /* "user-manual" */
170 #define hash_activity_animation          1817904738ul /* "activity-animation" */
171 #define hash_close_button_minimizes      3651284693ul /* "close-button-minimizes" */
172 #define hash_hide_console                2048809870ul /* "hide-console" */
173 #define hash_log_buffer_size             2918070425ul /* "log-buffer-size" */
174 #define hash_log_font_name               2866730124ul /* "log-font-name" */
175 #define hash_log_font_size               2866731014ul /* "log-font-size" */
176 #define hash_log_highlight_messages      4032101240ul /* "log-highlight-messages" */
177 #define hash_log_max_lines               2868344173ul /* "log-max-lines" */
178 #define hash_log_messages                2291744899ul /* "log-messages" */
179 #define hash_show_on_task_bar             215410365ul /* "show-on-task-bar" */
180
181
182 static void savearg(char *command, char *argument, struct configuration_spec * config);
183
184 /*********************************************************************
185  *
186  * Function    :  unload_configfile
187  *
188  * Description :  Free the config structure and all components.
189  *
190  * Parameters  :
191  *          1  :  data: struct configuration_spec to unload
192  *
193  * Returns     :  N/A
194  *
195  *********************************************************************/
196 static void unload_configfile (void * data)
197 {
198    struct configuration_spec * config = (struct configuration_spec *)data;
199    struct forward_spec *cur_fwd = config->forward;
200    int i;
201
202 #ifdef FEATURE_ACL
203    struct access_control_list *cur_acl = config->acl;
204
205    while (cur_acl != NULL)
206    {
207       struct access_control_list * next_acl = cur_acl->next;
208       free(cur_acl);
209       cur_acl = next_acl;
210    }
211    config->acl = NULL;
212 #endif /* def FEATURE_ACL */
213
214    while (cur_fwd != NULL)
215    {
216       struct forward_spec * next_fwd = cur_fwd->next;
217       free_url_spec(cur_fwd->url);
218
219       freez(cur_fwd->gateway_host);
220       freez(cur_fwd->forward_host);
221       free(cur_fwd);
222       cur_fwd = next_fwd;
223    }
224    config->forward = NULL;
225
226    freez(config->confdir);
227    freez(config->logdir);
228    freez(config->templdir);
229    freez(config->hostname);
230
231    freez(config->haddr);
232    freez(config->logfile);
233
234    for (i = 0; i < MAX_AF_FILES; i++)
235    {
236       freez(config->actions_file_short[i]);
237       freez(config->actions_file[i]);
238       freez(config->re_filterfile_short[i]);
239       freez(config->re_filterfile[i]);
240    }
241
242    freez(config->admin_address);
243    freez(config->proxy_info_url);
244    freez(config->proxy_args);
245    freez(config->usermanual);
246
247 #ifdef FEATURE_TRUST
248    freez(config->trustfile);
249    list_remove_all(config->trust_info);
250 #endif /* def FEATURE_TRUST */
251
252    freez(config);
253 }
254
255
256 #ifdef FEATURE_GRACEFUL_TERMINATION
257 /*********************************************************************
258  *
259  * Function    :  unload_current_config_file
260  *
261  * Description :  Unloads current config file - reset to state at
262  *                beginning of program.
263  *
264  * Parameters  :  None
265  *
266  * Returns     :  N/A
267  *
268  *********************************************************************/
269 void unload_current_config_file(void)
270 {
271    if (current_configfile)
272    {
273       current_configfile->unloader = unload_configfile;
274       current_configfile = NULL;
275    }
276 }
277 #endif
278
279
280 /*********************************************************************
281  *
282  * Function    :  load_config
283  *
284  * Description :  Load the config file and all parameters.
285  *
286  *                XXX: more than thousand lines long
287  *                and thus in serious need of refactoring.
288  *
289  * Parameters  :  None
290  *
291  * Returns     :  The configuration_spec, or NULL on error.
292  *
293  *********************************************************************/
294 struct configuration_spec * load_config(void)
295 {
296    char *buf = NULL;
297    char *p, *q;
298    FILE *configfp = NULL;
299    struct configuration_spec * config = NULL;
300    struct client_state * fake_csp;
301    struct file_list *fs;
302    unsigned long linenum = 0;
303    int i;
304    char *logfile = NULL;
305
306    if (!check_file_changed(current_configfile, configfile, &fs))
307    {
308       /* No need to load */
309       return ((struct configuration_spec *)current_configfile->f);
310    }
311    if (NULL == fs)
312    {
313       log_error(LOG_LEVEL_FATAL,
314          "can't check configuration file '%s':  %E", configfile);
315       return NULL;
316    }
317
318    if (NULL != current_configfile)
319    {
320       log_error(LOG_LEVEL_INFO, "Reloading configuration file '%s'", configfile);
321    }
322
323 #ifdef FEATURE_TOGGLE
324    global_toggle_state = 1;
325 #endif /* def FEATURE_TOGGLE */
326
327    fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
328
329    if (NULL == config)
330    {
331       freez(fs->filename);
332       freez(fs);
333       log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
334       return NULL;
335    }
336
337    /*
338     * This is backwards from how it's usually done.
339     * Following the usual pattern, "fs" would be stored in a member
340     * variable in "csp", and then we'd access "config" from "fs->f",
341     * using a cast.  However, "config" is used so often that a
342     * cast each time would be very ugly, and the extra indirection
343     * would waste CPU cycles.  Therefore we store "config" in
344     * "csp->config", and "fs" in "csp->config->config_file_list".
345     */
346    config->config_file_list = fs;
347
348    /*
349     * Set to defaults
350     */
351    config->multi_threaded            = 1;
352    config->buffer_limit              = 4096 * 1024;
353    config->usermanual                = strdup(USER_MANUAL_URL);
354    config->proxy_args                = strdup("");
355    config->forwarded_connect_retries = 0;
356    config->max_client_connections    = 0;
357    config->socket_timeout            = 300; /* XXX: Should be a macro. */
358 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
359    config->default_server_timeout    = 0;
360    config->keep_alive_timeout        = DEFAULT_KEEP_ALIVE_TIMEOUT;
361    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
362    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
363 #endif
364    config->feature_flags            &= ~RUNTIME_FEATURE_CGI_TOGGLE;
365    config->feature_flags            &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
366    config->feature_flags            &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
367    config->feature_flags            &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
368 #ifdef FEATURE_COMPRESSION
369    /*
370     * XXX: Run some benchmarks to see if there are better default values.
371     */
372    config->compression_level         = 1;
373 #endif
374
375    configfp = fopen(configfile, "r");
376    if (NULL == configfp)
377    {
378       log_error(LOG_LEVEL_FATAL,
379          "can't open configuration file '%s':  %E", configfile);
380       /* Never get here - LOG_LEVEL_FATAL causes program exit */
381    }
382
383    while (read_config_line(configfp, &linenum, &buf) != NULL)
384    {
385       char cmd[BUFFER_SIZE];
386       char arg[BUFFER_SIZE];
387       char tmp[BUFFER_SIZE];
388 #ifdef FEATURE_ACL
389       struct access_control_list *cur_acl;
390 #endif /* def FEATURE_ACL */
391       struct forward_spec *cur_fwd;
392       int vec_count;
393       char *vec[3];
394       unsigned long directive_hash;
395
396       strlcpy(tmp, buf, sizeof(tmp));
397
398       /* Copy command (i.e. up to space or tab) into cmd */
399       p = buf;
400       q = cmd;
401       while (*p && (*p != ' ') && (*p != '\t'))
402       {
403          *q++ = *p++;
404       }
405       *q = '\0';
406
407       /* Skip over the whitespace in buf */
408       while (*p && ((*p == ' ') || (*p == '\t')))
409       {
410          p++;
411       }
412
413       /* Copy the argument into arg */
414       if (strlcpy(arg, p, sizeof(arg)) >= sizeof(arg))
415       {
416          log_error(LOG_LEVEL_FATAL, "Config line too long: %s", buf);
417       }
418
419       /* Should never happen, but check this anyway */
420       if (*cmd == '\0')
421       {
422          freez(buf);
423          continue;
424       }
425
426       /* Make sure the command field is lower case */
427       for (p = cmd; *p; p++)
428       {
429          if (ijb_isupper(*p))
430          {
431             *p = (char)ijb_tolower(*p);
432          }
433       }
434
435       directive_hash = hash_string(cmd);
436       switch (directive_hash)
437       {
438 /* *************************************************************************
439  * actionsfile actions-file-name
440  * In confdir by default
441  * *************************************************************************/
442          case hash_actions_file :
443             i = 0;
444             while ((i < MAX_AF_FILES) && (NULL != config->actions_file[i]))
445             {
446                i++;
447             }
448
449             if (i >= MAX_AF_FILES)
450             {
451                log_error(LOG_LEVEL_FATAL, "Too many 'actionsfile' directives in config file - limit is %d.\n"
452                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
453                   MAX_AF_FILES);
454             }
455             config->actions_file_short[i] = strdup(arg);
456             config->actions_file[i] = make_path(config->confdir, arg);
457
458             break;
459 /* *************************************************************************
460  * accept-intercepted-requests
461  * *************************************************************************/
462          case hash_accept_intercepted_requests:
463             if ((*arg != '\0') && (0 != atoi(arg)))
464             {
465                config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
466             }
467             else
468             {
469                config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
470             }
471             break;
472
473 /* *************************************************************************
474  * admin-address email-address
475  * *************************************************************************/
476          case hash_admin_address :
477             freez(config->admin_address);
478             config->admin_address = strdup(arg);
479             break;
480
481 /* *************************************************************************
482  * allow-cgi-request-crunching
483  * *************************************************************************/
484          case hash_allow_cgi_request_crunching:
485             if ((*arg != '\0') && (0 != atoi(arg)))
486             {
487                config->feature_flags |= RUNTIME_FEATURE_CGI_CRUNCHING;
488             }
489             else
490             {
491                config->feature_flags &= ~RUNTIME_FEATURE_CGI_CRUNCHING;
492             }
493             break;
494
495 /* *************************************************************************
496  * buffer-limit n
497  * *************************************************************************/
498          case hash_buffer_limit :
499             config->buffer_limit = (size_t)(1024 * atoi(arg));
500             break;
501
502 /* *************************************************************************
503  * confdir directory-name
504  * *************************************************************************/
505          case hash_confdir :
506             freez(config->confdir);
507             config->confdir = make_path( NULL, arg);
508             break;
509
510 /* *************************************************************************
511  * compression-level 0-9
512  * *************************************************************************/
513 #ifdef FEATURE_COMPRESSION
514          case hash_compression_level :
515             if (*arg != '\0')
516             {
517                int compression_level = atoi(arg);
518                if (-1 <= compression_level && compression_level <= 9)
519                {
520                   config->compression_level = compression_level;;
521                }
522                else
523                {
524                   log_error(LOG_LEVEL_FATAL,
525                      "Invalid compression-level value: %s", arg);
526                }
527             }
528             else
529             {
530                log_error(LOG_LEVEL_FATAL,
531                   "Invalid compression-level directive. Compression value missing");
532             }
533             break;
534 #endif
535
536 /* *************************************************************************
537  * connection-sharing (0|1)
538  * *************************************************************************/
539 #ifdef FEATURE_CONNECTION_SHARING
540          case hash_connection_sharing :
541             if ((*arg != '\0') && (0 != atoi(arg)))
542             {
543                config->feature_flags |= RUNTIME_FEATURE_CONNECTION_SHARING;
544             }
545             else
546             {
547                config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
548             }
549             break;
550 #endif
551
552 /* *************************************************************************
553  * debug n
554  * Specifies debug level, multiple values are ORed together.
555  * *************************************************************************/
556          case hash_debug :
557             config->debug |= atoi(arg);
558             break;
559
560 /* *************************************************************************
561  * default-server-timeout timeout
562  * *************************************************************************/
563 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
564          case hash_default_server_timeout :
565             if (*arg != '\0')
566             {
567                int timeout = atoi(arg);
568                if (0 < timeout)
569                {
570                   config->default_server_timeout = (unsigned int)timeout;
571                }
572                else
573                {
574                   log_error(LOG_LEVEL_FATAL,
575                      "Invalid default-server-timeout value: %s", arg);
576                }
577             }
578             break;
579 #endif
580
581 /* *************************************************************************
582  * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
583  * *************************************************************************/
584 #ifdef FEATURE_ACL
585          case hash_deny_access:
586             strlcpy(tmp, arg, sizeof(tmp));
587             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
588
589             if ((vec_count != 1) && (vec_count != 2))
590             {
591                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
592                      "deny-access directive in configuration file.");
593                string_append(&config->proxy_args,
594                   "<br>\nWARNING: Wrong number of parameters for "
595                   "deny-access directive in configuration file.<br><br>\n");
596                break;
597             }
598
599             /* allocate a new node */
600             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
601
602             if (cur_acl == NULL)
603             {
604                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
605                /* Never get here - LOG_LEVEL_FATAL causes program exit */
606                break;
607             }
608             cur_acl->action = ACL_DENY;
609
610             if (acl_addr(vec[0], cur_acl->src) < 0)
611             {
612                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
613                   "for deny-access directive in configuration file: \"%s\"", vec[0]);
614                string_append(&config->proxy_args,
615                   "<br>\nWARNING: Invalid source address, port or netmask "
616                   "for deny-access directive in configuration file: \"");
617                string_append(&config->proxy_args,
618                   vec[0]);
619                string_append(&config->proxy_args,
620                   "\"<br><br>\n");
621                freez(cur_acl);
622                break;
623             }
624             if (vec_count == 2)
625             {
626                if (acl_addr(vec[1], cur_acl->dst) < 0)
627                {
628                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
629                      "for deny-access directive in configuration file: \"%s\"", vec[1]);
630                   string_append(&config->proxy_args,
631                      "<br>\nWARNING: Invalid destination address, port or netmask "
632                      "for deny-access directive in configuration file: \"");
633                   string_append(&config->proxy_args,
634                      vec[1]);
635                   string_append(&config->proxy_args,
636                      "\"<br><br>\n");
637                   freez(cur_acl);
638                   break;
639                }
640             }
641 #ifdef HAVE_RFC2553
642             else
643             {
644                cur_acl->wildcard_dst = 1;
645             }
646 #endif /* def HAVE_RFC2553 */
647
648             /*
649              * Add it to the list.  Note we reverse the list to get the
650              * behaviour the user expects.  With both the ACL and
651              * actions file, the last match wins.  However, the internal
652              * implementations are different:  The actions file is stored
653              * in the same order as the file, and scanned completely.
654              * With the ACL, we reverse the order as we load it, then
655              * when we scan it we stop as soon as we get a match.
656              */
657             cur_acl->next  = config->acl;
658             config->acl = cur_acl;
659
660             break;
661 #endif /* def FEATURE_ACL */
662
663 /* *************************************************************************
664  * enable-edit-actions 0|1
665  * *************************************************************************/
666 #ifdef FEATURE_CGI_EDIT_ACTIONS
667          case hash_enable_edit_actions:
668             if ((*arg != '\0') && (0 != atoi(arg)))
669             {
670                config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
671             }
672             else
673             {
674                config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
675             }
676             break;
677 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
678
679 /* *************************************************************************
680  * enable-remote-toggle 0|1
681  * *************************************************************************/
682 #ifdef FEATURE_TOGGLE
683          case hash_enable_remote_toggle:
684             if ((*arg != '\0') && (0 != atoi(arg)))
685             {
686                config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE;
687             }
688             else
689             {
690                config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE;
691             }
692             break;
693 #endif /* def FEATURE_TOGGLE */
694
695 /* *************************************************************************
696  * enable-remote-http-toggle 0|1
697  * *************************************************************************/
698          case hash_enable_remote_http_toggle:
699             if ((*arg != '\0') && (0 != atoi(arg)))
700             {
701                config->feature_flags |= RUNTIME_FEATURE_HTTP_TOGGLE;
702             }
703             else
704             {
705                config->feature_flags &= ~RUNTIME_FEATURE_HTTP_TOGGLE;
706             }
707             break;
708
709 /* *************************************************************************
710  * enforce-blocks 0|1
711  * *************************************************************************/
712          case hash_enforce_blocks:
713 #ifdef FEATURE_FORCE_LOAD
714             if ((*arg != '\0') && (0 != atoi(arg)))
715             {
716                config->feature_flags |= RUNTIME_FEATURE_ENFORCE_BLOCKS;
717             }
718             else
719             {
720                config->feature_flags &= ~RUNTIME_FEATURE_ENFORCE_BLOCKS;
721             }
722 #else
723             log_error(LOG_LEVEL_ERROR, "Ignoring directive 'enforce-blocks'. "
724                "FEATURE_FORCE_LOAD is disabled, blocks will always be enforced.");
725 #endif /* def FEATURE_FORCE_LOAD */
726             break;
727
728 /* *************************************************************************
729  * filterfile file-name
730  * In confdir by default.
731  * *************************************************************************/
732          case hash_filterfile :
733             i = 0;
734             while ((i < MAX_AF_FILES) && (NULL != config->re_filterfile[i]))
735             {
736                i++;
737             }
738
739             if (i >= MAX_AF_FILES)
740             {
741                log_error(LOG_LEVEL_FATAL, "Too many 'filterfile' directives in config file - limit is %d.\n"
742                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
743                   MAX_AF_FILES);
744             }
745             config->re_filterfile_short[i] = strdup(arg);
746             config->re_filterfile[i] = make_path(config->confdir, arg);
747
748             break;
749
750 /* *************************************************************************
751  * forward url-pattern (.|http-proxy-host[:port])
752  * *************************************************************************/
753          case hash_forward:
754             strlcpy(tmp, arg, sizeof(tmp));
755             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
756
757             if (vec_count != 2)
758             {
759                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
760                      "directive in configuration file.");
761                string_append(&config->proxy_args,
762                   "<br>\nWARNING: Wrong number of parameters for "
763                   "forward directive in configuration file.");
764                break;
765             }
766
767             /* allocate a new node */
768             cur_fwd = zalloc(sizeof(*cur_fwd));
769             if (cur_fwd == NULL)
770             {
771                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
772                /* Never get here - LOG_LEVEL_FATAL causes program exit */
773                break;
774             }
775
776             cur_fwd->type = SOCKS_NONE;
777
778             /* Save the URL pattern */
779             if (create_url_spec(cur_fwd->url, vec[0]))
780             {
781                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward "
782                      "directive in configuration file.");
783                string_append(&config->proxy_args,
784                   "<br>\nWARNING: Bad URL specifier for "
785                   "forward directive in configuration file.");
786                break;
787             }
788
789             /* Parse the parent HTTP proxy host:port */
790             p = vec[1];
791
792             if (strcmp(p, ".") != 0)
793             {
794                cur_fwd->forward_port = 8000;
795                parse_forwarder_address(p, &cur_fwd->forward_host,
796                   &cur_fwd->forward_port);
797             }
798
799             /* Add to list. */
800             cur_fwd->next = config->forward;
801             config->forward = cur_fwd;
802
803             break;
804
805 /* *************************************************************************
806  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
807  * *************************************************************************/
808          case hash_forward_socks4:
809             strlcpy(tmp, arg, sizeof(tmp));
810             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
811
812             if (vec_count != 3)
813             {
814                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
815                      "forward-socks4 directive in configuration file.");
816                string_append(&config->proxy_args,
817                   "<br>\nWARNING: Wrong number of parameters for "
818                   "forward-socks4 directive in configuration file.");
819                break;
820             }
821
822             /* allocate a new node */
823             cur_fwd = zalloc(sizeof(*cur_fwd));
824             if (cur_fwd == NULL)
825             {
826                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
827                /* Never get here - LOG_LEVEL_FATAL causes program exit */
828                break;
829             }
830
831             cur_fwd->type = SOCKS_4;
832
833             /* Save the URL pattern */
834             if (create_url_spec(cur_fwd->url, vec[0]))
835             {
836                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 "
837                      "directive in configuration file.");
838                string_append(&config->proxy_args,
839                   "<br>\nWARNING: Bad URL specifier for "
840                   "forward-socks4 directive in configuration file.");
841                break;
842             }
843
844             /* Parse the SOCKS proxy host[:port] */
845             p = vec[1];
846
847             /* XXX: This check looks like a bug. */
848             if (strcmp(p, ".") != 0)
849             {
850                cur_fwd->gateway_port = 1080;
851                parse_forwarder_address(p, &cur_fwd->gateway_host,
852                   &cur_fwd->gateway_port);
853             }
854
855             /* Parse the parent HTTP proxy host[:port] */
856             p = vec[2];
857
858             if (strcmp(p, ".") != 0)
859             {
860                cur_fwd->forward_port = 8000;
861                parse_forwarder_address(p, &cur_fwd->forward_host,
862                   &cur_fwd->forward_port);
863             }
864
865             /* Add to list. */
866             cur_fwd->next = config->forward;
867             config->forward = cur_fwd;
868
869             break;
870
871 /* *************************************************************************
872  * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port])
873  * *************************************************************************/
874          case hash_forward_socks4a:
875          case hash_forward_socks5:
876             strlcpy(tmp, arg, sizeof(tmp));
877             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
878
879             if (vec_count != 3)
880             {
881                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
882                      "forward-socks4a directive in configuration file.");
883                string_append(&config->proxy_args,
884                   "<br>\nWARNING: Wrong number of parameters for "
885                   "forward-socks4a directive in configuration file.");
886                break;
887             }
888
889             /* allocate a new node */
890             cur_fwd = zalloc(sizeof(*cur_fwd));
891             if (cur_fwd == NULL)
892             {
893                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
894                /* Never get here - LOG_LEVEL_FATAL causes program exit */
895                break;
896             }
897
898             if (directive_hash == hash_forward_socks4a)
899             {
900                cur_fwd->type = SOCKS_4A;
901             }
902             else
903             {
904                cur_fwd->type = SOCKS_5;
905             }
906
907             /* Save the URL pattern */
908             if (create_url_spec(cur_fwd->url, vec[0]))
909             {
910                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a "
911                      "directive in configuration file.");
912                string_append(&config->proxy_args,
913                   "<br>\nWARNING: Bad URL specifier for "
914                   "forward-socks4a directive in configuration file.");
915                break;
916             }
917
918             /* Parse the SOCKS proxy host[:port] */
919             p = vec[1];
920
921             cur_fwd->gateway_port = 1080;
922             parse_forwarder_address(p, &cur_fwd->gateway_host,
923                &cur_fwd->gateway_port);
924
925             /* Parse the parent HTTP proxy host[:port] */
926             p = vec[2];
927
928             if (strcmp(p, ".") != 0)
929             {
930                cur_fwd->forward_port = 8000;
931                parse_forwarder_address(p, &cur_fwd->forward_host,
932                   &cur_fwd->forward_port);
933             }
934
935             /* Add to list. */
936             cur_fwd->next = config->forward;
937             config->forward = cur_fwd;
938
939             break;
940
941 /* *************************************************************************
942  * forwarded-connect-retries n
943  * *************************************************************************/
944          case hash_forwarded_connect_retries :
945             config->forwarded_connect_retries = atoi(arg);
946             break;
947
948 /* *************************************************************************
949  * handle-as-empty-doc-returns-ok 0|1
950  *
951  * Workaround for firefox hanging on blocked javascript pages.
952  *   Block with the "+handle-as-empty-document" flag and set the
953  *   "handle-as-empty-doc-returns-ok" run-time config flag so that
954  *   Privoxy returns a 200/OK status instead of a 403/Forbidden status
955  *   to the browser for blocked pages.
956  ***************************************************************************/
957          case hash_handle_as_empty_returns_ok:
958             if ((*arg != '\0') && (0 != atoi(arg)))
959             {
960                config->feature_flags |= RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
961             }
962             else
963             {
964                config->feature_flags &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
965             }
966             break;
967
968 /* *************************************************************************
969  * hostname hostname-to-show-on-cgi-pages
970  * *************************************************************************/
971          case hash_hostname :
972             freez(config->hostname);
973             config->hostname = strdup(arg);
974             if (NULL == config->hostname)
975             {
976                log_error(LOG_LEVEL_FATAL, "Out of memory saving hostname.");
977             }
978             break;
979
980 /* *************************************************************************
981  * keep-alive-timeout timeout
982  * *************************************************************************/
983 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
984          case hash_keep_alive_timeout :
985             if (*arg != '\0')
986             {
987                int timeout = atoi(arg);
988                if (0 < timeout)
989                {
990                   config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
991                   config->keep_alive_timeout = (unsigned int)timeout;
992                }
993                else
994                {
995                   config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
996                }
997             }
998             break;
999 #endif
1000
1001 /* *************************************************************************
1002  * listen-address [ip][:port]
1003  * *************************************************************************/
1004          case hash_listen_address :
1005             freez(config->haddr);
1006             config->haddr = strdup(arg);
1007             break;
1008
1009 /* *************************************************************************
1010  * logdir directory-name
1011  * *************************************************************************/
1012          case hash_logdir :
1013             freez(config->logdir);
1014             config->logdir = make_path(NULL, arg);
1015             break;
1016
1017 /* *************************************************************************
1018  * logfile log-file-name
1019  * In logdir by default
1020  * *************************************************************************/
1021          case hash_logfile :
1022             if (daemon_mode)
1023             {
1024                logfile = make_path(config->logdir, arg);
1025                if (NULL == logfile)
1026                {
1027                   log_error(LOG_LEVEL_FATAL, "Out of memory while creating logfile path");
1028                }
1029             }
1030             break;
1031
1032 /* *************************************************************************
1033  * max-client-connections number
1034  * *************************************************************************/
1035          case hash_max_client_connections :
1036             if (*arg != '\0')
1037             {
1038                int max_client_connections = atoi(arg);
1039                if (0 <= max_client_connections)
1040                {
1041                   config->max_client_connections = max_client_connections;
1042                }
1043             }
1044             break;
1045
1046 /* *************************************************************************
1047  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
1048  * *************************************************************************/
1049 #ifdef FEATURE_ACL
1050          case hash_permit_access:
1051             strlcpy(tmp, arg, sizeof(tmp));
1052             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1053
1054             if ((vec_count != 1) && (vec_count != 2))
1055             {
1056                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1057                      "permit-access directive in configuration file.");
1058                string_append(&config->proxy_args,
1059                   "<br>\nWARNING: Wrong number of parameters for "
1060                   "permit-access directive in configuration file.<br><br>\n");
1061
1062                break;
1063             }
1064
1065             /* allocate a new node */
1066             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
1067
1068             if (cur_acl == NULL)
1069             {
1070                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1071                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1072                break;
1073             }
1074             cur_acl->action = ACL_PERMIT;
1075
1076             if (acl_addr(vec[0], cur_acl->src) < 0)
1077             {
1078                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
1079                   "for permit-access directive in configuration file: \"%s\"", vec[0]);
1080                string_append(&config->proxy_args,
1081                   "<br>\nWARNING: Invalid source address, port or netmask for "
1082                   "permit-access directive in configuration file: \"");
1083                string_append(&config->proxy_args,
1084                   vec[0]);
1085                string_append(&config->proxy_args,
1086                   "\"<br><br>\n");
1087                freez(cur_acl);
1088                break;
1089             }
1090             if (vec_count == 2)
1091             {
1092                if (acl_addr(vec[1], cur_acl->dst) < 0)
1093                {
1094                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
1095                      "for permit-access directive in configuration file: \"%s\"", vec[1]);
1096                   string_append(&config->proxy_args,
1097                      "<br>\nWARNING: Invalid destination address, port or netmask for "
1098                      "permit-access directive in configuration file: \"");
1099                   string_append(&config->proxy_args,
1100                      vec[1]);
1101                   string_append(&config->proxy_args,
1102                      "\"<br><br>\n");
1103                   freez(cur_acl);
1104                   break;
1105                }
1106             }
1107 #ifdef HAVE_RFC2553
1108             else
1109             {
1110                cur_acl->wildcard_dst = 1;
1111             }
1112 #endif /* def HAVE_RFC2553 */
1113
1114             /*
1115              * Add it to the list.  Note we reverse the list to get the
1116              * behaviour the user expects.  With both the ACL and
1117              * actions file, the last match wins.  However, the internal
1118              * implementations are different:  The actions file is stored
1119              * in the same order as the file, and scanned completely.
1120              * With the ACL, we reverse the order as we load it, then
1121              * when we scan it we stop as soon as we get a match.
1122              */
1123             cur_acl->next  = config->acl;
1124             config->acl = cur_acl;
1125
1126             break;
1127 #endif /* def FEATURE_ACL */
1128
1129 /* *************************************************************************
1130  * proxy-info-url url
1131  * *************************************************************************/
1132          case hash_proxy_info_url :
1133             freez(config->proxy_info_url);
1134             config->proxy_info_url = strdup(arg);
1135             break;
1136
1137 /* *************************************************************************
1138  * single-threaded
1139  * *************************************************************************/
1140          case hash_single_threaded :
1141             config->multi_threaded = 0;
1142             break;
1143
1144 /* *************************************************************************
1145  * socket-timeout numer_of_seconds
1146  * *************************************************************************/
1147          case hash_socket_timeout :
1148             if (*arg != '\0')
1149             {
1150                int socket_timeout = atoi(arg);
1151                if (0 < socket_timeout)
1152                {
1153                   config->socket_timeout = socket_timeout;
1154                }
1155                else
1156                {
1157                   log_error(LOG_LEVEL_FATAL,
1158                      "Invalid socket-timeout: '%s'", arg);
1159                }
1160             }
1161             break;
1162
1163 /* *************************************************************************
1164  * split-large-cgi-forms
1165  * *************************************************************************/
1166          case hash_split_large_cgi_forms :
1167             if ((*arg != '\0') && (0 != atoi(arg)))
1168             {
1169                config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1170             }
1171             else
1172             {
1173                config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1174             }
1175             break;
1176
1177 /* *************************************************************************
1178  * templdir directory-name
1179  * *************************************************************************/
1180          case hash_templdir :
1181             freez(config->templdir);
1182             config->templdir = make_path(NULL, arg);
1183             break;
1184
1185 /* *************************************************************************
1186  * toggle (0|1)
1187  * *************************************************************************/
1188 #ifdef FEATURE_TOGGLE
1189          case hash_toggle :
1190             global_toggle_state = atoi(arg);
1191             break;
1192 #endif /* def FEATURE_TOGGLE */
1193
1194 /* *************************************************************************
1195  * trust-info-url url
1196  * *************************************************************************/
1197 #ifdef FEATURE_TRUST
1198          case hash_trust_info_url :
1199             enlist(config->trust_info, arg);
1200             break;
1201 #endif /* def FEATURE_TRUST */
1202
1203 /* *************************************************************************
1204  * trustfile filename
1205  * (In confdir by default.)
1206  * *************************************************************************/
1207 #ifdef FEATURE_TRUST
1208          case hash_trustfile :
1209             freez(config->trustfile);
1210             config->trustfile = make_path(config->confdir, arg);
1211             break;
1212 #endif /* def FEATURE_TRUST */
1213
1214 /* *************************************************************************
1215  * usermanual url
1216  * *************************************************************************/
1217          case hash_usermanual :
1218             /*
1219              * XXX: If this isn't the first config directive, the
1220              * show-status page links to the website documentation
1221              * for the directives that were already parsed. Lame.
1222              */
1223             freez(config->usermanual);
1224             config->usermanual = strdup(arg);
1225             break;
1226
1227 /* *************************************************************************
1228  * Win32 Console options:
1229  * *************************************************************************/
1230
1231 /* *************************************************************************
1232  * hide-console
1233  * *************************************************************************/
1234 #ifdef _WIN_CONSOLE
1235          case hash_hide_console :
1236             hideConsole = 1;
1237             break;
1238 #endif /*def _WIN_CONSOLE*/
1239
1240
1241 /* *************************************************************************
1242  * Win32 GUI options:
1243  * *************************************************************************/
1244
1245 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
1246 /* *************************************************************************
1247  * activity-animation (0|1)
1248  * *************************************************************************/
1249          case hash_activity_animation :
1250             g_bShowActivityAnimation = atoi(arg);
1251             break;
1252
1253 /* *************************************************************************
1254  *  close-button-minimizes (0|1)
1255  * *************************************************************************/
1256          case hash_close_button_minimizes :
1257             g_bCloseHidesWindow = atoi(arg);
1258             break;
1259
1260 /* *************************************************************************
1261  * log-buffer-size (0|1)
1262  * *************************************************************************/
1263          case hash_log_buffer_size :
1264             g_bLimitBufferSize = atoi(arg);
1265             break;
1266
1267 /* *************************************************************************
1268  * log-font-name fontname
1269  * *************************************************************************/
1270          case hash_log_font_name :
1271             if (strlcpy(g_szFontFaceName, arg,
1272                    sizeof(g_szFontFaceName)) >= sizeof(g_szFontFaceName))
1273             {
1274                log_error(LOG_LEVEL_FATAL,
1275                   "log-font-name argument '%s' is longer than %u characters.",
1276                   arg, sizeof(g_szFontFaceName)-1);
1277             }
1278             break;
1279
1280 /* *************************************************************************
1281  * log-font-size n
1282  * *************************************************************************/
1283          case hash_log_font_size :
1284             g_nFontSize = atoi(arg);
1285             break;
1286
1287 /* *************************************************************************
1288  * log-highlight-messages (0|1)
1289  * *************************************************************************/
1290          case hash_log_highlight_messages :
1291             g_bHighlightMessages = atoi(arg);
1292             break;
1293
1294 /* *************************************************************************
1295  * log-max-lines n
1296  * *************************************************************************/
1297          case hash_log_max_lines :
1298             g_nMaxBufferLines = atoi(arg);
1299             break;
1300
1301 /* *************************************************************************
1302  * log-messages (0|1)
1303  * *************************************************************************/
1304          case hash_log_messages :
1305             g_bLogMessages = atoi(arg);
1306             break;
1307
1308 /* *************************************************************************
1309  * show-on-task-bar (0|1)
1310  * *************************************************************************/
1311          case hash_show_on_task_bar :
1312             g_bShowOnTaskBar = atoi(arg);
1313             break;
1314
1315 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
1316
1317
1318 /* *************************************************************************
1319  * Warnings about unsupported features
1320  * *************************************************************************/
1321 #ifndef FEATURE_ACL
1322          case hash_deny_access:
1323 #endif /* ndef FEATURE_ACL */
1324 #ifndef FEATURE_CGI_EDIT_ACTIONS
1325          case hash_enable_edit_actions:
1326 #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */
1327 #ifndef FEATURE_TOGGLE
1328          case hash_enable_remote_toggle:
1329 #endif /* ndef FEATURE_TOGGLE */
1330 #ifndef FEATURE_ACL
1331          case hash_permit_access:
1332 #endif /* ndef FEATURE_ACL */
1333 #ifndef FEATURE_TOGGLE
1334          case hash_toggle :
1335 #endif /* ndef FEATURE_TOGGLE */
1336 #ifndef FEATURE_TRUST
1337          case hash_trustfile :
1338          case hash_trust_info_url :
1339 #endif /* ndef FEATURE_TRUST */
1340
1341 #ifndef _WIN_CONSOLE
1342          case hash_hide_console :
1343 #endif /* ndef _WIN_CONSOLE */
1344
1345 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
1346          case hash_activity_animation :
1347          case hash_close_button_minimizes :
1348          case hash_log_buffer_size :
1349          case hash_log_font_name :
1350          case hash_log_font_size :
1351          case hash_log_highlight_messages :
1352          case hash_log_max_lines :
1353          case hash_log_messages :
1354          case hash_show_on_task_bar :
1355 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
1356             /* These warnings are annoying - so hide them. -- Jon */
1357             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
1358             break;
1359
1360 /* *************************************************************************/
1361          default :
1362 /* *************************************************************************/
1363             /*
1364              * I decided that I liked this better as a warning than an
1365              * error.  To change back to an error, just change log level
1366              * to LOG_LEVEL_FATAL.
1367              */
1368             log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive '%s' (%luul) in line %lu "
1369                   "in configuration file (%s).",  buf, directive_hash, linenum, configfile);
1370             string_append(&config->proxy_args,
1371                " <strong class='warning'>Warning: Ignoring unrecognized directive:</strong>");
1372             break;
1373
1374 /* *************************************************************************/
1375       } /* end switch( hash_string(cmd) ) */
1376
1377       /* Save the argument for the show-status page. */
1378       savearg(cmd, arg, config);
1379       freez(buf);
1380    } /* end while ( read_config_line(...) ) */
1381
1382    fclose(configfp);
1383
1384    set_debug_level(config->debug);
1385
1386    freez(config->logfile);
1387
1388    if (daemon_mode)
1389    {
1390       if (NULL != logfile)
1391       {
1392          config->logfile = logfile;
1393          init_error_log(Argv[0], config->logfile);
1394       }
1395       else
1396       {
1397          disable_logging();
1398       }
1399    }
1400
1401 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1402    if (config->default_server_timeout > config->keep_alive_timeout)
1403    {
1404       log_error(LOG_LEVEL_ERROR,
1405          "Reducing the default-server-timeout from %d to the keep-alive-timeout %d.",
1406          config->default_server_timeout, config->keep_alive_timeout);
1407       config->default_server_timeout = config->keep_alive_timeout;
1408    }
1409 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
1410
1411 #ifdef FEATURE_CONNECTION_SHARING
1412    if (config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
1413    {
1414       if (config->multi_threaded)
1415       {
1416          set_keep_alive_timeout(config->keep_alive_timeout);
1417       }
1418       else
1419       {
1420          /*
1421           * While we could use keep-alive without multiple threads
1422           * if we didn't bother with enforcing the connection timeout,
1423           * that might make Tor users sad, even though they shouldn't
1424           * enable the single-threaded option anyway.
1425           *
1426           * XXX: We could still use Proxy-Connection: keep-alive.
1427           */
1428          config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
1429          log_error(LOG_LEVEL_ERROR,
1430             "Config option single-threaded disables connection keep-alive.");
1431       }
1432    }
1433    else if ((config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
1434    {
1435       log_error(LOG_LEVEL_ERROR, "Config option connection-sharing "
1436          "has no effect if keep-alive-timeout isn't set.");
1437       config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
1438    }
1439 #endif /* def FEATURE_CONNECTION_SHARING */
1440
1441    if (NULL == config->proxy_args)
1442    {
1443       log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args");
1444    }
1445
1446    if (config->actions_file[0])
1447    {
1448       add_loader(load_action_files, config);
1449    }
1450
1451    if (config->re_filterfile[0])
1452    {
1453       add_loader(load_re_filterfiles, config);
1454    }
1455
1456 #ifdef FEATURE_TRUST
1457    if (config->trustfile)
1458    {
1459       add_loader(load_trustfile, config);
1460    }
1461 #endif /* def FEATURE_TRUST */
1462
1463    if ( NULL == config->haddr )
1464    {
1465       config->haddr = strdup( HADDR_DEFAULT );
1466    }
1467
1468    if ( NULL != config->haddr )
1469    {
1470       if ((*config->haddr == '[')
1471          && (NULL != (p = strchr(config->haddr, ']')))
1472          && (p[1] == ':')
1473          && (0 < (config->hport = atoi(p + 2))))
1474       {
1475          *p = '\0';
1476          memmove((void *)config->haddr, config->haddr + 1,
1477             (size_t)(p - config->haddr));
1478       }
1479       else if (NULL != (p = strchr(config->haddr, ':'))
1480          && (0 < (config->hport = atoi(p + 1))))
1481       {
1482          *p = '\0';
1483       }
1484       else
1485       {
1486          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1487          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1488       }
1489       if (*config->haddr == '\0')
1490       {
1491          /*
1492           * Only the port specified. We stored it in config->hport
1493           * and don't need its text representation anymore.
1494           */
1495          freez(config->haddr);
1496       }
1497    }
1498
1499    /*
1500     * Want to run all the loaders once now.
1501     *
1502     * Need to set up a fake csp, so they can get to the config.
1503     */
1504    fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
1505    fake_csp->config = config;
1506
1507    if (run_loader(fake_csp))
1508    {
1509       freez(fake_csp);
1510       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
1511       /* Never get here - LOG_LEVEL_FATAL causes program exit */
1512    }
1513    freez(fake_csp);
1514
1515 /* FIXME: this is a kludge for win32 */
1516 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
1517
1518    g_default_actions_file = config->actions_file[1]; /* FIXME Hope this is default.action */
1519    g_user_actions_file  = config->actions_file[2];  /* FIXME Hope this is user.action */
1520    g_default_filterfile = config->re_filterfile[0]; /* FIXME Hope this is default.filter */
1521    g_user_filterfile    = config->re_filterfile[1]; /* FIXME Hope this is user.filter */
1522
1523 #ifdef FEATURE_TRUST
1524    g_trustfile        = config->trustfile;
1525 #endif /* def FEATURE_TRUST */
1526
1527
1528 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
1529 /* FIXME: end kludge */
1530
1531
1532    config->need_bind = 1;
1533
1534    if (current_configfile)
1535    {
1536       struct configuration_spec * oldcfg = (struct configuration_spec *)
1537                                            current_configfile->f;
1538       /*
1539        * Check if config->haddr,hport == oldcfg->haddr,hport
1540        *
1541        * The following could be written more compactly as a single,
1542        * (unreadably long) if statement.
1543        */
1544       config->need_bind = 0;
1545       if (config->hport != oldcfg->hport)
1546       {
1547          config->need_bind = 1;
1548       }
1549       else if (config->haddr == NULL)
1550       {
1551          if (oldcfg->haddr != NULL)
1552          {
1553             config->need_bind = 1;
1554          }
1555       }
1556       else if (oldcfg->haddr == NULL)
1557       {
1558          config->need_bind = 1;
1559       }
1560       else if (0 != strcmp(config->haddr, oldcfg->haddr))
1561       {
1562          config->need_bind = 1;
1563       }
1564
1565       current_configfile->unloader = unload_configfile;
1566    }
1567
1568    fs->next = files->next;
1569    files->next = fs;
1570
1571    current_configfile = fs;
1572
1573    return (config);
1574 }
1575
1576
1577 /*********************************************************************
1578  *
1579  * Function    :  savearg
1580  *
1581  * Description :  Called from `load_config'.  It saves each non-empty
1582  *                and non-comment line from config into
1583  *                config->proxy_args.  This is used to create the
1584  *                show-proxy-args page.  On error, frees
1585  *                config->proxy_args and sets it to NULL
1586  *
1587  * Parameters  :
1588  *          1  :  command = config setting that was found
1589  *          2  :  argument = the setting's argument (if any)
1590  *          3  :  config = Configuration to save into.
1591  *
1592  * Returns     :  N/A
1593  *
1594  *********************************************************************/
1595 static void savearg(char *command, char *argument, struct configuration_spec * config)
1596 {
1597    char * buf;
1598    char * s;
1599
1600    assert(command);
1601    assert(argument);
1602
1603    /*
1604     * Add config option name embedded in
1605     * link to its section in the user-manual
1606     */
1607    buf = strdup("\n<a href=\"");
1608    if (!strncmpic(config->usermanual, "file://", 7) ||
1609        !strncmpic(config->usermanual, "http", 4))
1610    {
1611       string_append(&buf, config->usermanual);
1612    }
1613    else
1614    {
1615       string_append(&buf, "http://" CGI_SITE_2_HOST "/user-manual/");
1616    }
1617    string_append(&buf, CONFIG_HELP_PREFIX);
1618    string_join  (&buf, string_toupper(command));
1619    string_append(&buf, "\">");
1620    string_append(&buf, command);
1621    string_append(&buf, "</a> ");
1622
1623    if (NULL == buf)
1624    {
1625       freez(config->proxy_args);
1626       return;
1627    }
1628
1629    if ( (NULL != argument) && ('\0' != *argument) )
1630    {
1631       s = html_encode(argument);
1632       if (NULL == s)
1633       {
1634          freez(buf);
1635          freez(config->proxy_args);
1636          return;
1637       }
1638
1639       if (strncmpic(argument, "http://", 7) == 0)
1640       {
1641          string_append(&buf, "<a href=\"");
1642          string_append(&buf, s);
1643          string_append(&buf, "\">");
1644          string_join  (&buf, s);
1645          string_append(&buf, "</a>");
1646       }
1647       else
1648       {
1649          string_join  (&buf, s);
1650       }
1651    }
1652
1653    string_append(&buf, "<br>");
1654    string_join(&config->proxy_args, buf);
1655 }
1656
1657
1658 /*
1659   Local Variables:
1660   tab-width: 3
1661   end:
1662 */