Removing a single unused #define which referenced BUFSIZ
[privoxy.git] / cgi.c
1 const char cgi_rcs[] = "$Id: cgi.c,v 1.6 2001/06/07 23:05:19 jongfoster Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
5  *
6  * Purpose     :  Declares functions to intercept request, generate
7  *                html or gif answers, and to compose HTTP resonses.
8  *                
9  *                Functions declared include:
10  * 
11  *
12  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
13  *                IJBSWA team.  http://ijbswa.sourceforge.net
14  *
15  *                Based on the Internet Junkbuster originally written
16  *                by and Copyright (C) 1997 Anonymous Coders and 
17  *                Junkbusters Corporation.  http://www.junkbusters.com
18  *
19  *                This program is free software; you can redistribute it 
20  *                and/or modify it under the terms of the GNU General
21  *                Public License as published by the Free Software
22  *                Foundation; either version 2 of the License, or (at
23  *                your option) any later version.
24  *
25  *                This program is distributed in the hope that it will
26  *                be useful, but WITHOUT ANY WARRANTY; without even the
27  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
28  *                PARTICULAR PURPOSE.  See the GNU General Public
29  *                License for more details.
30  *
31  *                The GNU General Public License should be included with
32  *                this file.  If not, you can view it at
33  *                http://www.gnu.org/copyleft/gpl.html
34  *                or write to the Free Software Foundation, Inc., 59
35  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  *
37  * Revisions   :
38  *    $Log: cgi.c,v $
39  *    Revision 1.6  2001/06/07 23:05:19  jongfoster
40  *    Removing code related to old forward and ACL files.
41  *
42  *    Revision 1.5  2001/06/05 19:59:16  jongfoster
43  *    Fixing multiline character string (a GCC-only "feature"), and snprintf (it's _snprintf under VC++).
44  *
45  *    Revision 1.4  2001/06/04 10:41:52  swa
46  *    show version string of cgi.h and cgi.c
47  *
48  *    Revision 1.3  2001/06/03 19:12:16  oes
49  *    introduced new cgi handling
50  *
51  *    Revision 1.1  2001/06/03 11:03:48  oes
52  *    Makefile/in
53  *
54  *    introduced cgi.c
55  *
56  *    actions.c:
57  *
58  *    adapted to new enlist_unique arg format
59  *
60  *    conf loadcfg.c
61  *
62  *    introduced confdir option
63  *
64  *    filters.c filtrers.h
65  *
66  *     extracted-CGI relevant stuff
67  *
68  *    jbsockets.c
69  *
70  *     filled comment
71  *
72  *    jcc.c
73  *
74  *     support for new cgi mechansim
75  *
76  *    list.c list.h
77  *
78  *    functions for new list type: "map"
79  *    extended enlist_unique
80  *
81  *    miscutil.c .h
82  *    introduced bindup()
83  *
84  *    parsers.c parsers.h
85  *
86  *    deleted const struct interceptors
87  *
88  *    pcrs.c
89  *    added FIXME
90  *
91  *    project.h
92  *
93  *    added struct map
94  *    added struct http_response
95  *    changes struct interceptors to struct cgi_dispatcher
96  *    moved HTML stuff to cgi.h
97  *
98  *    re_filterfile:
99  *
100  *    changed
101  *
102  *    showargs.c
103  *    NO TIME LEFT
104  *
105  *
106  *
107  **********************************************************************/
108 \f
109
110 #include "config.h"
111
112 #include <stdio.h>
113 #include <sys/types.h>
114 #include <stdlib.h>
115 #include <ctype.h>
116 #include <string.h>
117
118 #ifdef _WIN32
119 #define snprintf _snprintf
120 #endif /* def _WIN32 */
121
122 #include "project.h"
123 #include "cgi.h"
124 #include "list.h"
125 #include "pcrs.h"
126 #include "encode.h"
127 #include "ssplit.h"
128 #include "jcc.h"
129 #include "filters.h"
130 #include "actions.h"
131 #include "errlog.h"
132 #include "miscutil.h"
133 #include "showargs.h"
134
135 const char cgi_h_rcs[] = CGI_H_VERSION;
136
137 const struct cgi_dispatcher cgi_dispatchers[] = {
138    { "show-status", 
139          11, cgi_show_status,  
140          "Show information about the version and configuration" }, 
141    { "show-url-info",
142          13, cgi_show_url_info, 
143          "Show which actions apply to a URL and why"  },
144    { "send-banner",
145          11, cgi_send_banner, 
146          "HIDE Send the transparent or \"Junkbuster\" gif" },
147 #ifdef TRUST_FILES
148 /* { "untrusted-url",
149          15, ij_untrusted_url,
150               "HIDE Show why a URL was not trusted" }, */
151 #endif /* def TRUST_FILES */
152    { "",
153          0, cgi_default,
154          "HIDE Send a page linking to all unhidden CGIs" },
155    { NULL, 0, NULL, NULL }
156 };
157
158
159 /*********************************************************************
160  * 
161  * Function    :  dispatch_cgi
162  *
163  * Description :  Checks if a request URL has either the magical hostname
164  *                i.j.b or matches HOME_PAGE_URL/config/. If so, it parses
165  *                the (rest of the) path as a cgi name plus query string,
166  *                prepares a map that maps CGI parameter names to their values,
167  *                initializes the http_response struct, and calls the 
168  *                relevant CGI handler function.
169  *
170  * Parameters  :
171  *          1  :  csp = Current client state (buffers, headers, etc...)
172  *
173  * Returns     :  http_response if match, NULL if nonmatch or handler fail
174  *
175  *********************************************************************/
176 struct http_response *cgi_dispatch(struct client_state *csp)
177 {
178    char *argstring = NULL;
179    const struct cgi_dispatcher *d;
180    struct map *param_list;
181    struct http_response *response;
182
183    /*
184     * Should we intercept ?
185     */
186
187    /* Either the host matches CGI_PREFIX_HOST ..*/
188    if (0 == strcmpic(csp->http->host, CGI_PREFIX_HOST))
189    {
190       /* ..then the path will all be for us */
191       argstring = csp->http->path;
192    }
193    /* Or it's the host part of HOME_PAGE_URL ? */
194    else if (   (0 == strcmpic(csp->http->host, HOME_PAGE_URL + 7 ))
195             && (0 == strncmpic(csp->http->path,"/config", 7))
196             && ((csp->http->path[7] == '/') || (csp->http->path[7] == '\0')))
197    {
198       /* then it's everything following "/config" */
199       argstring = csp->http->path + 7;
200    }
201    else
202    {
203       return NULL;
204    }
205
206    /* 
207     * We have intercepted it.
208     */
209
210    /* Get mem for response */
211    if (NULL == ( response = zalloc(sizeof(*response))))
212    {
213       return NULL;
214    }
215
216    /* remove any leading slash */
217    if (*argstring == '/')
218    {
219       argstring++;
220    }
221
222    log_error(LOG_LEVEL_GPC, "%s%s cgi call", csp->http->hostport, csp->http->path);
223    log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", 
224                             csp->ip_addr_str, csp->http->cmd); 
225
226    for (d = cgi_dispatchers; d->handler; d++)
227    {
228       if (strncmp(argstring, d->name, d->name_length) == 0)
229       {
230          param_list = parse_cgi(argstring + d->name_length);
231          if ((d->handler)(csp, response, param_list))
232               {
233                  freez(response);
234               }
235
236               free_map(param_list);
237               return(response);
238       }
239    }
240
241    freez(response);
242    return(NULL);
243
244 }
245
246
247 /*********************************************************************
248  *
249  * Function    :  parse_cgi
250  *
251  * Description :  Parse a URL-encoded argument string into name/value
252  *                pairs and store them in a struct map list.
253  *
254  * Parameters  :
255  *          1  :  string = string to be parsed 
256  *
257  * Returns     :  poniter to param list, or NULL if failiure
258  *
259  *********************************************************************/
260 struct map *parse_cgi(char *argstring)
261 {
262    char *tmp, *p;
263    char *vector[BUFFER_SIZE];
264    int pairs, i;
265    struct map *cgi_params = NULL;
266
267    if(*argstring == '?') argstring++;
268    tmp = strdup(argstring);
269
270    pairs = ssplit(tmp, "&", vector, SZ(vector), 1, 1);
271
272    for (i = 0; i < pairs; i++)
273    {
274       if ((NULL != (p = strchr(vector[i], '='))) && (*(p+1) != '\0'))
275       {
276          *p = '\0';
277          cgi_params = map(cgi_params, url_decode(vector[i]), 0, url_decode(++p), 0);
278       }
279    }
280
281    free(tmp);
282    return(cgi_params);
283
284 }
285
286
287 /*********************************************************************
288  *
289  * Function    :  make_http_response
290  *
291  * Description :  Fill in the missing headers in an http response,
292  *                and flatten the headers to an http head.
293  *
294  * Parameters  :
295  *          1  :  rsp = pointer to http_response to be processed
296  *
297  * Returns     :  length of http head, or 0 on failiure
298  *
299  *********************************************************************/
300 int make_http_response(struct http_response *rsp)
301 {
302   char buf[BUFFER_SIZE];
303
304   /* Fill in the HTTP Status */
305   sprintf(buf, "HTTP/1.0 %s", rsp->status ? rsp->status : "200 OK");
306   enlist_first(rsp->headers, buf);
307
308   /* Set the Content-Length */
309   if (rsp->content_length == 0)
310   {
311      rsp->content_length = rsp->body ? strlen(rsp->body) : 0;
312   }
313
314
315   sprintf(buf, "Content-Length: %d", rsp->content_length);
316   enlist(rsp->headers, buf);
317
318   /* Fill in the default headers FIXME: Are these correct? sequence OK? check rfc! */
319   enlist_unique(rsp->headers, "Pragma: no-cache", 7);
320   enlist_unique(rsp->headers, "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT", 14);
321   enlist_unique(rsp->headers, "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT", 8);
322   enlist_unique(rsp->headers, "Content-Type: text/html", 13);
323   enlist(rsp->headers, "");
324   
325
326   /* Write the head */
327   if (NULL == (rsp->head = list_to_text(rsp->headers)))
328   {
329     free_http_response(rsp);
330     return(0);
331   }
332  
333   return(strlen(rsp->head));
334 }
335   
336
337 /*********************************************************************
338  *
339  * Function    :  free_http_response
340  *
341  * Description :  Free the memory occupied by an http_response
342  *                and its depandant structures.
343  *
344  * Parameters  :
345  *          1  :  rsp = pointer to http_response to be freed
346  *
347  * Returns     :  N/A
348  *
349  *********************************************************************/
350 void free_http_response(struct http_response *rsp)
351 {
352    if(rsp)
353    {
354       freez(rsp->status);
355       freez(rsp->head);
356       freez(rsp->body);
357       destroy_list(rsp->headers);
358    }
359 }
360
361
362 /*********************************************************************
363  *
364  * Function    :  fill_template
365  *
366  * Description :  CGI support function that loads a given HTML
367  *                template from the confdir, and fills it in
368  *                by replacing @name@ with value using pcrs,
369  *                for each item in the output map.
370  *
371  * Parameters  :
372  *           1 :  csp = Current client state (buffers, headers, etc...)
373  *           3 :  template = name of the HTML template to be used
374  *           2 :  answers = map with fill in symbol -> name pairs
375  *                FIXME: needs better name!
376  *
377  * Returns     :  char * with filled out form, or NULL if failiure
378  *
379  *********************************************************************/
380 char *fill_template(struct client_state *csp, char *template, struct map *answers)
381 {
382    struct map *m;
383    pcrs_job *job, *joblist = NULL;
384    char buf[BUFFER_SIZE];
385    char *new, *old = NULL;
386    int size;
387    FILE *fp;
388
389    /*
390     * Open template file or fail
391     */
392    snprintf(buf, BUFFER_SIZE, "%s/templates/%s", csp->config->confdir, template);
393
394    if(NULL == (fp = fopen(buf, "r")))
395         {
396            log_error(LOG_LEVEL_ERROR, "error loading template %s: %E", buf);
397       return NULL;
398         }
399         
400    /* 
401     * Assemble pcrs joblist from answers map
402     */
403    for (m = answers; m; m = m->next)
404         {
405            int error;
406
407            snprintf(buf, BUFFER_SIZE, "s°@%s@°%s°ig", m->name, m->value);
408
409            if(NULL == (job = pcrs_make_job(buf, &error)))
410                 {
411                   log_error(LOG_LEVEL_ERROR, "Adding template fill job %s failed with error %d",
412                                                 buf, error);
413                   while ( NULL != (joblist = pcrs_free_job(joblist)) ) {};
414                   return NULL;
415                 }
416                 else
417                 {
418                    job->next = joblist;
419                         joblist = job;
420                 }
421         }
422
423    /* 
424     * Read the file, ignoring comments
425     */
426         while (fgets(buf, BUFFER_SIZE, fp))
427         {
428       /* skip lines starting with '#' */
429            if(*buf == '#') continue;
430         
431       old = strsav(old, buf);
432         }
433         fclose(fp);
434
435    /*
436     * Execute the jobs
437     */
438         size = strlen(old) + 1;
439    new = old;
440
441    for (job = joblist; NULL != job; job = job->next)
442    {
443            pcrs_exec_substitution(job, old, size, &new, &size);
444       if (old != buf) free(old);
445       old=new;
446         }
447
448    /*
449     * Free the jobs & return
450     */
451    while ( NULL != (joblist = pcrs_free_job(joblist)) ) {};
452    return(new);
453
454 }
455
456
457 /*********************************************************************
458  *
459  * Function    :  dump_map
460  *
461  * Description :  HTML-dump a map for debugging
462  *
463  * Parameters  :
464  *          1  :  map = map to dump
465  *
466  * Returns     :  string with HTML
467  *
468  *********************************************************************/
469 char *dump_map(struct map *map)
470 {
471    struct map *p = map;
472    char *ret = NULL;
473
474
475    ret = strsav(ret, "<table>\n");
476
477    while (p)
478    {
479       ret = strsav(ret, "<tr><td><b>");
480       ret = strsav(ret, p->name);
481       ret = strsav(ret, "</b></td><td>");
482       ret = strsav(ret, p->value);
483       ret = strsav(ret, "</td></tr>\n");
484       p = p->next;
485    }
486
487    ret = strsav(ret, "</table>\n");
488    return(ret);
489 }
490
491
492 /*********************************************************************
493  *
494  * Function    :  cgi_default
495  *
496  * Description :  CGI function that is called if no action was given
497  *                lists menu of available unhidden CGIs.
498  *               
499  * Parameters  :
500  *           1 :  csp = Current client state (buffers, headers, etc...)
501  *           2 :  rsp = http_response data structure for output
502  *           3 :  parameters = map of cgi parameters
503  *
504  * Returns     :  0
505  *
506  *********************************************************************/
507 int cgi_default(struct client_state *csp, struct http_response *rsp,
508                 struct map *parameters)
509 {
510    char *p, *tmp = NULL;
511    char buf[BUFFER_SIZE];
512    const struct cgi_dispatcher *d;
513         struct map *exports = NULL;
514
515    /* List available unhidden CGI's and export as "other-cgis" */
516    for (d = cgi_dispatchers; d->handler; d++)
517    {
518       if (strncmp(d->description, "HIDE", 4))
519            {
520          snprintf(buf, BUFFER_SIZE, "<li><a href=%s/config/%s>%s</a></li>",
521                                   HOME_PAGE_URL, d->name, d->description);
522          tmp = strsav(tmp, buf);
523       }
524         }
525         exports = map(exports, "other-cgis", 1, tmp, 0);
526
527    /* If there were other parameters, export a dump as "cgi-parameters" */
528    if(parameters)
529         {
530       p = dump_map(parameters);
531            tmp = strsav(tmp, "<p>What made you think this cgi takes options?\n"
532                         "Anyway, here they are, in case you're interested:</p>\n");
533                 tmp = strsav(tmp, p);
534                 exports = map(exports, "cgi-parameters", 1, tmp, 0);
535       free(p);
536         }
537         else
538         {
539            exports = map(exports, "cgi-parameters", 1, "", 1);
540         }
541
542    rsp->body = fill_template(csp, "default", exports);
543
544    free_map(exports);
545    return(0);
546
547 }
548
549
550 /*********************************************************************
551  *
552  * Function    :  cgi_send_banner
553  *
554  * Description :  CGI function that returns a banner. 
555  *
556  * Parameters  :
557  *           1 :  csp = Current client state (buffers, headers, etc...)
558  *           2 :  rsp = http_response data structure for output
559  *           3 :  parameters = map of cgi parameters
560  *
561  * CGI Parameters :
562  *           type : Selects the type of banner between "trans" and "jb".
563  *                  Defaults to "jb" if absent or != "trans".
564  *
565  * Returns     :  0
566  *
567  *********************************************************************/
568 int cgi_send_banner(struct client_state *csp, struct http_response *rsp,
569                     struct map *parameters)
570 {
571    if(strcmp(lookup(parameters, "type"), "trans"))
572    {
573      rsp->body = bindup(CJBGIF, sizeof(CJBGIF));
574      rsp->content_length = sizeof(CJBGIF);
575    }
576    else
577    {
578      rsp->body = bindup(CBLANKGIF, sizeof(CBLANKGIF));
579      rsp->content_length = sizeof(CBLANKGIF);
580    }   
581
582    enlist(rsp->headers, "Content-Type: image/gif");
583
584    return(0);
585 }
586
587
588 #ifdef FAST_REDIRECTS
589 /*********************************************************************
590  *
591  * Function    :  redirect_url
592  *
593  * Description :  Checks for redirection URLs and returns a HTTP redirect
594  *                to the destination URL.
595  *
596  * Parameters  :
597  *          1  :  http = http_request request, check `basename's of blocklist
598  *          2  :  csp = Current client state (buffers, headers, etc...)
599  *
600  * Returns     :  NULL if URL was clean, HTTP redirect otherwise.
601  *
602  *********************************************************************/
603 char *redirect_url(struct http_request *http, struct client_state *csp)
604 {
605    char *p, *q;
606
607    p = q = csp->http->path;
608    log_error(LOG_LEVEL_REDIRECTS, "checking path: %s", p);
609
610    /* find the last URL encoded in the request */
611    while (p = strstr(p, "http://"))
612    {
613       q = p++;
614    }
615
616    /* if there was any, generate and return a HTTP redirect */
617    if (q != csp->http->path)
618    {
619       log_error(LOG_LEVEL_REDIRECTS, "redirecting to: %s", q);
620
621       p = (char *)malloc(strlen(HTTP_REDIRECT_TEMPLATE) + strlen(q));
622       sprintf(p, HTTP_REDIRECT_TEMPLATE, q);
623       return(p);
624    }
625    else
626    {
627       return(NULL);
628    }
629
630 }
631 #endif /* def FAST_REDIRECTS */
632
633
634
635 /*********************************************************************
636  *
637  * Function    :  cgi_show_status
638  *
639  * Description :  CGI function that returns a a web page describing the
640  *                current status of IJB.
641  *
642  * Parameters  :
643  *           1 :  csp = Current client state (buffers, headers, etc...)
644  *           2 :  rsp = http_response data structure for output
645  *           3 :  parameters = map of cgi parameters
646  *
647  * CGI Parameters :
648  *           type : Selects the type of banner between "trans" and "jb".
649  *                  Defaults to "jb" if absent or != "trans".
650  *
651  * Returns     :  0
652  *
653  *********************************************************************/
654 int cgi_show_status(struct client_state *csp, struct http_response *rsp,
655                     struct map *parameters)
656 {
657    char *s = NULL;
658    struct map *exports = NULL;
659
660 #ifdef SPLIT_PROXY_ARGS
661    FILE * fp;
662    char buf[BUFFER_SIZE];
663    char * p;
664    const char * filename = NULL;
665    char * file_description = NULL;
666
667
668    p = lookup(parameters, "file");
669    switch (*p)
670    {
671    case 'p':
672       if (csp->actions_list)
673       {
674          filename = csp->actions_list->filename;
675          file_description = "Actions List";
676       }
677       break;
678
679 #ifdef PCRS
680    case 'r':
681       if (csp->rlist)
682       {
683          filename = csp->rlist->filename;
684          file_description = "Regex Filter List";
685       }
686       break;
687 #endif /* def PCRS */
688
689 #ifdef TRUST_FILES
690    case 't':
691       if (csp->tlist)
692       {
693          filename = csp->tlist->filename;
694          file_description = "Trust List";
695       }
696       break;
697 #endif /* def TRUST_FILES */
698    }
699
700    if (NULL != filename)
701    {
702            exports = map(exports, "filename", 1, file_description, 1);
703       exports = map(exports, "filepath", 1, html_encode(filename), 0);
704
705       if ((fp = fopen(filename, "r")) == NULL)
706       {
707          exports = map(exports, "content", 1, "</pre><h1>ERROR OPENING FILE!</h1><pre>", 1);
708       }
709       else
710       {
711          while (fgets(buf, sizeof(buf), fp))
712          {
713             p = html_encode(buf);
714             if (p)
715             {
716                s = strsav(s, p);
717                freez(p);
718                s = strsav(s, "<br>");
719             }
720          }
721          fclose(fp);
722          exports = map(exports, "contents", 1, s, 0);
723       }
724       rsp->body = fill_template(csp, "show-status-file", exports);;
725       free_map(exports);
726       return(0);
727
728    }
729
730 #endif /* def SPLIT_PROXY_ARGS */
731
732    exports = map(exports, "redirect-url", 1, REDIRECT_URL, 1);
733    exports = map(exports, "version", 1, VERSION, 1);
734    exports = map(exports, "home-page", 1, HOME_PAGE_URL, 1);
735    exports = map(exports, "invocation-args", 1, csp->config->proxy_args_header, 1);
736
737
738 #ifdef STATISTICS
739    exports = map(exports, "statistics", 1, add_stats(NULL), 0);
740 #else
741    exports = map(exports, "statistics", 1, "", 1);
742 #endif /* ndef STATISTICS */
743
744 #ifdef SPLIT_PROXY_ARGS
745    if (csp->actions_list)
746    {
747       exports = map(exports, "actions-filename", 1,  csp->actions_list->filename, 1);
748         }
749    else
750         {
751            exports = map(exports, "actions-filename", 1, "None specified", 1);
752         }
753
754 #ifdef PCRS
755    if (csp->rlist)
756    {
757       exports = map(exports, "re-filter-filename", 1,  csp->rlist->filename, 1);
758         }
759    else
760         {
761            exports = map(exports, "re-filter-filename", 1, "None specified", 1);
762         }
763 #else
764    exports = map(exports, "re-filter-killer-start.*re-filter-killer-end", 1, "", 1);
765 #endif /* ndef PCRS */
766
767 #ifdef TRUST_FILES
768    if (csp->tlist)
769    {
770       exports = map(exports, "trust-filename", 1,  csp->tlist->filename, 1);
771         }
772    else
773         {
774            exports = map(exports, "trust-filename", 1, "None specified", 1);
775         }
776 #else
777    exports = map(exports, "acl-killer-start.*acl-killer-end", 1, "", 1);
778 #endif /* ndef TRUST_FILES */
779
780    exports = map(exports, ".list", 1, "" , 1);
781
782 #else /* ifndef SPLIT_PROXY_ARGS */
783    exports = map(exports, "magic-eliminator-start.*magic-eliminator-end", 1, "", 1);
784
785    if (csp->clist)
786    {
787       map(exports, "clist", 1, csp->clist->proxy_args , 1);
788    }
789
790 #ifdef PCRS
791    if (csp->rlist)
792    {
793       map(exports, "rlist", 1, csp->rlist->proxy_args , 1);
794         }
795 #endif /* def PCRS */
796
797 #ifdef TRUST_FILES
798     if (csp->tlist)
799    {
800       map(exports, "tlist", 1, csp->tlist->proxy_args , 1);
801         }
802 #endif /* def TRUST_FILES */
803
804 #endif /* ndef SPLIT_PROXY_ARGS */
805
806         s = end_proxy_args(csp->config);
807    exports = map(exports, "rcs-and-defines", 1, s , 0);
808
809
810    rsp->body = fill_template(csp, "show-status", exports);
811    free_map(exports);
812    return(0);
813
814 }
815
816  
817  /*********************************************************************
818  *
819  * Function    :  cgi_show_url_info
820  *
821  * Description :  (please fill me in)
822  *
823  * Parameters  :
824  *          1  :  http = http_request request for crunched URL
825  *          2  :  csp = Current client state (buffers, headers, etc...)
826  *
827  * Returns     :  ???FIXME
828  *
829  *********************************************************************/
830 int cgi_show_url_info(struct client_state *csp, struct http_response *rsp,\r
831                       struct map *parameters)\r
832 {
833    const char * host_param = lookup(parameters, "url");\r
834    char * host = NULL;\r
835
836    if (*host_param != '\0')\r
837    {
838       host = strdup(host_param);
839    }
840    if (host != NULL)
841    {
842       char * matches = NULL;
843       char * path;
844       char * s;
845       int port = 80;
846       struct file_list *fl;
847       struct url_actions *b;
848       struct url_spec url[1];
849       struct current_action_spec action[1];
850       struct map *exports = NULL;\r
851
852       exports = map(exports, "url", 1, html_encode(host), 0);\r
853 \r
854       init_current_action(action);
855
856       s = current_action_to_text(action);
857       exports = map(exports, "default", 1, s , 0);\r
858
859       if (((fl = csp->actions_list) == NULL) || ((b = fl->f) == NULL))\r
860       {\r
861          exports = map(exports, "matches", 1, "" , 1);\r
862          exports = map(exports, "final", 1, lookup(exports, "default"), 1);\r
863 \r
864          freez(host);\r
865          free_current_action(action);\r
866 \r
867          rsp->body = fill_template(csp, "show-url-info", exports);\r
868          free_map(exports);\r
869 \r
870          return 0;\r
871       }\r
872 \r
873       s = strchr(host, '/');
874       if (s != NULL)
875       {
876          path = strdup(s);
877          *s = '\0';
878       }
879       else
880       {
881          path = strdup("");
882       }
883       s = strchr(host, ':');
884       if (s != NULL)
885       {
886          *s++ = '\0';
887          port = atoi(s);
888          s = NULL;\r
889       }
890
891       *url = dsplit(host);
892
893       /* if splitting the domain fails, punt */
894       if (url->dbuf == NULL)
895       {
896          exports = map(exports, "matches", 1, "" , 1);\r
897          exports = map(exports, "final", 1, lookup(exports, "default"), 1);\r
898 \r
899          freez(host);\r
900          freez(path);\r
901          free_current_action(action);\r
902 \r
903          rsp->body = fill_template(csp, "show-url-info", exports);\r
904          free_map(exports);\r
905 \r
906          return 0;\r
907       }
908
909       for (b = b->next; NULL != b; b = b->next)
910       {
911          if ((b->url->port == 0) || (b->url->port == port))
912          {
913             if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
914             {
915                if ((b->url->path == NULL) ||
916 #ifdef REGEX
917                   (regexec(b->url->preg, path, 0, NULL, 0) == 0)
918 #else
919                   (strncmp(b->url->path, path, b->url->pathlen) == 0)
920 #endif
921                )
922                {
923                   s = actions_to_text(b->action);
924                   matches = strsav(matches, "<b>{");
925                   matches = strsav(matches, s);
926                   matches = strsav(matches, " }</b><br>\n<code>");
927                   matches = strsav(matches, b->url->spec);
928                   matches = strsav(matches, "</code><br>\n<br>\n");
929                   freez(s);
930
931                   merge_current_action(action, b->action);
932                }
933             }
934          }
935       }
936
937       exports = map(exports, "matches", 1, matches , 0);\r
938       matches = NULL;\r
939 \r
940       freez(url->dbuf);
941       freez(url->dvec);
942
943       freez(host);
944       freez(path);
945 \r
946       s = current_action_to_text(action);
947       exports = map(exports, "final", 1, s, 0);\r
948       s = NULL;\r
949
950       free_current_action(action);
951
952       rsp->body = fill_template(csp, "show-url-info", exports);\r
953       free_map(exports);\r
954 \r
955       return 0;\r
956    }
957    else
958    {
959       rsp->body = fill_template(csp, "show-url-info-form", NULL);\r
960 \r
961       return 0;
962    }
963 }
964
965
966
967 #ifdef TRUST_FILES
968 /*********************************************************************
969  *
970  * Function    :  ij_untrusted_url
971  *
972  * Description :  This "crunch"es "http:/any.thing/ij-untrusted-url" and
973  *                returns a web page describing why it was untrusted.
974  *
975  * Parameters  :
976  *          1  :  http = http_request request for crunched URL
977  *          2  :  csp = Current client state (buffers, headers, etc...)
978  *
979  * Returns     :  A string that contains why this was untrusted.
980  *
981  *********************************************************************/
982 char *ij_untrusted_url(struct http_request *http, struct client_state *csp)
983 {
984    int n;
985    char *hostport, *path, *refer, *p, *v[9];
986    char buf[BUFFER_SIZE];
987    struct url_spec **tl, *t;
988
989
990    static const char format[] =
991       "HTTP/1.0 200 OK\r\n"
992       "Pragma: no-cache\n"
993       "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
994       "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\n"
995       "Content-Type: text/html\n\n"
996       "<html>\n"
997       "<head>\n"
998       "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
999       "</head>\n"
1000       BODY
1001       "<center><h1>"
1002       BANNER
1003       "</h1></center>"
1004       "The " BANNER " Proxy "
1005       "<A href=\"" HOME_PAGE_URL "\">"
1006       "(" HOME_PAGE_URL ") </A>"
1007       "intercepted the request for %s%s\n"
1008       "because the URL is not trusted.\n"
1009       "<br><br>\n";
1010
1011    if ((n = ssplit(http->path, "?+", v, SZ(v), 0, 0)) == 4)
1012    {
1013       hostport = url_decode(v[1]);
1014       path     = url_decode(v[2]);
1015       refer    = url_decode(v[3]);
1016    }
1017    else
1018    {
1019       hostport = strdup("undefined_host");
1020       path     = strdup("/undefined_path");
1021       refer    = strdup("undefined");
1022    }
1023
1024    n  = sizeof(format);
1025    n += strlen(hostport);
1026    n += strlen(path    );
1027
1028    if ((p = (char *)malloc(n)))
1029    {
1030       sprintf(p, format, hostport, path);
1031    }
1032
1033    strsav(p, "The referrer in this request was <strong>");
1034    strsav(p, refer);
1035    strsav(p, "</strong><br>\n");
1036
1037    freez(hostport);
1038    freez(path    );
1039    freez(refer   );
1040
1041    p = strsav(p, "<h3>The following referrers are trusted</h3>\n");
1042
1043    for (tl = csp->config->trust_list; (t = *tl) ; tl++)
1044    {
1045       sprintf(buf, "%s<br>\n", t->spec);
1046       p = strsav(p, buf);
1047    }
1048
1049    if (csp->config->trust_info->next)
1050    {
1051       struct list *l;
1052
1053       strcpy(buf,
1054          "<p>"
1055          "You can learn more about what this means "
1056          "and what you may be able to do about it by "
1057          "reading the following documents:<br>\n"
1058          "<ol>\n"
1059       );
1060
1061       p = strsav(p, buf);
1062
1063       for (l = csp->config->trust_info->next; l ; l = l->next)
1064       {
1065          sprintf(buf,
1066             "<li> <a href=%s>%s</a><br>\n",
1067                l->str, l->str);
1068          p = strsav(p, buf);
1069       }
1070
1071       p = strsav(p, "</ol>\n");
1072    }
1073
1074    p = strsav(p, "</body>\n" "</html>\n");
1075
1076    return(p);
1077
1078 }
1079 #endif /* def TRUST_FILES */
1080
1081
1082 #ifdef STATISTICS
1083 /*********************************************************************
1084  *
1085  * Function    :  add_stats
1086  *
1087  * Description :  Statistics function of JB.  Called by `show_proxy_args'.
1088  *
1089  * Parameters  :
1090  *          1  :  s = string that holds the proxy args description page
1091  *
1092  * Returns     :  A pointer to the descriptive status web page.
1093  *
1094  *********************************************************************/
1095 char *add_stats(char *s)
1096 {
1097    /*
1098     * Output details of the number of requests rejected and
1099     * accepted. This is switchable in the junkbuster config.
1100     * Does nothing if this option is not enabled.
1101     */
1102
1103    float perc_rej;   /* Percentage of http requests rejected */
1104    char out_str[81];
1105    int local_urls_read     = urls_read;
1106    int local_urls_rejected = urls_rejected;
1107
1108    /*
1109     * Need to alter the stats not to include the fetch of this
1110     * page.
1111     *
1112     * Can't do following thread safely! doh!
1113     *
1114     * urls_read--;
1115     * urls_rejected--; * This will be incremented subsequently *
1116     */
1117
1118    s = strsav(s,"<h2>Statistics for this " BANNER ":</h2>\n");
1119
1120    if (local_urls_read == 0)
1121    {
1122
1123       s = strsav(s,"No activity so far!\n");
1124
1125    }
1126    else
1127    {
1128
1129       perc_rej = (float)local_urls_rejected * 100.0F /
1130             (float)local_urls_read;
1131
1132       sprintf(out_str,
1133          "%d requests received, %d filtered "
1134          "(%6.2f %%).",
1135          local_urls_read, 
1136          local_urls_rejected, perc_rej);
1137
1138       s = strsav(s,out_str);
1139    }
1140
1141    return(s);
1142 }
1143 #endif /* def STATISTICS */
1144
1145 /*
1146   Local Variables:
1147   tab-width: 3
1148   end:
1149 */