File: apache.c

package info (click to toggle)
libapache-csacek 2.1.9-4
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 1,500 kB
  • ctags: 1,773
  • sloc: ansic: 11,833; makefile: 454; yacc: 199; sh: 164; php: 51; sed: 5
file content (1384 lines) | stat: -rw-r--r-- 38,977 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
#line 2 "apache.c"
/*-
 * C-SaCzech
 * Copyright (c) 1996-2002 Jaromir Dolecek <dolecek@ics.muni.cz>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Jaromir Dolecek
 *	for the CSacek project.
 * 4. The name of Jaromir Dolecek may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY JAROMIR DOLECEK ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL JAROMIR DOLECEK BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* $Id: apache.c,v 1.109.2.1 2002/03/05 21:07:40 dolecek Exp $ */

/* this needs to be included _before_ "csacek.h" */
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "http_log.h"
#include "util_script.h"
#include "http_main.h"
#include "http_request.h"
#include "http_core.h"

#include "csacek.h"
#include "csa_version.h"

/* local functions */
static int x_setheaderin_func __P((void *, const char *key, const char *value));
static void x_csa_init __P((server_rec *, struct pool *));
static int x_csa_rewrite __P((request_rec *));
static int x_csa_fixup __P((request_rec *));
static int x_csa_run __P((request_rec *));
#ifdef EAPI
static int csa_sslhandle_hook __P((request_rec *));
#endif
#ifndef CSA_USE_APACHE13_API
static int ap_is_initial_req __P((request_rec *r));
#endif 

/* structure used for holding CSacek context */
typedef struct csa_ap_ctx {
#ifdef EAPI
	char foobar[4];	
#endif
	csa_params_t *p;
	BUFF *oldcl;
	FILE *tmpfp;
#ifdef EAPI
	BUFF *newcl;
#endif
} csa_ap_ctx_t;

/* local variables */

#ifndef CSA_USE_APACHE13_API
/*
 * Note that Apache 1.1 and Apache 1.2 used purely process model, so
 * it's actually safe to use global variable. Under Apache 1.3+, we
 * store the context in r->notes array.
 */
static csa_ap_ctx_t csactx__;
#endif

/* used when request won't be served "normal" way */
#define CSA_MAGIC_TYPE	"csacek-output"

/* used to hide symbols not usable for Apache 1.1 */
#ifdef CSA_USE_APACHE11_API
#  define CSA_A12_SYM(x)	
#  define CSA_A12_SYM2(x,y)
#else
#  define CSA_A12_SYM(x)	x
#  define CSA_A12_SYM2(x,y)	x, y,
#endif

/* basic support for threaded Apache */
#ifndef MODULE_VAR_EXPORT
#  define MODULE_VAR_EXPORT
#endif

#if defined(APACHE_SSL) || defined(EAPI) || defined(STRONGHOLD) || \
	defined(__MSWIN__)
#  define CSA_FORCE_PROCESS_INPUT
#endif

/* defines for configuration commands */
#define CSA_BARDEF	1
#define CSA_DEFCHARSET	2
#define CSA_IPREFIX	3
#define CSA_PARTNAME	4
#define CSA_TEMPLATES	5

/*
 * Used to fill in r->proto_num. New in Apache 1.3, define it if it's not
 * available.
 */
#ifndef HTTP_VERSION
#define HTTP_VERSION(major, minor)	(1000*(major)+(minor))
#endif

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* implementation of a few functions which are not available in all      */
/* supported version of Apache (1.1-1.3)                                 */

#ifdef CSA_USE_APACHE11_API 
/*
 * implement rwrite() for pre 1.2 Apache servers
 */
int
ap_rwrite(const void *buf, int nbyte, request_rec *r)
{
    int n;
    if (r->connection->aborted) return EOF;
    n=bwrite(r->connection->client, buf, nbyte);
    if (r->sent_bodyct)
	bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent);
    return n;
}

/*
 * table_do() for pre 1.2 Apache servers
 */
void table_do (int (*comp)(void *, const char *, const char *), void *rec,
               const table *t, ...)
{
    va_list vp;
    char *argp;
    table_entry *elts = (table_entry *)t->elts;
    int rv, i;

    va_start(vp, t);

    argp = va_arg(vp, char *);

    do {
        for (rv = 1, i = 0; rv && (i < t->nelts); ++i) {
            if (elts[i].key && (!argp || !strcasecmp(elts[i].key, argp))) {
                rv = (*comp)(rec, elts[i].key, elts[i].val);
            }
        }
    } while (argp && ((argp = va_arg(vp, char *)) != NULL));

    va_end(vp);
}

/*
 * clear_table() was added in Apache 1.2 and this implementation is taken
 * from there
 */
void
clear_table (table *t)
{
    t->nelts = 0;
}


#endif /* CSA_USE_APACHE11_API */

#ifndef CSA_USE_APACHE13_API
/*
 * used to test if the request is initial request, or internal redirect
 * or sub-request - note: in Apache 1.3, this is part od Apache API
 */
static int
ap_is_initial_req(request_rec *r)
{
	return 
		(r->main == NULL) /* otherwise, this is a sub-request */
		&&
		(r->prev == NULL);/* otherwise, this is an internal redirect */
}
#endif /* ndef CSA_USE_APACHE13_API */

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ 
/* implementation of MD-compulsory functions for Apache                    */

/*
 * this is called from csa_malloc_fail() after some memory allocation
 * function fails
 */
void
csa_md_alloc_fail()
{
	/* not many things can be done ... */
	printf("C-SaCzech: malloc() failed !\n");
}

/*
 * this is called when we should run in whichcode mode
 */
int
csa_md_call_whichcode(p, filename)
  csa_params_t *p;
  const char *filename;
{
	request_rec *r = (request_rec *)p->m_cookie;
	ap_table_setn(r->notes, "csacek_whichcode", filename);
	
	return CSA_WHICHCODE;
}

/*
 * returns value of variable given; the needed vars are just standard CGI
 * variables
 */
const char *
csa_md_getvalueof(p, var)
  csa_params_t *p;
  const char *var;
{
	table *vart = ((const request_rec *)p->m_cookie)->notes;
#ifdef CSA_USE_APACHE11_API
	return table_get(vart, (char *) var);
#else
	return ap_table_get(vart, var);
#endif
}

/*
 * logs an error into server's error log
 * returns 1 if no other output should be written (i.e. the
 * rest of csa_http_error() should not be executed)
 */
int
csa_md_log_error(p, log)
  csa_params_t *p;
  const char *log;
{
#ifdef CSA_USE_APACHE13_API
	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
		((request_rec *)p->m_cookie)->server, "%s", log);
#else
	/* LINTED - cont castaway for log*/
	log_error((char *)log, ((request_rec *)p->m_cookie)->server);
#endif
	return 1;
}

/*
 * read's len bytes from input (i.e. result of request) and places
 * it in buf
 * returns number of characters written
 */
int
csa_md_read_response(p, buf, len)
  csa_params_t *p;
  char *buf;
  size_t len;
{
	return csa_fread(buf, 1, len, p->resp);
}

/*
 * used in csa_md_set_headersin() below
 * this is called in Apache's ap_table_do() for each key-value pair
 * found in the table
 */
static int
x_setheaderin_func(cookie, key, value)
  void *cookie;
  const char *key, *value;
{
	csa_params_t *p = (csa_params_t *) cookie;
	(void) csa_setheaderin(p, key, value, 0);
	return 1;
}

/*
 * get all input headers (headers sent by client) and store them
 * in ``p''
 */
int 
csa_md_set_headersin(p)
  csa_params_t *p;
{
	csa_setheaderin(p, "Content-Type", 
		csa_md_getvalueof(p, "CONTENT_TYPE"), 0);
	csa_setheaderin(p, "Content-Length", 
		csa_md_getvalueof(p, "CONTENT_LENGTH"), 0);

	ap_table_do(x_setheaderin_func, p, 
		((const request_rec *)p->m_cookie)->headers_in, NULL);
		
	return 0;
}

/*
 * separates headers and data; in most implementations, this means
 * all the headers and one extra newline is sent to client
 */
int
csa_md_send_separator(p)
  csa_params_t *p;
{
	ap_send_http_header((request_rec *)p->m_cookie);
	return 0;
}

/*
 * sends header given to an output
 */
void
csa_md_send_header(p, header_name, header_value)
  csa_params_t *p;
  const char *header_name, *header_value;
{
	request_rec *r = (request_rec *) p->m_cookie;

	/* special case Status & Content-Length - they are stored directly */
	/* in request structure */
	if (strcasecmp(header_name, "Status") == 0) {
		r->status_line = ap_pstrdup(p->pool_req, header_value);
		r->status = atoi(header_value);
        }
	else if (strcasecmp(header_name, "Content-Type") == 0) {
		r->content_type = ap_pstrdup(p->pool_req, header_value);
	}
	else if (strcasecmp(header_name, "Content-Encoding") == 0) {
		r->content_encoding = ap_pstrdup(p->pool_req, header_value);
	}
	/* all other headers should be put into r->headers_out */
	else {
		/* LINTED Apache 1.1 & 1.2 don't use const in prototype */
		ap_table_addn(r->headers_out, header_name, header_value);
	}
}

/* 
 * sends ``len'' bytes from the place pointed to by ``ptr'' 
 * into output
 */
int
csa_md_send_output(p, ptr, len)
  csa_params_t *p;
  const char *ptr;
  size_t len;
{
	return ap_rwrite(ptr, (int) len, (request_rec *) p->m_cookie);
}

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* Module staff                                                            */

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* following functions handle configuration                                */

/*
 * create per-directory configuration structure
 */
/* ARGSUSED */
static void *
csa_create_conf(pool *p, char *path)
{
	csa_conf_t *newcfg;

	newcfg = (csa_conf_t *)ap_pcalloc(p, sizeof(csa_conf_t));
	memcpy(newcfg, (const void *)&csa_cfg_def, sizeof(csa_conf_t));
	return (newcfg);
}

/*
 * merge two records and create new one
 */
static void *
csa_merge_conf(pool *p, void *_ocfg, void *_ncfg)
{
	csa_conf_t *ocfg = (csa_conf_t *)_ocfg;
	csa_conf_t *ncfg = (csa_conf_t *)_ncfg;
	csa_conf_t *newcfg = (csa_conf_t *) csa_create_conf(p, NULL);

	if (ncfg->flags != csa_cfg_def.flags)
		newcfg->flags = ncfg->flags;
	else
		newcfg->flags = ocfg->flags;

	if (csa_n_strcmp(ncfg->DefaultCharset, csa_cfg_def.DefaultCharset) !=0)
		newcfg->DefaultCharset = ncfg->DefaultCharset;
	else
		newcfg->DefaultCharset = ocfg->DefaultCharset;

	if (csa_n_strcmp(ncfg->DefaultPartname,csa_cfg_def.DefaultPartname) !=0)
		newcfg->DefaultPartname= ncfg->DefaultPartname;
	else
		newcfg->DefaultPartname= ocfg->DefaultPartname;

	if (csa_n_strcmp(ncfg->TemplateDir, csa_cfg_def.TemplateDir) != 0)
		newcfg->TemplateDir= ncfg->TemplateDir;
	else
		newcfg->TemplateDir = ocfg->TemplateDir;

	if (csa_n_strcmp(ncfg->BarDef, csa_cfg_def.BarDef) != 0)
		newcfg->BarDef= ncfg->BarDef;
	else
		newcfg->BarDef= ocfg->BarDef;

	if (csa_n_strcmp(ncfg->IgnorePrefix, csa_cfg_def.IgnorePrefix) != 0)
		newcfg->IgnorePrefix= ncfg->IgnorePrefix;
	else
		newcfg->IgnorePrefix= ocfg->IgnorePrefix;

	return (void *)newcfg;
}

static CSA_A12_SYM(const) char *
x_csa_setvalue(cmd_parms *cmd, csa_conf_t *cfg, char *value)
{
	cstools_t newcodeset;
	/* LINTED */ /* may loose bits, but it's safe in this case */
	int cmd_type = (int) cmd->info;

	if (value[0] == '\0') 
		return ap_pstrcat(cmd->temp_pool,
				CSA_A12_SYM2(cmd->cmd->name, ": ")
				"no parameter specified", NULL);

	switch (cmd_type) {
	    case CSA_DEFCHARSET:
		newcodeset = cstools_whichcode(value, 0);
		if (newcodeset < CSTOOLS_ASCII)
		    return "csacekDefaultCharset: invalid charset";

		cfg->DefaultCharset = value;
		break;

	    case CSA_PARTNAME:
		cfg->DefaultPartname = value;
		break;

	    case CSA_TEMPLATES:
		cfg->TemplateDir = value;
		break;

	    case CSA_BARDEF:
		cfg->BarDef = value;
		break;

	    case CSA_IPREFIX:
		cfg->IgnorePrefix = value;
		break;

	    default:
		return ap_pstrcat(cmd->temp_pool,
			CSA_A12_SYM2(cmd->cmd->name, ": ")
			"unknown configuration command", NULL);
	}

	/* NOTREACHED */
	return NULL;
}

static CSA_A12_SYM(const) char *
x_csa_flaghandler(cmd_parms *cmd, csa_conf_t *conf, int val)
{
	/* LINTED */ /* may loose bits, but it's safe in this case */
	int code = (int) cmd->info;

	if (val)
		CSA_SET(conf->flags, code);
	else
		CSA_UNSET(conf->flags, code);

	return NULL;
}

/*
 * this adds a server to a list of CSacek servers
 */
static CSA_A12_SYM(const) char *
x_csa_addservers(cmd_parms *cmd, void *cfg, const char *raw_args)
{
	size_t len = strlen(raw_args);
	char *ra_copy = ap_pstrndup(cmd->pool, raw_args, (int)len);

	/* if csacek_servers is not initialized yet, initialize it now */
	if (!csacek_servers)
		csa_cs_slist_init(cmd->pool);

	csa_add_servers(cmd->pool, csacek_servers, ra_copy, len);
	return NULL;
}

/* csacsekServer is deprecated, warn user to use csacekServers instead */
/* ARGSUSED */
static CSA_A12_SYM(const) char *
x_csa_addserver_deprec(cmd_parms *cmd, void *cfg, const char *ra)
{
	const char *msg =
	  "mod_csacek: csacekServer is deprecated, use csacekServers instead";
#ifdef CSA_USE_APACHE11_API
	return (char *) msg;
#else
	return msg;
#endif
}

		
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
/* hooks to request handling procedure                                     */

/* define it here so handlers can use it to get configuration */
module MODULE_VAR_EXPORT csacek_module;

/*
 * initialize module; create list of CSacek servers from all virtual
 * hosts and add CSacek version info into server identification for Apache 1.3
 */
static void
x_csa_init(server_rec *s, struct pool *p)
{
	server_rec *s1;
#ifndef CSA_USE_APACHE11_API
	server_addr_rec *s2;
#endif
#ifdef CSA_USE_APACHE13_API
	char csaname[50];

	ap_snprintf(csaname, sizeof(csaname), "CSacek/%s", CSA_VERSION);
	ap_add_version_component(csaname);
#endif

	/* if csacek_servers is not initialized yet, initialize it now */
	if (!csacek_servers)
		csa_cs_slist_init(p);

	/* server_hostname should never be NULL */
	for(s1 = s ; s1; s1 = s1->next) {
		csa_slist_add(csacek_servers, s1->server_hostname, s1->port);
	}

#ifdef CSA_USE_APACHE11_API
	/* we can't find all the other server addresses in Apache 1.1.X */
	/* so just add virtual host name as given to <VirtualHost>      */
	csa_slist_add(p, csacek_servers, s->virthost, s->port);
#else
	/* virtual hosts addresses for this particular host */
	for(s2 = s->addrs; s2; s2 = s2->next) {
		csa_slist_add(csacek_servers, s2->virthost, s2->host_port);
	}
#endif /* !CSA_USE_APACHE11_API */

#ifndef CSA_NO_INIT_COMPAT
	/* any other platform-dependant initializations */
	(void) csa_init_compat();
#endif

#ifdef EAPI
	csa_eapi_init();
#endif
}

#ifdef CSA_USE_APACHE13_API 

/* ARGSUSED */
static void
x_csa_initchild(server_rec *s, struct pool *wpool)
{
#if defined(CSA_DEBUG) && defined(__MSWIN__)
	csa_debuglog_mutex = csa_create_mutex(NULL);
#endif
}

/* ARGSUSED */
static void
x_csa_exitchild(server_rec *s, struct pool *wpool)
{
#if defined(CSA_DEBUG) && defined(__MSWIN__)
	CloseHandle(csa_debuglog_mutex), csa_debuglog_mutex = NULL;
#endif
}

#endif /* Apache 1.3 API */

#ifdef EAPI
/*
 * This is called in access authentication hook. We use this hook to
 * remove the ssl context from connection again. See x_csa_fixup() for
 * what egregious hack we do there. We redirect the output to temporary
 * file and force the server to use it. We don't want the ssl engine
 * to mess with the output in this stage. After the request is handled
 * by server, we reenable the ssl, process the data and send it to client.
 */
static int 
csa_sslhandle_hook(request_rec *r) {
	/*
	 * If sub-request, strip the ssl context back off; see x_csa_rewrite()
	 * for when it gets set.
	 * We do this here instead of doing it in access_check handler
	 * to not be dependant on load order. It's okay to do so here
	 * even if mod_ssl hook runs before us - it returns an error
	 * only if the Auth hook errorred out and we would be OOL in that case
	 * anyway.
	 */
	if (!ap_is_initial_req(r)) {
		csa_ap_ctx_t *csactx;

		/* only do staff if CSacek is on */
		csactx = (void *) ap_table_get(r->subprocess_env,
					"CSACEK_WITH_MODSSL");
		if (!csactx)
			return DECLINED;

		/* swap context back */
		r->connection->client = csactx->newcl;
		csactx->newcl = NULL;
	}

	return DECLINED;
}
#endif /* EAPI */

/*
 * this would change URL to point directly to object we want to give client
 * the part important for CSacek (i.e. /toFOO[.PART]) is stripped
 * and saved to r->notes as SCRIPT_NAME
 * Note: the URL will be rewrited even when csacekEngine is not (yet)  On --
 * 	it's possible it would be turned on for some sub-directory even
 *	through it's globally off 
 */
static int
x_csa_rewrite(request_rec *r)
{
	csa_conf_t *cfg;
	char *start, *end, *csacek;
	const char *sn=NULL, *ignoreprefix;
	size_t len;
	int found_ignoreprefix=0;

#ifdef EAPI
	/*
	 * When doing internal redirects, put in the original client context in
	 * so that mod_ssl has a chance to check necessary permissions and
	 * do renegotiations if necessary. CSacek would not be able to
	 * intercept the output if mod_ssl's Auth handler errors out, but
	 * such is life. We can't do anything with it within Apache 1.3- API.
	 *
	 * Without such hack, it would be impossible to use e.g. SSLRequireSSL
	 * directive for any directory.
	 * Note that if ssl access handler errors out, x_csa_run() has to
	 * do nothing (the data would be written directly to client in that
	 * case).
	 * We do this here instead of doing it in access_check handler,
	 * to not be dependant on load order.
	 */
	if (!ap_is_initial_req(r)) {
		csa_ap_ctx_t *csactx;
		ap_ctx *ssl;

 		csactx = (void *) ap_table_get(r->subprocess_env,
					"CSACEK_WITH_MODSSL");
		if (!csactx)
			return DECLINED;	/* no CSacek ctx, no action */

		if ((ssl = ap_ctx_get(csactx->oldcl->ctx, "ssl")) != NULL) {
			csactx->newcl = r->connection->client;
			r->connection->client =  csactx->oldcl;
		}
	}
#endif

	/* no rewrites for sub-request */
	if (r->proxyreq 			/* proxy request */
	    || !ap_is_initial_req(r)		/* subrequest or int. redir */
	    || ap_table_get(r->notes, "CSACEK")	/* run already */
	    )
		return DECLINED;

	/* we need to check for IgnorePrefix; unfortunately, this has to */
	/* be set globally (not per-dir), as in time of parsing per-dir  */
	/* config, it's too late to change URI */
	if (r->per_dir_config)  {
	    cfg = (csa_conf_t *)
		ap_get_module_config(r->per_dir_config, &csacek_module);
	}
	else
	    cfg = NULL;
	
	/* strip part of URI which marks output encoding and optionally */
	/* document variant */

	start = r->uri;

	/* strip IgnorePrefix */

	if (cfg && cfg->IgnorePrefix) 
		ignoreprefix = cfg->IgnorePrefix;
	else
		ignoreprefix = CSA_DEFAULT_IGNOREPREFIX;

	len = strlen(ignoreprefix);
	if (strncmp(start, ignoreprefix, len) == 0) {
		start += len;
		found_ignoreprefix = 1;
	}
	
	/* check initial component of URI for CSacek-related staff */
	if (csa_parse_sn(r->pool, start, NULL, NULL, &end, &csacek, NULL))
	{
		if (*end) {
			sn = csacek;
			r->uri = end;
		}
		else {
			/* redirect client on URL ending with slash */
			char *newuri = ap_pstrcat(r->pool, r->uri, "/", NULL);
#if defined(CSA_USE_APACHE13_API) || defined(APACHE_SSL)
			sn = ap_construct_url(r->pool, newuri, r);
#else
			sn = ap_construct_url(r->pool, newuri, r->server);
#endif
			ap_table_setn(r->headers_out, "Location", sn);
			return HTTP_MOVED_PERMANENTLY;
		}

		if (found_ignoreprefix)
			sn = ap_pstrcat(r->pool, ignoreprefix, sn, NULL);
	}
	else
		sn = "";

	ap_table_setn(r->notes, "SCRIPT_NAME", sn);

	return DECLINED;
}

/*
 * this would set all thing up for request's output to be processed
 * by CSacek
 */
static int
x_csa_fixup(request_rec *r)
{
	csa_conf_t *cfg;
	csa_params_t *p;
	int csa_result, recodeinput, process_input, fd_in;
	csa_item_t *hh;
	FILE *tmpfp, *dbg=NULL;
	char *port;
	server_rec *s = r->server;
	conn_rec *c = r->connection;
	BUFF *newcl, *oldcl=c->client;
	int use_oldcl=0;
	const char *ct;
	const csa_String *qs;
	csa_ap_ctx_t *csactx;

	/* do nothing for subrequest */
	if (r->proxyreq			/* proxy request */
	    || !ap_is_initial_req(r)	/* subrequest or internal redirect */
	    || (r->content_type && strncmp(r->content_type, "text/", 5) != 0
		&& !strstr(r->content_type, "httpd") )
					/* hopeless Content-Type */
	    )
		return DECLINED;

	cfg = (csa_conf_t *)
		ap_get_module_config(r->per_dir_config, &csacek_module);

	/* return if csacekEngine is off for this request */
	if (!CSA_ISSET(cfg->flags, CSA_CFG_ENGINEON))
		return DECLINED;

	/* if implicitWork is off and SCRIPT_NAME (CSacek part of URI)
	 * is empty, handle the request as if CSacek would be off */
	if (!CSA_ISSET(cfg->flags, CSA_CFG_IMPLICITWORK)) {
		const char *sn = ap_table_get(r->notes, "SCRIPT_NAME");
		if (!sn || !*sn) return DECLINED;
	}

	/* set a few vars needed by CSacek */
	ap_table_setn(r->notes, "SERVER_NAME", s->server_hostname);
	port = ap_palloc(r->pool, CSA_GETMAXNUMCOUNT(s->port) + 1);
	sprintf(port, "%u", s->port); /* safe */
	ap_table_set(r->notes, "SERVER_PORT", port);
	ap_table_setn(r->notes, "SERVER_PROTOCOL", r->protocol);
#ifdef CSA_USE_APACHE13_API
	ap_table_setn(r->notes, "REMOTE_HOST",
		ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST));
#else
	table_set(r->notes, "REMOTE_HOST",
		get_remote_host(c, r->per_dir_config, REMOTE_NAME));
#endif
	ap_table_setn(r->notes, "REMOTE_ADDR", c->remote_ip);
	/* SCRIPT_NAME is set in x_csa_rewrite() */
	ap_table_setn(r->notes, "PATH_INFO", r->uri);
	if (r->filename)
		ap_table_setn(r->notes, "PATH_TRANSLATED", r->filename);
	ap_table_setn(r->notes, "REQUEST_METHOD", r->method);
	if (r->args)
		ap_table_setn(r->notes, "QUERY_STRING", r->args);
#ifdef CSA_USE_APACHE13_API
	ap_table_setn(r->notes, "SERVER_SOFTWARE", ap_get_server_version());
#else
	table_set(r->notes, "SERVER_SOFTWARE", SERVER_VERSION);
#endif
	
#ifdef CSA_DEBUG
	dbg = csa_debug_start();
	csa_debug_register_cleanup(r->pool, dbg);
#endif

	/* allocate the CSacek request struct */
	p = (csa_params_t *) ap_palloc(r->pool, sizeof(csa_params_t));

	/* init CSacek */
	csa_result = csa_init_params(p, r->pool, (void *)r, cfg, dbg);
	if (csa_result != CSA_OK) {
		if (csa_result > CSA_OK
#ifndef CSA_USE_APACHE11_API
		&& csa_result < HTTP_CONTINUE
#else  /* CSA_USE_APACHE11_API */
		&& csa_result < HTTP_OK
#endif /* !CSA_USE_APACHE11_API */
		   ) {
			r->handler = CSA_MAGIC_TYPE;
			r->content_type = "text/html";
			if (csa_result != CSA_WHICHCODE) {
#ifdef CSA_USE_APACHE13_API
				ap_table_setn(r->notes, "CSACEK", (void *)p);
#else
				csactx__.p = p;
#endif
				return OK; /* disable any other fixers */
			}
		}
		else {
			if (csa_result < CSA_OK)
				csa_result = HTTP_INTERNAL_SERVER_ERROR;

			if (CSA_SEND_HEADERS(p))
				csa_send_headersout(p);
			return csa_result;
		}
	}

	if (CSA_ISSET(cfg->flags, CSA_CFG_RECODEINPUT) && r->args) {
		/* r->args has to be set to new (recoded) QUERY_STRING */
		qs = csa_getvar(p, "QUERY_STRING");
		if (qs) r->args = ap_pstrdup(r->pool, qs->value);
	}

	/* "upgrade" request to HTTP/1.0 if it has been done as HTTP/0.9   */
	/* in order to get all headers from sub-request - CSacek will take */
	/* care to not send headers to client */
	/* XXX if the request is HTTP/1.1 and not GET, downgrade it to
	 * HTTP/1.0 to prevent Apache core using the 100 Continue status */
	if (p->protocol <= 9
	    || (p->protocol >= 11 && csa_n_strcmp(r->method, "GET") != 0)) {
		r->proto_num = HTTP_VERSION(1, 0);
		r->protocol  = ap_pstrdup(r->pool, "HTTP/1.0");
		r->assbackwards = 0;
		p->req_protocol = 10;
	}

	/* change input headers */
	hh = csa_make_headersin(p);
	ap_clear_table(r->headers_in);
	for(; hh; hh = hh->prev) {
	    /* LINTED Apache 1.1 & 1.2 don't use const in prototype */
	    ap_table_addn(r->headers_in, hh->key.value, hh->value.value);
	}
	
	/*
	 * Redirect output (and input, if needed ) of the handler
	 * to a file, so CSacek would be able to process it later
	 * XXX the writing to a file should be eliminated somehow
	 *
	 * if the input is form data and recodeinput is on, download
	 * input from client and decode it to server's default charset
	 *
	 * in case of APACHE_SSL, I need to download all the input from
	 * client, because I cannot use SSL for subrequest;
	 * under MS Windoze, it's necessary to get all the data as well,
	 * because we can't mix file descriptor and socket in one BUFF
	 * structure - it's too bad MS Windoze treat file descriptor and
	 * and socket as two different things
	 */

	ct = ap_table_get(r->headers_in, "Content-Type");
	recodeinput = (CSA_ISSET(cfg->flags, CSA_CFG_RECODEINPUT) && ct &&
		strncasecmp(ct, CSA_CT_FORMDATA, strlen(CSA_CT_FORMDATA))==0);

#ifndef CSA_FORCE_PROCESS_INPUT
	process_input = recodeinput;
#else
# ifdef EAPI
	if (!ap_ctx_get(r->connection->client->ctx, "ssl"))
		process_input = recodeinput;
	else
# endif
		process_input = (csa_n_strcmp(r->method, "GET") != 0);
#endif

	/*
	 * If necessary, suck all incoming data, recode it if needed,
	 * and put it into a file so that we would be able to pass
	 * descriptor via which it's possible to read the data later.
	 */
	if (process_input) {
	    FILE *fp;
	    size_t final_length=0, len;
	    const char *lenp = ap_table_get(r->headers_in, "Content-Length");
	    int to_read = (lenp) ? atoi(lenp) : 0;
#ifndef CSA_USE_APACHE11_API
	    char buf[2048];
	    int retval;
#else /* CSA_USE_APACHE11_API */

	    if (!lenp || !to_read) {
		ap_log_reason("POST or PUT without Content-length:", r->uri, r);
		return HTTP_INTERNAL_SERVER_ERROR;
	    }
#endif /* !CSA_USE_APACHE11_API */

	    ap_block_alarms();
	    fp = tmpfile();
	    if (fp) {
#ifdef __MSWIN__
		/* braindead MS Windoze aren't able to make a unlinked file */
		/* which would go away as soon as the file descriptor would */
		/* be closed; explicit routine for removing temporary files */
		/* has to be called */
		//XXXap_register_cleanup(r->pool, NULL, _rmtmp, NULL);
#else
		ap_note_cleanups_for_file(r->pool, fp);
#endif
	    }
	    ap_unblock_alarms();

	    if (!fp) {
		ap_log_reason("tmpfile() failed", r->uri, r);
		return HTTP_INTERNAL_SERVER_ERROR;
	    }

#ifndef CSA_USE_APACHE11_API
	    retval = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
	    if (retval != OK) return retval;

	    if (!ap_should_client_block(r)) {
		use_oldcl = 1;
		goto after_client_block_handling;
	    }

#endif /* !CSA_USE_APACHE11_API */

	    if (recodeinput) {
		char *temp;
		size_t total_input_len=0, idx;
		csa_String str;
#ifndef CSA_USE_APACHE11_API
		csa_queue_t *q, *tmpq, *startq=NULL;
#endif

#ifdef CSA_USE_APACHE11_API
		temp = (char *) ap_palloc(p->pool_tmp, to_read);
		idx = 0;
		while( (len = read_client_block(r, &temp[idx], to_read)))
		{
		    idx += len;
		    total_input_len += len;
		    to_read -= len;
		}
#else /* !CSA_USE_APACHE11_API */
		if (to_read >0) {
		    temp = (char *) ap_palloc(p->pool_tmp, to_read);
		    idx = 0;
		    while((len=ap_get_client_block(r,&temp[idx],to_read))>0)
		    {
			idx += len;
			total_input_len += len;
			to_read -= len;
		    }
		}
		else {
		    /* unknown input data length */
		    while((len = ap_get_client_block(r, buf, sizeof(buf)))>0)
		    {
			tmpq = ap_palloc(p->pool_tmp, sizeof(csa_queue_t));
			if (!startq) startq = q = tmpq;
			else q->next = tmpq, q = q->next;
			q->next = NULL;
			q->value = ap_palloc(p->pool_tmp, (int) len);
			memcpy(q->value, buf, len);
			q->len = len;
			total_input_len += len;
		    }
		
		    if (startq && !startq->next) {
			temp = startq->value;
		    }
		    else {
			temp = (char *) ap_palloc(p->pool_tmp,
						(int)total_input_len);
			idx = 0;
			q = startq;
			for(; q; idx += q->len, q = q->next)
			      memcpy(&temp[idx], q->value, q->len);
		    }
		} /* unknown input data len */
#endif /* !CSA_USE_APACHE11_API */

		/* decode input and store it to a file, so sub-request */
		/* would be able to read it normally by using descriptor */
		csa_decodequery(&str, p, temp, total_input_len);
		fwrite(str.value, str.len, 1, fp);

		/* length of final input after recoding */
		final_length = str.len;
	    }
#ifdef CSA_FORCE_PROCESS_INPUT
	    else {
#ifdef CSA_USE_APACHE11_API
		final_length = to_read;
   
		while( (len = read_client_block(r, buf,
			(to_read > sizeof(buf))?sizeof(buf):to_read)) )
		{
		    fwrite(buf, 1, len, fp);
		    to_read -= len;
		}
#else /* !CSA_USE_APACHE11_API */
		while( (len = ap_get_client_block(r, buf, sizeof(buf))) )
		{
		    fwrite(buf, 1, len, fp);
		    final_length += len;
		}
#endif /* CSA_USE_APACHE11_API */
	    } /* if (recodeinput) */
#endif /* CSA_FORCE_RECODEINPUT */
			
	    rewind(fp);

#ifndef CSA_USE_APACHE11_API
	    /* set up these variables as if no data have been read */
	    r->remaining = final_length;
	    r->read_length = 0;

	    r->read_chunked = 0;
#endif /* !CSA_USE_APACHE11_API */

	    fd_in = fileno(fp);
	} /* if (process_input) */
	else {
		use_oldcl = 1;
	}
#ifndef CSA_USE_APACHE11_API
    after_client_block_handling:
#endif

	newcl = ap_bcreate(r->pool, B_RD|B_WR);
#ifdef __MSWIN__
	/* hello, braindead MS Windoze, making difference between */
	/* socket and file descriptor */
	CSA_UNSET(newcl->flags, B_SOCKET);
#endif

	/* make temporary file to store handler's result */
	ap_block_alarms();
	tmpfp = tmpfile();
	if (!tmpfp) {
		ap_log_reason("tmpfile() failed", r->uri, r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}
#ifdef __MSWIN__
	/* braindead MS Windoze aren't able to make a unlinked file */
	/* which would go away as soon as the file descriptor would */
	/* be closed; explicit routine for removing temporary files*/
	/* has to be called */
	//XXXap_register_cleanup(r->pool, NULL, _rmtmp, NULL);
#else
	ap_note_cleanups_for_file(r->pool, tmpfp);
#endif
	ap_unblock_alarms();

	/* we didn't read the input, so have to use old buffer */
	/* to prevent data loss */
	if (use_oldcl) {
		newcl->inbase = oldcl->inbase;
		newcl->inptr  = oldcl->inptr;
		newcl->incnt  = oldcl->incnt;
#if defined(CSA_USE_APACHE13_API) && defined(B_SFIO)
		newcl->sf_in  = oldcl->sf_in;
#endif
		fd_in = oldcl->fd_in;
	}
	
	/* set up decriptors for subrequest */
	ap_bpushfd(newcl, fd_in, fileno(tmpfp));

	/* redirect output/input for request handler */
	r->connection->client = newcl;

	/* store needed pointers for later use */
#ifdef CSA_USE_APACHE13_API
	csactx = (csa_ap_ctx_t *)ap_palloc(r->pool, sizeof(csa_ap_ctx_t));
#else
	csactx = &csactx__;
#endif

	/* Set context variables */
	csactx->p = p;
	csactx->oldcl = oldcl;
	csactx->tmpfp = tmpfp;

#ifdef CSA_USE_APACHE13_API
	ap_table_setn(r->notes, "CSACEK", (void *) csactx);
#else /* !Apache1.3 API */
	ap_table_setn(r->notes, "CSACEK", "yes");
#endif
	
#ifdef EAPI
	/* For EAPI, also put the context to subprocess_env - this is the
	 * only table retained when making subrequest and we need
	 * the context in case that ssl is used for this request.
	 *
	 * The hack with foobar is needed so that we hand out
	 * something what looks like a regular string so that users
	 * of subprocess_env won't SIGSEGV trying to copy string from
	 * memory pointed to by csactx. Hehe, long live C :)
	 */
	if (ap_ctx_get(csactx->oldcl->ctx, "ssl")) {
		strcpy(csactx->foobar, "yes");
		ap_table_setn(r->subprocess_env,
			"CSACEK_WITH_MODSSL", (void *)csactx);
	}
#endif
		
	return DECLINED;
}

/*
 * this is run when output from csa_whichcode() or csa_info() need
 * to be send to client -- "normal" request processing is bypassed
 */
static int
x_csa_handler(request_rec *r)
{
	const char *templatename = ap_table_get(r->notes, "csacek_whichcode");
	if (templatename) {
		/* make a sub-request to take care of symlinks and such */
		request_rec *subr;

#ifndef CSA_USE_APACHE11_API
		subr = ap_sub_req_lookup_file(templatename, r);
#else
		/* Apache 1.1 defined sub_req_lookup_file() as taking */
		/* (char *) instead of (const char *) in Apache 1.2+  */
		subr = sub_req_lookup_file((char *)templatename, r);
#endif
		subr->assbackwards = 0;
		ap_run_sub_req(subr);
	}
	else {
		csa_params_t *p;

#ifndef CSA_USE_APACHE13_API
		p = csactx__.p;
#else
		/* LINTED we really want strip const off returned value */
		p = (csa_params_t *) ap_table_get(r->notes, "CSACEK");
		/* switch CSacek off so that no confusion would occur in
		 * x_csa_run() */
		ap_table_unset(r->notes, "CSACEK");
#endif

		csa_output(p);
	}

	return OK;
}

/*
 * this actually processes the request's output and writes it to the client
 */
static int
x_csa_run(request_rec *r)
{
	FILE *tmpfp;
	csa_params_t *p;
	const void *csacek;
	const csa_ap_ctx_t *ctx;

	/* do nothing for subrequest */
	if (!ap_is_initial_req(r) || !(csacek=ap_table_get(r->notes,"CSACEK"))
		)
		return DECLINED;

#ifndef CSA_USE_APACHE13_API
	ctx = &csactx__;
#else
	ctx = (const csa_ap_ctx_t *) csacek;
#endif

#ifdef EAPI
	/* If request has original client pointer, mod_ssl's auth checking
	 * routine errorred out - don't do anything else then. 
	 */
	if (r->connection->client == ctx->oldcl)
		return DECLINED;
#endif

	/* flush buffers */
	ap_bflush(r->connection->client);

	/* restore values stored in x_csa_fixup() */
	tmpfp = ctx->tmpfp;
	r->connection->client = ctx->oldcl;
	p = ctx->p;

	/* reposition file access offset to beginning of file;  note */
	/* rewind(3) is not needed, as the file has been accessed    */
	/* by write(2) exclusively */
	/* LINTED */ /* on NetBSD, 2nd arg is off_t, which is long long */
	lseek(fileno(tmpfp), 0, SEEK_SET);

	/* set response stream */
	csa_set_fio(p, &(p->resp), 0, tmpfp, fileno(tmpfp));

	/* clear old cruft set by sub-request */
	ap_clear_table(r->headers_out);
	ap_clear_table(r->err_headers_out);
	r->content_encoding = NULL;
#ifndef CSA_USE_APACHE11_API
	r->chunked = 0;
#endif

	/* process headers returned by handler */
	/* XXX Note that we don't handle CSA_CONTINUE, but Apache core should
	 * never send 100 Continue to CSacek in present state of things
	 * anyway */
	if (csa_process_headers(p) != CSA_OK) {
		ap_log_reason("C-SaCzech: error while processing sub-request's headers", r->uri, r);
		return HTTP_INTERNAL_SERVER_ERROR;
	}

	/* XXX set request protocol back to HTTP/1.1 if needed. See
	 * x_csa_fixup() why this dance is necessary. */
	if (p->protocol >= 11 && p->req_protocol == 10) {
		r->proto_num = HTTP_VERSION(1, 1);
		r->protocol = ap_pstrdup(r->pool, "HTTP/1.1");
	}

	/* process data */
	if (CSA_SHOULD_DIRECT_FORWARD(p)) {
		/* avoid unnecessary memory caching if the result won't */
		/* be changed by CSacek and Content-Length is known */
		csa_direct_forward(p);
	}
	else {
		(void ) csa_process_body(p);
		csa_output(p);
	}

#ifdef CSA_USE_APACHE13_API
	/* since we are called after "normal" processing is done, we
	 * have to call ap_finalize_request_protocol() explicitely */
	ap_finalize_request_protocol(r);
#endif

	/* flush buffers */
	ap_bflush(r->connection->client);

	return DECLINED;
}

/* CSacek commands */
static command_rec csa_commands[] = {
{ "csacekBarDef",
	x_csa_setvalue, (void *)CSA_BARDEF, OR_ALL, TAKE1,
	"specification of BAR -- behaves exactly as BARDEF command" },
{ "csacekChangeURL",
	x_csa_flaghandler, (void *)CSA_CFG_CHANGEURL, OR_ALL, FLAG,
	"On or Off to enable (default) or disable automatic URL rewriting" },
{ "csacekCompress",
	x_csa_flaghandler, (void *)CSA_CFG_COMPRESS, OR_ALL, FLAG,
	"On or Off to enable (default) or disable compression" },
{ "csacekDefaultCharset",
	x_csa_setvalue, (void *)CSA_DEFCHARSET, OR_ALL, TAKE1,
	"default server charset" },
{ "csacekDefaultPartname",
	x_csa_setvalue, (void *)CSA_PARTNAME, OR_ALL, TAKE1,
	"PARTname when no part is explicitly specified (default - cs)" },
{ "csacekEngine",
	x_csa_flaghandler, (void *)CSA_CFG_ENGINEON, OR_ALL, FLAG,
	"On or Off to enable (default) or disable CSacek module" },
{ "csacekIgnorePrefix",
	x_csa_setvalue, (void *)CSA_IPREFIX, RSRC_CONF, TAKE1,
	"this prefix of URL will be ignored by CSacek (default - /cgi-bin)" },
{ "csacekImplicitWork",
	x_csa_flaghandler, (void *)CSA_CFG_IMPLICITWORK, OR_ALL, FLAG,
	"On or Off to enable (default) or disable implicit CSacek working" },
{ "csacekRecodeInput",
	x_csa_flaghandler, (void *)CSA_CFG_RECODEINPUT, OR_ALL, FLAG,
	"On or Off to enable (default) or disable recoding of input form data to server encoding" },
{ "csacekServers",
	x_csa_addservers, NULL, RSRC_CONF, RAW_ARGS,
	"syntax: server[:port] [...]" },
{ "csacekServer",
	x_csa_addserver_deprec, NULL, OR_ALL, RAW_ARGS,
	"(deprecated, use csacekServers)" },
{ "csacekTemplateDir",
	x_csa_setvalue, (void *)CSA_TEMPLATES, OR_ALL, TAKE1,
	"directory with CSacek templates" },
{ "csacekTestJS",
	x_csa_flaghandler, (void *)CSA_CFG_TESTJS, OR_ALL, FLAG,
	"On or Off to enable or disable (default) test of presented text/html to find out if document is actually JavaScript" },
{ NULL, NULL, NULL, 0, 0, NULL }
};

/* CSacek handlers */
static handler_rec csa_handlers[] =
{
  { CSA_MAGIC_TYPE, x_csa_handler },
  { NULL, NULL },
};
  
/* pretend that following code was in mod_csacek.c - to correctly set */
/* module source name in the structure */
#line 2 "mod_csacek.c"

module csacek_module = {
   STANDARD_MODULE_STUFF,
   x_csa_init,			/* initializer */
   csa_create_conf,		/* create per-directory config structure */
   csa_merge_conf,		/* merge per-directory config structures */
   NULL,			/* create per-server config structure */
   NULL,			/* merge per-server config structures */
   csa_commands,		/* command table */

   /*
    * for Apache 1.2.X, the order is:
    * [2] [9] [5] [3] [4] [1] [7] .. [8]
    */
   csa_handlers,		/* list of handlers			*/
   x_csa_rewrite,		/* [2] filename-to-URI translation	*/
   NULL,			/* [3] check/validate HTTP user_id	*/
   NULL,			/* [4] check HTTP user_id is _ok_ here	*/
#ifdef EAPI
   csa_sslhandle_hook,		/* [5] check access by host address	*/ 
#else
   NULL,			/* [5] check access by host address	*/
#endif
   NULL,			/* [6] MIME type checker/setter		*/
   x_csa_fixup,			/* [7] fixups				*/
   x_csa_run,			/* [8] logger				*/
#ifdef CSA_USE_APACHE13_API 
   NULL,			/* [9] header parser			*/
   x_csa_initchild,		/* [10] child init			*/
   x_csa_exitchild,		/* [11] child exit			*/
   NULL,			/* [1] post read-request		*/
#endif /* CSA_USE_APACHE13_API */

#ifdef EAPI
   /* Extended API (forced to be enabled with mod_ssl) */

   csa_eapi_addmodule,		/* after modules was added to core	*/
   csa_eapi_removemodule,	/* before module is removed from core	*/
   NULL,			/* configuration command rewriting	*/
   csa_eapi_newconnection,	/* socket connection open		*/
   csa_eapi_closeconnection,	/* socket connection close		*/
#endif /* EAPI */   
};