1 /*
2  *  Copyright (C) 2004-2008 Christos Tsantilas
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  *  MA  02110-1301  USA.
18  */
19 
20 #include "common.h"
21 #include "c-icap.h"
22 #include <errno.h>
23 #include <ctype.h>
24 #include <time.h>
25 #include <assert.h>
26 #ifdef _NOTUSED
27 #include <sys/ioctl.h>
28 #endif
29 
30 #include "debug.h"
31 #include "request.h"
32 #include "service.h"
33 #include "access.h"
34 #include "util.h"
35 #include "simple_api.h"
36 #include "cfg_param.h"
37 #include "stats.h"
38 #include "body.h"
39 
40 
41 extern int TIMEOUT;
42 extern int KEEPALIVE_TIMEOUT;
43 extern const char *DEFAULT_SERVICE;
44 extern int PIPELINING;
45 extern int CHECK_FOR_BUGGY_CLIENT;
46 extern int ALLOW204_AS_200OK_ZERO_ENCAPS;
47 extern int FAKE_ALLOW204;
48 
49 /*This variable defined in mpm_server.c and become 1 when the child must
50   halt imediatelly:*/
51 extern int CHILD_HALT;
52 
53 #define FORBITTEN_STR "ICAP/1.0 403 Forbidden\r\n\r\n"
54 /*#define ISTAG         "\"5BDEEEA9-12E4-2\""*/
55 
56 static int STAT_REQUESTS = -1;
57 static int STAT_FAILED_REQUESTS = -1;
58 static int STAT_BYTES_IN = -1;
59 static int STAT_BYTES_OUT = -1;
60 static int STAT_HTTP_BYTES_IN = -1;
61 static int STAT_HTTP_BYTES_OUT = -1;
62 static int STAT_BODY_BYTES_IN = -1;
63 static int STAT_BODY_BYTES_OUT = -1;
64 static int STAT_REQMODS = -1;
65 static int STAT_RESPMODS = -1;
66 static int STAT_OPTIONS = -1;
67 static int STAT_ALLOW204 = -1;
68 
request_stats_init()69 void request_stats_init()
70 {
71     STAT_REQUESTS = ci_stat_entry_register("REQUESTS", STAT_INT64_T, "General");
72     STAT_REQMODS = ci_stat_entry_register("REQMODS", STAT_INT64_T, "General");
73     STAT_RESPMODS = ci_stat_entry_register("RESPMODS", STAT_INT64_T, "General");
74     STAT_OPTIONS = ci_stat_entry_register("OPTIONS", STAT_INT64_T, "General");
75     STAT_FAILED_REQUESTS = ci_stat_entry_register("FAILED REQUESTS", STAT_INT64_T, "General");
76     STAT_ALLOW204 = ci_stat_entry_register("ALLOW 204", STAT_INT64_T, "General");
77     STAT_BYTES_IN = ci_stat_entry_register("BYTES IN", STAT_KBS_T, "General");
78     STAT_BYTES_OUT = ci_stat_entry_register("BYTES OUT", STAT_KBS_T, "General");
79     STAT_HTTP_BYTES_IN = ci_stat_entry_register("HTTP BYTES IN", STAT_KBS_T, "General");
80     STAT_HTTP_BYTES_OUT = ci_stat_entry_register("HTTP BYTES OUT", STAT_KBS_T, "General");
81     STAT_BODY_BYTES_IN = ci_stat_entry_register("BODY BYTES IN", STAT_KBS_T, "General");
82     STAT_BODY_BYTES_OUT = ci_stat_entry_register("BODY BYTES OUT", STAT_KBS_T, "General");
83 }
84 
wait_for_data(ci_connection_t * conn,int secs,int what_wait)85 static int wait_for_data(ci_connection_t *conn, int secs, int what_wait)
86 {
87     int wait_status;
88 
89     /*if we are going down do not wait....*/
90     if (CHILD_HALT)
91         return -1;
92 
93     do {
94         wait_status = ci_connection_wait(conn, secs, what_wait);
95         if (wait_status < 0)
96             return -1;
97         if (wait_status == 0 && CHILD_HALT) /*abort*/
98             return -1;
99     } while (wait_status & ci_wait_should_retry);
100 
101     if (wait_status == 0) /* timeout */
102         return -1;
103 
104     return wait_status;
105 }
106 
newrequest(ci_connection_t * connection)107 ci_request_t *newrequest(ci_connection_t * connection)
108 {
109     ci_request_t *req;
110     int access;
111     int len;
112     ci_connection_t *conn;
113 
114     conn = (ci_connection_t *) malloc(sizeof(ci_connection_t));
115     assert(conn);
116     ci_copy_connection(conn, connection);
117     req = ci_request_alloc(conn);
118 
119     if ((access = access_check_client(req)) == CI_ACCESS_DENY) { /*Check for client access */
120         len = strlen(FORBITTEN_STR);
121         ci_connection_write(connection, FORBITTEN_STR, len, TIMEOUT);
122         ci_request_destroy(req);
123         return NULL;          /*Or something that means authentication error */
124     }
125 
126 
127     req->access_type = access;
128     return req;
129 }
130 
131 
recycle_request(ci_request_t * req,ci_connection_t * connection)132 int recycle_request(ci_request_t * req, ci_connection_t * connection)
133 {
134     int access;
135     int len;
136 
137     ci_request_reset(req);
138     ci_copy_connection(req->connection, connection);
139 
140     if ((access = access_check_client(req)) == CI_ACCESS_DENY) { /*Check for client access */
141         len = strlen(FORBITTEN_STR);
142         ci_connection_write(connection, FORBITTEN_STR, len, TIMEOUT);
143         return 0;             /*Or something that means authentication error */
144     }
145     req->access_type = access;
146     return 1;
147 }
148 
keepalive_request(ci_request_t * req)149 int keepalive_request(ci_request_t *req)
150 {
151     /* Preserve extra read bytes*/
152     char *pstrblock = req->pstrblock_read;
153     int pstrblock_len = req->pstrblock_read_len;
154     // Just reset without change or free memory
155     ci_request_reset(req);
156     if (PIPELINING) {
157         req->pstrblock_read = pstrblock;
158         req->pstrblock_read_len = pstrblock_len;
159     }
160 
161     if (req->pstrblock_read && req->pstrblock_read_len > 0)
162         return 1;
163     return wait_for_data(req->connection, KEEPALIVE_TIMEOUT, ci_wait_for_read);
164 }
165 
166 /*Here we want to read in small blocks icap header becouse in most cases
167  it will not bigger than 512-1024 bytes.
168  So we are going to do small reads and small increments in icap headers size,
169  to save some space and keep small the number of over-read bytes
170 */
171 #define ICAP_HEADER_READSIZE 512
172 
173 /*this function check if there is enough space in buffer buf ....*/
icap_header_check_realloc(char ** buf,int * size,int used,int mustadded)174 static int icap_header_check_realloc(char **buf, int *size, int used, int mustadded)
175 {
176     char *newbuf;
177     int len;
178     if (*size - used < mustadded) {
179         len = *size + ICAP_HEADER_READSIZE;
180         newbuf = realloc(*buf, len);
181         if (!newbuf) {
182             return EC_500;
183         }
184         *buf = newbuf;
185         *size = *size + ICAP_HEADER_READSIZE;
186     }
187     return EC_100;
188 }
189 
190 
ci_read_icap_header(ci_request_t * req,ci_headers_list_t * h,int timeout)191 static int ci_read_icap_header(ci_request_t * req, ci_headers_list_t * h, int timeout)
192 {
193     int bytes, request_status = EC_100, i, eoh = 0, startsearch = 0, readed = 0;
194     int wait_status = 0;
195     char *buf_end;
196     int dataPrefetch = 0;
197 
198     buf_end = h->buf;
199     readed = 0;
200     bytes = 0;
201 
202     if (PIPELINING && req->pstrblock_read && req->pstrblock_read_len > 0) {
203         if ((request_status =
204                     icap_header_check_realloc(&(h->buf), &(h->bufsize), req->pstrblock_read_len,
205                                               ICAP_HEADER_READSIZE)) != EC_100)
206             return request_status;
207         memmove(h->buf, req->pstrblock_read, req->pstrblock_read_len);
208         readed = req->pstrblock_read_len;
209         buf_end = h->buf;
210         bytes = readed;
211         dataPrefetch = 1;
212         req->pstrblock_read = NULL;
213         req->pstrblock_read_len = 0;
214         ci_debug_printf(5, "Get data from previous request read.\n");
215     }
216 
217     do {
218 
219         if (!dataPrefetch) {
220             if ((wait_status = wait_for_data(req->connection, timeout, ci_wait_for_read)) < 0)
221                 return EC_408;
222 
223             bytes = ci_connection_read_nonblock(req->connection, buf_end, ICAP_HEADER_READSIZE);
224             if (bytes < 0)
225                 return EC_408;
226 
227             if (bytes == 0) /*NOP? should retry?*/
228                 continue;
229 
230             readed += bytes;
231             req->bytes_in += bytes;
232         } else
233             dataPrefetch = 0;
234 
235         for (i = startsearch; i < bytes - 3; i++) {   /*search for end of header.... */
236             if (strncmp(buf_end + i, "\r\n\r\n", 4) == 0) {
237                 buf_end = buf_end + i + 2;
238                 eoh = 1;
239                 break;
240             }
241         }
242         if (eoh)
243             break;
244 
245         if ((request_status =
246                     icap_header_check_realloc(&(h->buf), &(h->bufsize), readed,
247                                               ICAP_HEADER_READSIZE)) != EC_100)
248             break;
249         buf_end = h->buf + readed;
250         if (startsearch > -3)
251             startsearch = (readed > 3 ? -3 : -readed);       /*Including the last 3 char ellements ....... */
252     } while (1);
253 
254     h->bufused = buf_end - h->buf;     /* -1 ; */
255     req->pstrblock_read = buf_end + 2; /*after the \r\n\r\n. We keep the first \r\n and the other dropped.... */
256     req->pstrblock_read_len = readed - h->bufused - 2; /*the 2 of the 4 characters \r\n\r\n and the '\0' character */
257     req->request_bytes_in = h->bufused + 2; /*This is include the "\r\n\r\n" sequence*/
258     return request_status;
259 }
260 
read_encaps_header(ci_request_t * req,ci_headers_list_t * h,int size)261 static int read_encaps_header(ci_request_t * req, ci_headers_list_t * h, int size)
262 {
263     int bytes = 0, remains, readed = 0;
264     char *buf_end = NULL;
265 
266     if (!ci_headers_setsize(h, size + (CHECK_FOR_BUGGY_CLIENT != 0 ? 2 : 0)))
267         return EC_500;
268     buf_end = h->buf;
269 
270     if (req->pstrblock_read_len > 0) {
271         readed =
272             (size > req->pstrblock_read_len ? req->pstrblock_read_len : size);
273         memcpy(h->buf, req->pstrblock_read, readed);
274         buf_end = h->buf + readed;
275         if (size <= req->pstrblock_read_len) {        /*We have readed all this header....... */
276             req->pstrblock_read = (req->pstrblock_read) + readed;
277             req->pstrblock_read_len = (req->pstrblock_read_len) - readed;
278         } else {
279             req->pstrblock_read = NULL;
280             req->pstrblock_read_len = 0;
281         }
282     }
283 
284     remains = size - readed;
285     while (remains > 0) {
286         if (wait_for_data(req->connection, TIMEOUT, ci_wait_for_read) < 0)
287             return CI_ERROR;
288         if ((bytes = ci_connection_read_nonblock(req->connection, buf_end, remains)) < 0)
289             return CI_ERROR;
290         remains -= bytes;
291         buf_end += bytes;
292         req->bytes_in += bytes;
293     }
294 
295     h->bufused = buf_end - h->buf;     // -1 ;
296     if (strncmp(buf_end - 4, "\r\n\r\n", 4) == 0) {
297         h->bufused -= 2;      /*eat the last 2 bytes of "\r\n\r\n" */
298     } else if (CHECK_FOR_BUGGY_CLIENT && strncmp(buf_end - 2, "\r\n", 2) != 0) {
299         // Some icap clients missing the "\r\n\r\n" after end of headers
300         // when null-body is present.
301         *buf_end = '\r';
302         *(buf_end + 1) = '\n';
303         h->bufused += 2;
304     }
305     /*Currently we are counting only successfull http headers read.*/
306     req->http_bytes_in += size;
307     req->request_bytes_in += size;
308     return EC_100;
309 }
310 
get_method(char * buf,char ** end)311 static int get_method(char *buf, char **end)
312 {
313     if (!strncmp(buf, "OPTIONS", 7)) {
314         *end = buf + 7;
315         return ICAP_OPTIONS;
316     } else if (!strncmp(buf, "REQMOD", 6)) {
317         *end = buf + 6;
318         return ICAP_REQMOD;
319     } else if (!strncmp(buf, "RESPMOD", 7)) {
320         *end = buf + 7;
321         return ICAP_RESPMOD;
322     } else {
323         *end = buf;
324         return -1;
325     }
326 }
327 
parse_request(ci_request_t * req,char * buf)328 static int parse_request(ci_request_t * req, char *buf)
329 {
330     char *start, *end;
331     int servnamelen, len, args_len;
332     int vmajor, vminor;
333     ci_service_module_t *service = NULL;
334     service_alias_t *salias = NULL;
335 
336     if ((req->type = get_method(buf, &end)) < 0)
337         return EC_400;
338 
339     while (*end == ' ') end++;
340     start = end;
341 
342     if (strncasecmp(start, "icap://", 7) == 0)
343         start = start + 7;
344     else if (strncasecmp(start, "icaps://", 8) == 0)
345         start = start + 8;
346     else
347         return EC_400;
348 
349     len = strcspn(start, "/ ");
350     end = start + len;
351     servnamelen =
352         (CI_MAXHOSTNAMELEN > len ? len : CI_MAXHOSTNAMELEN);
353     memcpy(req->req_server, start, servnamelen);
354     req->req_server[servnamelen] = '\0';
355     if (*end == '/') { /*we are expecting service name*/
356         start = ++end;
357         while (*end && *end != ' ' && *end != '?')
358             end++;
359         len = end - start;
360 
361         len =
362             (len < MAX_SERVICE_NAME ? len : MAX_SERVICE_NAME);
363         if (len) {
364             strncpy(req->service, start, len);
365             req->service[len] = '\0';
366         }
367 
368         if (*end == '?') {     /*args */
369             start = ++end;
370             if ((end = strchr(start, ' ')) != NULL) {
371                 args_len = strlen(req->args);
372                 len = end - start;
373                 if (args_len && len) {
374                     req->args[args_len] = '&';
375                     args_len++;
376                 }
377                 len = (len < (MAX_SERVICE_ARGS - args_len) ?
378                        len : (MAX_SERVICE_ARGS - args_len));
379                 strncpy(req->args + args_len, start, len);
380                 req->args[args_len + len] = '\0';
381             } else
382                 return EC_400;
383         }      /*end of parsing args */
384     }
385 
386     while (*end == ' ')
387         end++;
388     start = end;
389 
390     vminor = vmajor = -1;
391     if (strncmp(start, "ICAP/", 5) == 0) {
392         start += 5;
393         vmajor = strtol(start, &end, 10);
394         if (vmajor > 0 && *end == '.') {
395             start = end + 1;
396             vminor = strtol(start, &end, 10);
397             if (end == start) /*no chars parsed*/
398                 vminor = -1;
399         }
400     }
401 
402     if (vminor == -1 || vmajor < 1)
403         return EC_400;
404 
405     if (req->service[0] == '\0' && DEFAULT_SERVICE) { /*No service name defined*/
406         strncpy(req->service, DEFAULT_SERVICE, MAX_SERVICE_NAME);
407     }
408 
409     if (req->service[0] != '\0') {
410         if (!(service = find_service(req->service))) { /*else search for an alias */
411             if ((salias = find_service_alias(req->service))) {
412                 service = salias->service;
413                 if (salias->args[0] != '\0')
414                     strcpy(req->args, salias->args);
415             }
416         }
417     }
418     req->current_service_mod = service;
419 
420     if (!req->current_service_mod)
421         return EC_404; /*Service not found*/
422 
423     if (!ci_method_support
424             (req->current_service_mod->mod_type, req->type)
425             && req->type != ICAP_OPTIONS) {
426         return EC_405;    /* Method not allowed for service. */
427     }
428 
429     return EC_100;
430 }
431 
check_request(ci_request_t * req)432 static int check_request(ci_request_t *req)
433 {
434     /*Check encapsulated header*/
435     if (req->entities[0] == NULL && req->type != ICAP_OPTIONS) /*No encapsulated header*/
436         return EC_400;
437 
438     ci_debug_printf(6, "\n type:%d Entities: %d %d %d %d \n",
439                     req->type,
440                     req->entities[0] ? req->entities[0]->type : -1,
441                     req->entities[1] ? req->entities[1]->type : -1,
442                     req->entities[2] ? req->entities[2]->type : -1,
443                     req->entities[3] ? req->entities[3]->type : -1
444                    );
445     if (req->type == ICAP_REQMOD) {
446         if (req->entities[2] != NULL)
447             return EC_400;
448         else if (req->entities[1] != NULL) {
449             if (req->entities[0]->type != ICAP_REQ_HDR)
450                 return EC_400;
451             if (req->entities[1]->type != ICAP_REQ_BODY && req->entities[1]->type != ICAP_NULL_BODY)
452                 return EC_400;
453         } else {
454             /*If it has only one encapsulated object it must be body data*/
455             if (req->entities[0]->type != ICAP_REQ_BODY)
456                 return EC_400;
457 
458         }
459     } else if (req->type == ICAP_RESPMOD) {
460         if (req->entities[3] != NULL)
461             return EC_400;
462         else if (req->entities[2] != NULL) {
463             assert(req->entities[0]);
464             assert(req->entities[1]);
465             if (req->entities[0]->type != ICAP_REQ_HDR)
466                 return EC_400;
467             if (req->entities[1]->type != ICAP_RES_HDR)
468                 return EC_400;
469             if (req->entities[2]->type != ICAP_RES_BODY && req->entities[2]->type != ICAP_NULL_BODY)
470                 return EC_400;
471         } else if (req->entities[1] != NULL) {
472             if (req->entities[0]->type != ICAP_RES_HDR && req->entities[0]->type != ICAP_REQ_HDR)
473                 return EC_400;
474             if (req->entities[1]->type != ICAP_RES_BODY && req->entities[1]->type != ICAP_NULL_BODY)
475                 return EC_400;
476         } else {
477             /*If it has only one encapsulated object it must be body data*/
478             if (req->entities[0]->type != ICAP_RES_BODY)
479                 return EC_400;
480         }
481     }
482     return EC_100;
483 }
484 
parse_header(ci_request_t * req)485 static int parse_header(ci_request_t * req)
486 {
487     int i, request_status = EC_100, result;
488     ci_headers_list_t *h;
489     char *val;
490 
491     h = req->request_header;
492     if ((request_status = ci_read_icap_header(req, h, TIMEOUT)) != EC_100)
493         return request_status;
494 
495     if ((request_status = ci_headers_unpack(h)) != EC_100)
496         return request_status;
497 
498     if ((request_status = parse_request(req, h->headers[0])) != EC_100)
499         return request_status;
500 
501     for (i = 1; i < h->used && request_status == EC_100; i++) {
502         if (strncasecmp("Preview:", h->headers[i], 8) == 0) {
503             val = h->headers[i] + 8;
504             for (; isspace(*val) && *val != '\0'; ++val);
505             errno = 0;
506             result = strtol(val, NULL, 10);
507             if (errno != EINVAL && errno != ERANGE) {
508                 req->preview = result;
509                 if (result >= 0)
510                     ci_buf_reset_size(&(req->preview_data), result + 64);
511             }
512         } else if (strncasecmp("Encapsulated:", h->headers[i], 13) == 0)
513             request_status = process_encapsulated(req, h->headers[i]);
514         else if (strncasecmp("Connection:", h->headers[i], 11) == 0) {
515             val = h->headers[i] + 11;
516             for (; isspace(*val) && *val != '\0'; ++val);
517             /*             if(strncasecmp(val,"keep-alive",10)==0)*/
518             if (strncasecmp(val, "close", 5) == 0)
519                 req->keepalive = 0;
520             /*else the default behaviour of keepalive ..... */
521         } else if (strncasecmp("Allow:", h->headers[i], 6) == 0) {
522             if (strstr(h->headers[i]+6, "204"))
523                 req->allow204 = 1;
524             if (strstr(h->headers[i]+6, "206"))
525                 req->allow206 = 1;
526         }
527     }
528 
529     if (request_status != EC_100)
530         return request_status;
531 
532     return check_request(req);
533 }
534 
535 
parse_encaps_headers(ci_request_t * req)536 static int parse_encaps_headers(ci_request_t * req)
537 {
538     int size, i, request_status = 0;
539     ci_encaps_entity_t *e = NULL;
540     for (i = 0; (e = req->entities[i]) != NULL; i++) {
541         if (e->type > ICAP_RES_HDR)   //res_body,req_body or opt_body so the end of the headers.....process_encapsulated
542             return EC_100;
543 
544         if (req->entities[i + 1] == NULL)
545             return EC_400;
546 
547         size = req->entities[i + 1]->start - e->start;
548 
549         if ((request_status =
550                     read_encaps_header(req, (ci_headers_list_t *) e->entity,
551                                        size)) != EC_100)
552             return request_status;
553 
554         if ((request_status =
555                     ci_headers_unpack((ci_headers_list_t *) e->entity)) != EC_100)
556             return request_status;
557     }
558     return EC_100;
559 }
560 
561 /*
562   In read_preview_data I must check if readed data are more than
563   those client said in preview header
564 */
read_preview_data(ci_request_t * req)565 static int read_preview_data(ci_request_t * req)
566 {
567     int ret;
568     char *wdata;
569 
570     req->current_chunk_len = 0;
571     req->chunk_bytes_read = 0;
572     req->write_to_module_pending = 0;
573 
574     if (req->pstrblock_read_len == 0) {
575         if (wait_for_data(req->connection, TIMEOUT, ci_wait_for_read) < 0)
576             return CI_ERROR;
577 
578         if (net_data_read(req) == CI_ERROR)
579             return CI_ERROR;
580     }
581 
582     do {
583         do {
584             if ((ret = parse_chunk_data(req, &wdata)) == CI_ERROR) {
585                 ci_debug_printf(1,
586                                 "Error parsing chunks, current chunk len: %d readed:%d, str:%s\n",
587                                 req->current_chunk_len,
588                                 req->chunk_bytes_read, req->pstrblock_read);
589                 return CI_ERROR;
590             }
591             if (ci_buf_write
592                     (&(req->preview_data), wdata,
593                      req->write_to_module_pending) < 0)
594                 return CI_ERROR;
595             req->write_to_module_pending = 0;
596 
597             if (ret == CI_EOF) {
598                 req->pstrblock_read = NULL;
599                 req->pstrblock_read_len = 0;
600                 if (req->eof_received)
601                     return CI_EOF;
602                 return CI_OK;
603             }
604         } while (ret != CI_NEEDS_MORE);
605 
606         if (wait_for_data(req->connection, TIMEOUT, ci_wait_for_read) < 0)
607             return CI_ERROR;
608         if (net_data_read(req) == CI_ERROR)
609             return CI_ERROR;
610     } while (1);
611 
612     return CI_ERROR;
613 }
614 
ec_responce_simple(ci_request_t * req,int ec)615 static void ec_responce_simple(ci_request_t * req, int ec)
616 {
617     char buf[256];
618     int len;
619     snprintf(buf, 256, "ICAP/1.0 %d %s\r\n\r\n",
620              ci_error_code(ec), ci_error_code_string(ec));
621     buf[255] = '\0';
622     len = strlen(buf);
623     ci_connection_write(req->connection, buf, len, TIMEOUT);
624     req->bytes_out += len;
625     req->return_code = ec;
626 }
627 
ec_responce(ci_request_t * req,int ec)628 static int ec_responce(ci_request_t * req, int ec)
629 {
630     char buf[256];
631     ci_service_xdata_t *srv_xdata = NULL;
632     int len, allow204to200OK = 0;
633     if (req->current_service_mod)
634         srv_xdata = service_data(req->current_service_mod);
635     ci_headers_reset(req->response_header);
636 
637     if (ec == EC_204 && ALLOW204_AS_200OK_ZERO_ENCAPS) {
638         allow204to200OK = 1;
639         ec = EC_200;
640     }
641     snprintf(buf, 256, "ICAP/1.0 %d %s",
642              ci_error_code(ec), ci_error_code_string(ec));
643     ci_headers_add(req->response_header, buf);
644     ci_headers_add(req->response_header, "Server: C-ICAP/" VERSION);
645     if (req->keepalive)
646         ci_headers_add(req->response_header, "Connection: keep-alive");
647     else
648         ci_headers_add(req->response_header, "Connection: close");
649 
650     if (srv_xdata) {
651         ci_service_data_read_lock(srv_xdata);
652         ci_headers_add(req->response_header, srv_xdata->ISTag);
653         ci_service_data_read_unlock(srv_xdata);
654     }
655     if (!ci_headers_is_empty(req->xheaders)) {
656         ci_headers_addheaders(req->response_header, req->xheaders);
657     }
658     if (allow204to200OK) {
659         if (req->type == ICAP_REQMOD)
660             ci_headers_add(req->response_header, "Encapsulated: req-hdr=0, null-body=0");
661         else
662             ci_headers_add(req->response_header, "Encapsulated: res-hdr=0, null-body=0");
663     }
664     /*
665       TODO: Release req->entities (ci_request_release_entity())
666      */
667     ci_headers_pack(req->response_header);
668     req->return_code = ec;
669 
670     len = ci_connection_write(req->connection,
671                               req->response_header->buf, req->response_header->bufused,
672                               TIMEOUT);
673 
674     /*We are finishing sending*/
675     req->status = SEND_EOF;
676 
677     if (len < 0)
678         return -1;
679 
680     req->bytes_out += len;
681     return len;
682 }
683 
684 extern char MY_HOSTNAME[];
mk_responce_header(ci_request_t * req)685 static int mk_responce_header(ci_request_t * req)
686 {
687     ci_headers_list_t *head;
688     ci_encaps_entity_t **e_list;
689     ci_service_xdata_t *srv_xdata;
690     char buf[512];
691     srv_xdata = service_data(req->current_service_mod);
692     ci_headers_reset(req->response_header);
693     head = req->response_header;
694     assert(req->return_code >= EC_100 && req->return_code < EC_MAX);
695     snprintf(buf, 512, "ICAP/1.0 %d %s",
696              ci_error_code(req->return_code), ci_error_code_string(req->return_code));
697     ci_headers_add(head, buf);
698     ci_headers_add(head, "Server: C-ICAP/" VERSION);
699     if (req->keepalive)
700         ci_headers_add(head, "Connection: keep-alive");
701     else
702         ci_headers_add(head, "Connection: close");
703     ci_service_data_read_lock(srv_xdata);
704     ci_headers_add(head, srv_xdata->ISTag);
705     ci_service_data_read_unlock(srv_xdata);
706     if (!ci_headers_is_empty(req->xheaders)) {
707         ci_headers_addheaders(head, req->xheaders);
708     }
709 
710     e_list = req->entities;
711     if (req->type == ICAP_RESPMOD) {
712         if (e_list[0]->type == ICAP_REQ_HDR) {
713             ci_request_release_entity(req, 0);
714             e_list[0] = e_list[1];
715             e_list[1] = e_list[2];
716             e_list[2] = NULL;
717         }
718     }
719 
720     snprintf(buf, 512, "Via: ICAP/1.0 %s (C-ICAP/" VERSION " %s )",
721              MY_HOSTNAME,
722              (req->current_service_mod->mod_short_descr ? req->
723               current_service_mod->mod_short_descr : req->current_service_mod->
724               mod_name));
725     /*Here we must append it to an existsing Via header not just add a new header */
726     if (req->type == ICAP_RESPMOD) {
727         ci_http_response_add_header(req, buf);
728     } else if (req->type == ICAP_REQMOD) {
729         ci_http_request_add_header(req, buf);
730     }
731 
732     ci_response_pack(req);
733     return 1;
734 }
735 
736 
737 /****************************************************************/
738 /* New  functions to send responce */
739 
740 const char *eol_str = "\r\n";
741 const char *eof_str = "0\r\n\r\n";
742 
743 
send_current_block_data(ci_request_t * req)744 static int send_current_block_data(ci_request_t * req)
745 {
746     int bytes;
747     if (req->remain_send_block_bytes == 0)
748         return 0;
749     if ((bytes =
750                 ci_connection_write_nonblock(req->connection, req->pstrblock_responce,
751                         req->remain_send_block_bytes)) < 0) {
752         ci_debug_printf(5, "Error writing to socket (errno:%d, bytes:%d. string:\"%s\")", errno, req->remain_send_block_bytes, req->pstrblock_responce);
753         return CI_ERROR;
754     }
755 
756     /*
757          if (bytes == 0) {
758              ci_debug_printf(5, "Can not write to the client. Is the connection closed?");
759              return CI_ERROR;
760          }
761     */
762 
763     req->pstrblock_responce += bytes;
764     req->remain_send_block_bytes -= bytes;
765     req->bytes_out += bytes;
766     if (req->status >= SEND_HEAD1 &&  req->status <= SEND_HEAD3)
767         req->http_bytes_out +=bytes;
768     return req->remain_send_block_bytes;
769 }
770 
771 
format_body_chunk(ci_request_t * req)772 static int format_body_chunk(ci_request_t * req)
773 {
774     int def_bytes;
775     char *wbuf = NULL;
776     char tmpbuf[EXTRA_CHUNK_SIZE];
777 
778     if (!req->responce_hasbody)
779         return CI_EOF;
780     if (req->remain_send_block_bytes > 0) {
781         assert(req->remain_send_block_bytes <= MAX_CHUNK_SIZE);
782 
783         /*The data are not written yet but I hope there is not any problem.
784           It is difficult to compute data sent */
785         req->http_bytes_out += req->remain_send_block_bytes;
786         req->body_bytes_out += req->remain_send_block_bytes;
787 
788         wbuf = req->wbuf + EXTRA_CHUNK_SIZE + req->remain_send_block_bytes;
789         /*Put the "\r\n" sequence at the end of chunk */
790         *(wbuf++) = '\r';
791         *wbuf = '\n';
792         def_bytes =
793             snprintf(tmpbuf, EXTRA_CHUNK_SIZE, "%x\r\n",
794                      req->remain_send_block_bytes);
795         wbuf = req->wbuf + EXTRA_CHUNK_SIZE - def_bytes;      /*Copy the chunk define in the beggining of chunk ..... */
796         memcpy(wbuf, tmpbuf, def_bytes);
797         req->pstrblock_responce = wbuf;
798         req->remain_send_block_bytes += def_bytes + 2;
799     } else if (req->remain_send_block_bytes == CI_EOF) {
800         if (req->return_code == EC_206 && req->i206_use_original_body >= 0) {
801             def_bytes = sprintf(req->wbuf, "0; use-original-body=%" PRId64 "\r\n\r\n",
802                                 req->i206_use_original_body );
803             req->pstrblock_responce = req->wbuf;
804             req->remain_send_block_bytes = def_bytes;
805         } else {
806             strcpy(req->wbuf, "0\r\n\r\n");
807             req->pstrblock_responce = req->wbuf;
808             req->remain_send_block_bytes = 5;
809         }
810         return CI_EOF;
811     }
812     return CI_OK;
813 }
814 
815 
816 
resp_check_body(ci_request_t * req)817 static int resp_check_body(ci_request_t * req)
818 {
819     int i;
820     ci_encaps_entity_t **e = req->entities;
821     for (i = 0; e[i] != NULL; i++)
822         if (e[i]->type == ICAP_NULL_BODY)
823             return 0;
824     return 1;
825 }
826 
827 /*
828 The
829 if((ret=send_current_block_data(req))!=0)
830   return ret;
831 
832 must called after this function....
833 */
834 
update_send_status(ci_request_t * req)835 static int update_send_status(ci_request_t * req)
836 {
837     int i, status;
838     ci_encaps_entity_t *e;
839 
840     if (req->status == SEND_NOTHING) { //If nothing has send start sending....
841         if (!mk_responce_header(req)) {
842             ci_debug_printf(1, "Error constructing the responce headers!\n");
843             return CI_ERROR;
844         }
845         req->responce_hasbody = resp_check_body(req);
846 
847         req->pstrblock_responce = req->response_header->buf;
848         req->remain_send_block_bytes = req->response_header->bufused;
849         req->status = SEND_RESPHEAD;
850         ci_debug_printf(9, "Going to send response headers\n");
851         return CI_OK;
852     }
853 
854     if (req->status == SEND_EOF) {
855         ci_debug_printf(9, "The req->status is EOF (remain to send bytes:%d)\n",
856                         req->remain_send_block_bytes);
857         if (req->remain_send_block_bytes == 0)
858             return CI_EOF;
859         else
860             return CI_OK;
861     }
862     if (req->status == SEND_BODY) {
863         ci_debug_printf(9, "Send status is SEND_BODY return\n");
864         return CI_OK;
865     }
866 
867     if ((status = req->status) < SEND_HEAD3) {
868         status++;
869     }
870 
871     if (status > SEND_RESPHEAD && status < SEND_BODY) {        /*status is SEND_HEAD1 SEND_HEAD2 or SEND_HEAD3    */
872         i = status - SEND_HEAD1;      /*We have to send next headers block .... */
873         if ((e = req->entities[i]) != NULL
874                 && (e->type == ICAP_REQ_HDR || e->type == ICAP_RES_HDR)) {
875 
876             req->pstrblock_responce = ((ci_headers_list_t *) e->entity)->buf;
877             req->remain_send_block_bytes =
878                 ((ci_headers_list_t *) e->entity)->bufused;
879 
880             req->status = status;
881             ci_debug_printf(9, "Going to send http headers on entity :%d\n", i);
882             return CI_OK;
883         } else if (req->responce_hasbody) {   /*end of headers, going to send body now.A body always follows the res_hdr or req_hdr..... */
884             req->status = SEND_BODY;
885             return CI_OK;
886         } else {
887             req->status = SEND_EOF;
888             req->pstrblock_responce = (char *) NULL;
889             req->remain_send_block_bytes = 0;
890             return CI_EOF;
891         }
892     }
893 
894     return CI_ERROR;           /*Can not be reached (I thing)...... */
895 }
896 
mod_null_io(char * rbuf,int * rlen,char * wbuf,int * wlen,int iseof,ci_request_t * req)897 static int mod_null_io(char *rbuf, int *rlen, char *wbuf, int *wlen, int iseof,
898                        ci_request_t *req)
899 {
900     if (iseof)
901         *rlen = CI_EOF;
902     else
903         *rlen = 0;
904     return CI_OK;
905 }
906 
mod_echo_io(char * wbuf,int * wlen,char * rbuf,int * rlen,int iseof,ci_request_t * req)907 static int mod_echo_io(char *wbuf, int *wlen, char *rbuf, int *rlen, int iseof,
908                        ci_request_t *req)
909 {
910     if (!req->echo_body)
911         return CI_ERROR;
912 
913     if (rlen && rbuf) {
914         *rlen = ci_ring_buf_write(req->echo_body, rbuf, *rlen);
915         if (*rlen < 0)
916             return CI_ERROR;
917     }
918 
919     if (wbuf && wlen) {
920         *wlen = ci_ring_buf_read(req->echo_body, wbuf, *wlen);
921         if (*wlen == 0 && req->eof_received)
922             *wlen = CI_EOF;
923     }
924 
925     return CI_OK;
926 }
927 
get_send_body(ci_request_t * req,int parse_only)928 static int get_send_body(ci_request_t * req, int parse_only)
929 {
930     char *wchunkdata = NULL, *rchunkdata = NULL;
931     int ret, parse_chunk_ret, has_formated_data = 0;
932     int (*service_io) (char *rbuf, int *rlen, char *wbuf, int *wlen, int iseof,
933                        ci_request_t *);
934     int action = 0, rchunk_has_space = 0, service_eof = 0, wbytes, rbytes;
935     int lock_status;
936     int no_io;
937 
938     if (parse_only)
939         service_io = mod_null_io;
940     else if (req->echo_body)
941         service_io = mod_echo_io;
942     else
943         service_io = req->current_service_mod->mod_service_io;
944     if (!service_io)
945         return CI_ERROR;
946 
947     req->status = SEND_NOTHING;
948     /*in the case we did not have preview data and body is small maybe
949        the c-icap already read the body with the headers so do not read
950        if there are unparsed bytes in pstrblock buffer
951      */
952     if (req->pstrblock_read_len == 0)
953         action = ci_wait_for_read;
954     do {
955         if (action) {
956             ci_debug_printf(9, "Going to %s/%s data\n",
957                             (action & ci_wait_for_read ? "Read" : "-"),
958                             (action & ci_wait_for_write ? "Write" : "-")
959                            );
960             if ((ret =
961                         wait_for_data(req->connection, TIMEOUT,
962                                       action)) < 0)
963                 break;
964             if (ret & ci_wait_for_read) {
965                 if (net_data_read(req) == CI_ERROR)
966                     return CI_ERROR;
967             }
968             if (ret & ci_wait_for_write) {
969                 if (!req->data_locked && req->status == SEND_NOTHING) {
970                     update_send_status(req);
971                 }
972                 if (send_current_block_data(req) == CI_ERROR)
973                     return CI_ERROR;
974             }
975             ci_debug_printf(9,
976                             "OK done reading/writing going to process\n");
977         }
978 
979         if (!req->data_locked && req->remain_send_block_bytes == 0) {
980             if (update_send_status(req) == CI_ERROR)
981                 return CI_ERROR;
982             // if(update_send_status == CI_EOF)/*earlier responce from icap server???...*/
983         }
984 
985         /*Store lock status. If it is changed during module io, we need
986           to update send status.*/
987         lock_status = req->data_locked;
988 
989         /*In the following loop, parses the chunks from readed data
990            and try to write data to the service.
991            At the same time reads the data from module and try to fill
992            the req->wbuf
993          */
994         if (req->remain_send_block_bytes)
995             has_formated_data = 1;
996         else
997             has_formated_data = 0;
998         parse_chunk_ret = 0;
999         int repeat_module_io = 0;
1000         do {
1001             if (req->pstrblock_read_len != 0
1002                     && req->write_to_module_pending == 0) {
1003                 if ((parse_chunk_ret =
1004                             parse_chunk_data(req, &wchunkdata)) == CI_ERROR) {
1005                     ci_debug_printf(1, "Error parsing chunks!\n");
1006                     return CI_ERROR;
1007                 }
1008 
1009                 if (parse_chunk_ret == CI_EOF)
1010                     req->eof_received = 1;
1011             }
1012             if (wchunkdata && req->write_to_module_pending)
1013                 wbytes = req->write_to_module_pending;
1014             else
1015                 wbytes = 0;
1016 
1017             if (req->status == SEND_BODY && !service_eof) {
1018                 if (req->remain_send_block_bytes == 0) {
1019                     /*Leave space for chunk spec.. */
1020                     rchunkdata = req->wbuf + EXTRA_CHUNK_SIZE;
1021                     req->pstrblock_responce = rchunkdata;  /*does not needed! */
1022                 }
1023                 if ((MAX_CHUNK_SIZE - req->remain_send_block_bytes) > 0
1024                         && has_formated_data == 0) {
1025                     rbytes = MAX_CHUNK_SIZE - req->remain_send_block_bytes;
1026                 } else {
1027                     rbytes = 0;
1028                 }
1029             } else
1030                 rbytes = 0;
1031             rchunk_has_space = (rbytes > 0);
1032             if (wbytes > 0 || rbytes > 0 || parse_chunk_ret == CI_EOF) {
1033                 ci_debug_printf(9, "get send body: going to write/read: %d/%d bytes\n", wbytes, rbytes);
1034                 if ((*service_io)(rchunkdata, &rbytes, wchunkdata, &wbytes, req->eof_received, req) == CI_ERROR)
1035                     return CI_ERROR;
1036                 ci_debug_printf(9, "get send body: written/read: %d/%d bytes (eof: %d)\n", wbytes, rbytes, req->eof_received);
1037             }
1038             no_io = (rbytes <= 0 && wbytes <= 0);
1039             if (wbytes > 0) {
1040                 wchunkdata += wbytes;
1041                 req->write_to_module_pending -= wbytes;
1042             } else if (wbytes < 0){
1043                 ci_debug_printf(2, "Unexpected write error %d returned by service '%s' io function\n", wbytes, req->service);
1044                 return CI_ERROR;
1045             }
1046 
1047             if (rbytes > 0) {
1048                 rchunkdata += rbytes;
1049                 req->remain_send_block_bytes += rbytes;
1050             } else if (rbytes == CI_EOF) {
1051                 service_eof = 1;
1052             } else if (rbytes < 0) {
1053                 ci_debug_printf(2, "Unexpected read error %d returned by service '%s' io function\n", wbytes, req->service);
1054                 return CI_ERROR;
1055             }
1056 
1057             const int may_have_client_data = req->pstrblock_read_len != 0 /*has client data to parse*/
1058                                              && parse_chunk_ret != CI_NEEDS_MORE
1059                                              && parse_chunk_ret != CI_EOF;
1060             repeat_module_io = (no_io == 0) && (may_have_client_data || rchunk_has_space);
1061         } while (repeat_module_io);
1062 
1063         action = 0;
1064         if (!req->write_to_module_pending) {
1065             action = ci_wait_for_read;
1066             wchunkdata = NULL;
1067         }
1068 
1069         if (req->status == SEND_BODY) {
1070             if (req->remain_send_block_bytes == 0 && service_eof == 1)
1071                 req->remain_send_block_bytes = CI_EOF;
1072             if (has_formated_data == 0) {
1073                 if (format_body_chunk(req) == CI_EOF)
1074                     req->status = SEND_EOF;
1075             }
1076         }
1077 
1078         if (req->remain_send_block_bytes) {
1079             action = action | ci_wait_for_write;
1080         }
1081 
1082     } while ((!req->eof_received || (req->eof_received && req->write_to_module_pending)) && (action || lock_status != req->data_locked));
1083 
1084     if (req->eof_received)
1085         return CI_OK;
1086 
1087     if (!action) {
1088         ci_debug_printf(1,
1089                         "Bug: service '%s'. "
1090                         "can not accept or sent body data.\n"
1091                         "request status: %d\n"
1092                         "request data locked?: %d\n"
1093                         "Write to module pending: %d\n"
1094                         "Remain send block bytes: %d\n"
1095                         "Read block len: %d\n",
1096                         req->service,
1097                         req->status,
1098                         req->data_locked,
1099                         req->write_to_module_pending,
1100                         req->remain_send_block_bytes,
1101                         req->pstrblock_read_len
1102             );
1103     } else {
1104         ci_debug_printf(5, "Error reading from network......\n");
1105     }
1106     return CI_ERROR;
1107 }
1108 
1109 
1110 /*Return CI_ERROR on error or CI_OK on success*/
send_remaining_response(ci_request_t * req)1111 static int send_remaining_response(ci_request_t * req)
1112 {
1113     int ret = 0;
1114     int (*service_io) (char *rbuf, int *rlen, char *wbuf, int *wlen, int iseof,
1115                        ci_request_t *);
1116     if (req->echo_body)
1117         service_io = mod_echo_io;
1118     else
1119         service_io = req->current_service_mod->mod_service_io;
1120 
1121     if (!service_io)
1122         return CI_ERROR;
1123 
1124 
1125     if (req->status == SEND_EOF && req->remain_send_block_bytes == 0) {
1126         ci_debug_printf(5, "OK sending all data\n");
1127         return CI_OK;
1128     }
1129     do {
1130         while (req->remain_send_block_bytes > 0) {
1131             if ((ret =
1132                         wait_for_data(req->connection, TIMEOUT,
1133                                       ci_wait_for_write)) < 0) {
1134                 ci_debug_printf(3,
1135                                 "Timeout sending data. Ending .......\n");
1136                 return CI_ERROR;
1137             }
1138             if (send_current_block_data(req) == CI_ERROR)
1139                 return CI_ERROR;
1140         }
1141 
1142         if (req->status == SEND_BODY && req->remain_send_block_bytes == 0) {
1143             req->pstrblock_responce = req->wbuf + EXTRA_CHUNK_SIZE;  /*Leave space for chunk spec.. */
1144             req->remain_send_block_bytes = MAX_CHUNK_SIZE;
1145             ci_debug_printf(9, "rest response: going to read: %d bytes\n", req->remain_send_block_bytes);
1146             service_io(req->pstrblock_responce,
1147                        &(req->remain_send_block_bytes), NULL, NULL, 1, req);
1148             ci_debug_printf(9, "rest response: read: %d bytes\n", req->remain_send_block_bytes);
1149             if (req->remain_send_block_bytes == CI_ERROR)    /*CI_EOF of CI_ERROR, stop sending.... */
1150                 return CI_ERROR;
1151             if (req->remain_send_block_bytes == 0)
1152                 break;
1153 
1154             if ((ret = format_body_chunk(req)) == CI_EOF) {
1155                 req->status = SEND_EOF;
1156             }
1157         }
1158 
1159     } while ((ret = update_send_status(req)) >= 0);    /*CI_EOF is < 0 */
1160 
1161     if (ret == CI_ERROR)
1162         return ret;
1163 
1164     return CI_OK;
1165 }
1166 
options_responce(ci_request_t * req)1167 static void options_responce(ci_request_t * req)
1168 {
1169     char buf[MAX_HEADER_SIZE + 1];
1170     const char *str;
1171     ci_headers_list_t *head;
1172     ci_service_xdata_t *srv_xdata;
1173     unsigned int xopts;
1174     int preview, allow204, allow206, max_conns, xlen;
1175     int hastransfer = 0;
1176     int ttl;
1177     req->return_code = EC_200;
1178     head = req->response_header;
1179     srv_xdata = service_data(req->current_service_mod);
1180     ci_headers_reset(head);
1181     if (run_services_option_handlers(srv_xdata, req) != CI_OK)
1182         ci_headers_add(head, "ICAP/1.0 500 Server Error");
1183     else
1184         ci_headers_add(head, "ICAP/1.0 200 OK");
1185     strcpy(buf, "Methods: ");
1186     if (ci_method_support(req->current_service_mod->mod_type, ICAP_RESPMOD)) {
1187         strcat(buf, "RESPMOD");
1188         if (ci_method_support
1189                 (req->current_service_mod->mod_type, ICAP_REQMOD)) {
1190             strcat(buf, ", REQMOD");
1191         }
1192     } else {                   /*At least one method must supported. A check for error must exists here..... */
1193         strcat(buf, "REQMOD");
1194     }
1195 
1196     ci_headers_add(head, buf);
1197     snprintf(buf, MAX_HEADER_SIZE, "Service: C-ICAP/" VERSION " server - %s",
1198              ((str =
1199                    req->current_service_mod->mod_short_descr) ? str : req->
1200               current_service_mod->mod_name));
1201     buf[MAX_HEADER_SIZE] = '\0';
1202     ci_headers_add(head, buf);
1203 
1204     ci_service_data_read_lock(srv_xdata);
1205     ci_headers_add(head, srv_xdata->ISTag);
1206     if (srv_xdata->TransferPreview[0] != '\0' && srv_xdata->preview_size >= 0) {
1207         ci_headers_add(head, srv_xdata->TransferPreview);
1208         hastransfer++;
1209     }
1210     if (srv_xdata->TransferIgnore[0] != '\0') {
1211         ci_headers_add(head, srv_xdata->TransferIgnore);
1212         hastransfer++;
1213     }
1214     if (srv_xdata->TransferComplete[0] != '\0') {
1215         ci_headers_add(head, srv_xdata->TransferComplete);
1216         hastransfer++;
1217     }
1218     /*If none of the Transfer-* headers configured but preview configured  send all requests*/
1219     if (!hastransfer && srv_xdata->preview_size >= 0)
1220         ci_headers_add(head, "Transfer-Preview: *");
1221     /*Get service options before close the lock.... */
1222     xopts = srv_xdata->xopts;
1223     preview = srv_xdata->preview_size;
1224     allow204 = srv_xdata->allow_204;
1225     allow206 = srv_xdata->allow_206;
1226     max_conns = srv_xdata->max_connections;
1227     ttl = srv_xdata->options_ttl;
1228     ci_service_data_read_unlock(srv_xdata);
1229 
1230     ci_debug_printf(5, "Options response: \n"
1231                     " Preview: %d\n"
1232                     " Allow 204: %s\n"
1233                     " Allow 206: %s\n"
1234                     " TransferPreview: \"%s\"\n"
1235                     " TransferIgnore: %s\n"
1236                     " TransferComplete: %s\n"
1237                     " Max-Connections: %d\n",
1238                     preview,(allow204?"yes":"no"),
1239                     (allow206?"yes":"no"),
1240                     srv_xdata->TransferPreview,
1241                     srv_xdata->TransferIgnore,
1242                     srv_xdata->TransferComplete,
1243                     max_conns
1244                    );
1245 
1246     /* ci_headers_add(head, "Max-Connections: 20"); */
1247     if (ttl > 0) {
1248         sprintf(buf, "Options-TTL: %d", ttl);
1249         ci_headers_add(head, buf);
1250     } else
1251         ci_headers_add(head, "Options-TTL: 3600");
1252     strcpy(buf, "Date: ");
1253     ci_strtime_rfc822(buf + strlen(buf));
1254     ci_headers_add(head, buf);
1255     if (preview >= 0) {
1256         sprintf(buf, "Preview: %d", srv_xdata->preview_size);
1257         ci_headers_add(head, buf);
1258     }
1259     if (max_conns >= 0) {
1260         sprintf(buf, "Max-Connections: %d", max_conns);
1261         ci_headers_add(head, buf);
1262     }
1263     if (allow204 && allow206) {
1264         ci_headers_add(head, "Allow: 204, 206");
1265     } else if (allow204) {
1266         ci_headers_add(head, "Allow: 204");
1267     }
1268     if (xopts) {
1269         strcpy(buf, "X-Include: ");
1270         xlen = 11;            /*sizeof("X-Include: ") */
1271         if ((xopts & CI_XCLIENTIP)) {
1272             strcat(buf, "X-Client-IP");
1273             xlen += sizeof("X-Client-IP");
1274         }
1275         if ((xopts & CI_XSERVERIP)) {
1276             if (xlen > 11) {
1277                 strcat(buf, ", ");
1278                 xlen += 2;
1279             }
1280             strcat(buf, "X-Server-IP");
1281             xlen += sizeof("X-Server-IP");
1282         }
1283         if ((xopts & CI_XSUBSCRIBERID)) {
1284             if (xlen > 11) {
1285                 strcat(buf, ", ");
1286                 xlen += 2;
1287             }
1288             strcat(buf, "X-Subscriber-ID");
1289             xlen += sizeof("X-Subscriber-ID");
1290         }
1291         if ((xopts & CI_XAUTHENTICATEDUSER)) {
1292             if (xlen > 11) {
1293                 strcat(buf, ", ");
1294                 xlen += 2;
1295             }
1296             strcat(buf, "X-Authenticated-User");
1297             xlen += sizeof("X-Authenticated-User");
1298         }
1299         if ((xopts & CI_XAUTHENTICATEDGROUPS)) {
1300             if (xlen > 11) {
1301                 strcat(buf, ", ");
1302                 xlen += 2;
1303             }
1304             strcat(buf, "X-Authenticated-Groups");
1305             xlen += sizeof("X-Authenticated-Groups");
1306         }
1307         if (xlen > 11)
1308             ci_headers_add(head, buf);
1309     }
1310     if (!ci_headers_is_empty(req->xheaders)) {
1311         ci_headers_addheaders(head, req->xheaders);
1312     }
1313     ci_response_pack(req);
1314 
1315     req->pstrblock_responce = head->buf;
1316     req->remain_send_block_bytes = head->bufused;
1317 
1318     do {
1319         if ((wait_for_data(req->connection, TIMEOUT, ci_wait_for_write))
1320                 < 0) {
1321             ci_debug_printf(3, "Timeout sending data. Ending .......\n");
1322             return;
1323         }
1324         if (send_current_block_data(req) == CI_ERROR) {
1325             ci_debug_printf(3, "Error sending data. Ending .....\n");
1326             return;
1327         }
1328     } while (req->remain_send_block_bytes > 0);
1329 
1330 //     if(responce_body)
1331 //        send_body_responce(req,responce_body);
1332 
1333 }
1334 
1335 /*Read preview data, call preview handler and respond with error,  "204" or
1336   "100 Continue" if required.
1337   Returns:
1338   - CI_OK on success and 100 Continue,
1339   - CI_EOF on ieof chunk response (means all body data received,
1340      inside preview, no need to read more data from the client)
1341   - CI_ERROR on error
1342 */
do_request_preview(ci_request_t * req)1343 static int do_request_preview(ci_request_t *req)
1344 {
1345     int preview_read_status;
1346     int res;
1347 
1348     ci_debug_printf(8,"Read preview data if there are and process request\n");
1349 
1350     /*read_preview_data returns CI_OK, CI_EOF or CI_ERROR */
1351     if (!req->hasbody)
1352         preview_read_status = CI_EOF;
1353     else if ((preview_read_status = read_preview_data(req)) == CI_ERROR) {
1354         ci_debug_printf(5,
1355                         "An error occured while reading preview data (propably timeout)\n");
1356         req->keepalive = 0;
1357         ec_responce(req, EC_408);
1358         return CI_ERROR;
1359     }
1360 
1361     if (!req->current_service_mod->mod_check_preview_handler) {
1362         /*We have not a preview data handler. We are responding with "100 Continue"
1363           assuming that the service needs to process all data.
1364           The preview data are stored in req->preview_data.buf, if the service needs them.
1365          */
1366         ci_debug_printf(3, "Preview request but no preview data handler. Respond with \"100 Continue\"\n");
1367         res =  CI_MOD_CONTINUE;
1368     } else {
1369         /*We have a preview handler and we are going to call it*/
1370         res = req->current_service_mod->mod_check_preview_handler(
1371                   req->preview_data.buf, req->preview_data.used, req);
1372     }
1373 
1374     if (res == CI_MOD_ALLOW204) {
1375         if (ec_responce(req, EC_204) < 0) {
1376             req->keepalive = 0; /*close the connection*/
1377             return CI_ERROR;
1378         }
1379 
1380         ci_debug_printf(5,"Preview handler return allow 204 response\n");
1381         /*we are finishing here*/
1382         return CI_OK;
1383     }
1384 
1385     if (res == CI_MOD_ALLOW206 && req->allow206) {
1386         req->return_code = EC_206;
1387         ci_debug_printf(5,"Preview handler return 206 response\n");
1388         return CI_OK;
1389     }
1390 
1391     /*The CI_MOD_CONTINUE is the only remaining valid answer */
1392     if (res != CI_MOD_CONTINUE) {
1393         ci_debug_printf(5, "An error occured in preview handler!"
1394                         " return code: %d , req->allow204=%d, req->allow206=%d\n",
1395                         res, req->allow204, req->allow206);
1396         req->keepalive = 0;
1397         ec_responce(req, EC_500);
1398         return CI_ERROR;
1399     }
1400 
1401     if (preview_read_status != CI_EOF)  {
1402         ec_responce_simple(req, EC_100);     /*if 100 Continue and not "0;ieof"*/
1403     }
1404     /* else 100 Continue and "0;ieof" received. Do not send "100 Continue"*/
1405 
1406     ci_debug_printf(5,"Preview handler %s\n",
1407                     (preview_read_status == CI_EOF ? "receives all body data" : "continue reading more body data"));
1408 
1409     return preview_read_status;
1410 }
1411 
1412 /*
1413    Call the preview handler in the case there is not preview request.
1414 
1415 */
do_fake_preview(ci_request_t * req)1416 static int do_fake_preview(ci_request_t * req)
1417 {
1418     int res;
1419     /*We are outside preview. The preview handler will be called but it needs
1420       special handle.
1421       Currently the preview data handler called with no preview data.In the future we
1422       should add code to read data from client and pass them to the service.
1423       Also in the future the service should not need to know if preview supported
1424       by the client or not
1425     */
1426 
1427     if (!req->current_service_mod->mod_check_preview_handler) {
1428         req->return_code = req->hasbody ? EC_100 : EC_200;
1429         return CI_OK; /*do nothing*/
1430     }
1431 
1432     ci_debug_printf(8,"Preview does not supported. Call the preview handler with no preview data.\n");
1433     res = req->current_service_mod->mod_check_preview_handler(NULL, 0, req);
1434 
1435     /*We are outside preview. The client should support allow204 outside preview
1436       to support it.
1437      */
1438     if (res == CI_MOD_ALLOW204 && req->allow204) {
1439         ci_debug_printf(5,"Preview handler return allow 204 response, and allow204 outside preview supported\n");
1440         if (ec_responce(req, EC_204) < 0) {
1441             req->keepalive = 0; /*close the connection*/
1442             return CI_ERROR;
1443         }
1444 
1445         /*And now parse body data we have read and data the client going to send us,
1446           but do not pass them to the service (second argument of the get_send_body)*/
1447         if (req->hasbody) {
1448             res = get_send_body(req, 1);
1449             if (res == CI_ERROR)
1450                 return res;
1451         }
1452         req->return_code = EC_204;
1453         return CI_OK;
1454     }
1455 
1456     if (res == CI_MOD_ALLOW204) {
1457         if (req->hasbody) {
1458             ci_debug_printf(5,"Preview handler return allow 204 response, allow204 outside preview does NOT supported, and body data\n");
1459             if (FAKE_ALLOW204) {
1460                 ci_debug_printf(5,"Fake allow204 supported, echo data back\n");
1461                 req->echo_body = ci_ring_buf_new(32768);
1462                 req->return_code = EC_100;
1463                 return CI_OK;
1464             }
1465         } else {
1466             ci_debug_printf(5,"Preview handler return allow 204 response, allow204 outside preview does NOT supported, but no body data\n");
1467             /*Just copy http headers to icap response*/
1468             req->return_code = EC_200;
1469             return CI_OK;
1470         }
1471     }
1472 
1473     if (res == CI_MOD_ALLOW206 && req->allow204 && req->allow206) {
1474         ci_debug_printf(5,"Preview handler return allow 204 response, allow204 outside preview and allow206 supported by t");
1475         req->return_code = EC_206;
1476         return CI_OK;
1477     }
1478 
1479     if (res == CI_MOD_CONTINUE) {
1480         req->return_code = req->hasbody ? EC_100 : EC_200;
1481         return CI_OK;
1482     }
1483 
1484     ci_debug_printf(1, "An error occured in preview handler (outside preview)!"
1485                     " return code: %d, req->allow204=%d, req->allow206=%d\n",
1486                     res, req->allow204, req->allow206);
1487     req->keepalive = 0;
1488     ec_responce(req, EC_500);
1489     return CI_ERROR;
1490 }
1491 
1492 /*
1493   Return CI_ERROR or CI_OK
1494 */
do_end_of_data(ci_request_t * req)1495 static int do_end_of_data(ci_request_t * req)
1496 {
1497     int res;
1498 
1499     if (!req->current_service_mod->mod_end_of_data_handler)
1500         return CI_OK; /*Nothing to do*/
1501 
1502     res = req->current_service_mod->mod_end_of_data_handler(req);
1503     /*
1504          while( req->current_service_mod->mod_end_of_data_handler(req)== CI_MOD_NOT_READY){
1505          //can send some data here .........
1506          }
1507     */
1508     if (res == CI_MOD_ALLOW204 && req->allow204 && !ci_req_sent_data(req)) {
1509         if (ec_responce(req, EC_204) < 0) {
1510             ci_debug_printf(5, "An error occured while sending allow 204 response\n");
1511             return CI_ERROR;
1512         }
1513 
1514         return CI_OK;
1515     }
1516 
1517     if (res == CI_MOD_ALLOW206 && req->allow204 && req->allow206 && !ci_req_sent_data(req)) {
1518         req->return_code = EC_206;
1519         return CI_OK;
1520     }
1521 
1522     if (res != CI_MOD_DONE) {
1523         ci_debug_printf(1, "An error occured in end-of-data handler !"
1524                         "return code : %d, req->allow204=%d, req->allow206=%d\n",
1525                         res, req->allow204, req->allow206);
1526 
1527         if (!ci_req_sent_data(req)) {
1528             req->keepalive = 0;
1529             ec_responce(req, EC_500);
1530         }
1531         return CI_ERROR;
1532     }
1533 
1534     return CI_OK;
1535 }
1536 
1537 
do_request(ci_request_t * req)1538 static int do_request(ci_request_t * req)
1539 {
1540     ci_service_xdata_t *srv_xdata = NULL;
1541     int res, preview_status = 0, auth_status;
1542     int ret_status = CI_OK; /*By default ret_status is CI_OK, on error must set to CI_ERROR*/
1543     res = parse_header(req);
1544     if (res != EC_100) {
1545         /*if read some data, bad request or Service not found or Server error or what else,
1546           else connection timeout, or client closes the connection*/
1547         req->return_code = res;
1548         req->keepalive = 0;   // Error occured, close the connection ......
1549         if (res > EC_100 && req->request_header->bufused > 0)
1550             ec_responce(req, res);
1551         ci_debug_printf((req->request_header->bufused ? 5 : 11), "Error %d while parsing headers :(%d)\n",
1552                         res, req->request_header->bufused);
1553         return CI_ERROR;
1554     }
1555     assert(req->current_service_mod);
1556     srv_xdata = service_data(req->current_service_mod);
1557     if (!srv_xdata || srv_xdata->status != CI_SERVICE_OK) {
1558         ci_debug_printf(2, "Service %s not initialized\n", req->current_service_mod->mod_name);
1559         req->keepalive = 0;
1560         ec_responce(req, EC_500);
1561         return CI_ERROR;
1562     }
1563 
1564     if ((auth_status = access_check_request(req)) == CI_ACCESS_DENY) {
1565         req->keepalive = 0;
1566         if (req->auth_required) {
1567             ec_responce(req, EC_407); /*Responce with authentication required */
1568         } else {
1569             ec_responce(req, EC_403); /*Forbitten*/
1570         }
1571         ci_debug_printf(3, "Request not authenticated, status: %d\n", auth_status);
1572         return CI_ERROR;      /*Or something that means authentication error */
1573     }
1574 
1575     if (res == EC_100) {
1576         res = parse_encaps_headers(req);
1577         if (res != EC_100) {
1578             req->keepalive = 0;
1579             ec_responce(req, EC_400);
1580             return CI_ERROR;
1581         }
1582     }
1583 
1584     if (req->current_service_mod->mod_init_request_data)
1585         req->service_data =
1586             req->current_service_mod->mod_init_request_data(req);
1587     else
1588         req->service_data = NULL;
1589 
1590     ci_debug_printf(8, "Requested service: %s\n",
1591                     req->current_service_mod->mod_name);
1592 
1593     switch (req->type) {
1594     case ICAP_OPTIONS:
1595         options_responce(req);
1596         ret_status = CI_OK;
1597         break;
1598     case ICAP_REQMOD:
1599     case ICAP_RESPMOD:
1600         if (req->preview >= 0) /*we are inside preview*/
1601             preview_status = do_request_preview(req);
1602         else {
1603             /* do_fake_preview return CI_OK or CI_ERROR. */
1604             preview_status = do_fake_preview(req);
1605         }
1606 
1607         if (preview_status == CI_ERROR) {
1608             ret_status = CI_ERROR;
1609             break;
1610         } else if (preview_status == CI_EOF)
1611             req->return_code = EC_200; /*Equivalent to "100 Continue"*/
1612 
1613         if (req->return_code == EC_204) /*Allow 204,  Stop processing here*/
1614             break;
1615         /*else 100 continue or 206  response or Internal error*/
1616         else if (req->return_code != EC_100 && req->return_code != EC_200 && req->return_code != EC_206) {
1617             ec_responce(req, EC_500);
1618             ret_status = CI_ERROR;
1619             break;
1620         }
1621 
1622         if (req->return_code == EC_100 && req->hasbody && preview_status != CI_EOF) {
1623             req->return_code = EC_200; /*We have to repsond with "200 OK"*/
1624             ci_debug_printf(9, "Going to get/send body data.....\n");
1625             ret_status = get_send_body(req, 0);
1626             if (ret_status == CI_ERROR) {
1627                 req->keepalive = 0; /*close the connection*/
1628                 ci_debug_printf(5,
1629                                 "An error occured. Parse error or the client closed the connection (res:%d, preview status:%d)\n",
1630                                 ret_status, preview_status);
1631                 break;
1632             }
1633         }
1634 
1635         /*We have received all data from the client. Call the end-of-data service handler and process*/
1636         ret_status = do_end_of_data(req);
1637         if (ret_status == CI_ERROR) {
1638             req->keepalive = 0; /*close the connection*/
1639             break;
1640         }
1641 
1642         if (req->return_code == EC_204)
1643             break;  /* Nothing to be done, stop here*/
1644         /*else we have to send response to the client*/
1645 
1646 
1647         unlock_data(req); /*unlock data if locked so that it can be send to the client*/
1648         ret_status = send_remaining_response(req);
1649         if (ret_status == CI_ERROR) {
1650             req->keepalive = 0; /*close the connection*/
1651             ci_debug_printf(5, "Error while sending rest responce or client closed the connection\n");
1652         }
1653         /*We are finished here*/
1654         break;
1655     default:
1656         req->keepalive = 0; /*close the connection*/
1657         ret_status = CI_ERROR;
1658         break;
1659     }
1660 
1661     if (req->current_service_mod->mod_release_request_data
1662             && req->service_data)
1663         req->current_service_mod->mod_release_request_data(req->service_data);
1664 
1665 //     debug_print_request(req);
1666     return ret_status;
1667 }
1668 
process_request(ci_request_t * req)1669 int process_request(ci_request_t * req)
1670 {
1671     int res;
1672     ci_service_xdata_t *srv_xdata;
1673     res = do_request(req);
1674 
1675     if (req->pstrblock_read_len) {
1676         ci_debug_printf(5, "There are unparsed data od size %d: \"%.*s\"\n. Move to connection buffer\n", req->pstrblock_read_len, (req->pstrblock_read_len < 64 ? req->pstrblock_read_len : 64), req->pstrblock_read);
1677     }
1678 
1679     if (res<0 && req->request_header->bufused == 0) /*Did not read anything*/
1680         return CI_NO_STATUS;
1681 
1682     if (STATS) {
1683         if (req->return_code != EC_404 && req->current_service_mod)
1684             srv_xdata = service_data(req->current_service_mod);
1685         else
1686             srv_xdata = NULL;
1687 
1688         STATS_LOCK();
1689         if (STAT_REQUESTS >= 0) STATS_INT64_INC(STAT_REQUESTS,1);
1690 
1691         if (req->type == ICAP_REQMOD) {
1692             STATS_INT64_INC(STAT_REQMODS, 1);
1693             if (srv_xdata)
1694                 STATS_INT64_INC(srv_xdata->stat_reqmods, 1);
1695         } else if (req->type == ICAP_RESPMOD) {
1696             STATS_INT64_INC(STAT_RESPMODS, 1);
1697             if (srv_xdata)
1698                 STATS_INT64_INC(srv_xdata->stat_respmods, 1);
1699         } else if (req->type == ICAP_OPTIONS) {
1700             STATS_INT64_INC(STAT_OPTIONS, 1);
1701             if (srv_xdata)
1702                 STATS_INT64_INC(srv_xdata->stat_options, 1);
1703         }
1704 
1705         if (res <0 && STAT_FAILED_REQUESTS >= 0)
1706             STATS_INT64_INC(STAT_FAILED_REQUESTS,1);
1707         else if (req->return_code == EC_204) {
1708             STATS_INT64_INC(STAT_ALLOW204, 1);
1709             if (srv_xdata)
1710                 STATS_INT64_INC(srv_xdata->stat_allow204, 1);
1711         }
1712 
1713 
1714         if (STAT_BYTES_IN >= 0) STATS_KBS_INC(STAT_BYTES_IN, req->bytes_in);
1715         if (STAT_BYTES_OUT >= 0) STATS_KBS_INC(STAT_BYTES_OUT, req->bytes_out);
1716         if (STAT_HTTP_BYTES_IN >= 0) STATS_KBS_INC(STAT_HTTP_BYTES_IN, req->http_bytes_in);
1717         if (STAT_HTTP_BYTES_OUT >= 0) STATS_KBS_INC(STAT_HTTP_BYTES_OUT, req->http_bytes_out);
1718         if (STAT_BODY_BYTES_IN >= 0) STATS_KBS_INC(STAT_BODY_BYTES_IN, req->body_bytes_in);
1719         if (STAT_BODY_BYTES_OUT >= 0) STATS_KBS_INC(STAT_BODY_BYTES_OUT, req->body_bytes_out);
1720 
1721         if (srv_xdata) {
1722             if (srv_xdata->stat_bytes_in >= 0)
1723                 STATS_KBS_INC(srv_xdata->stat_bytes_in, req->bytes_in);
1724             if (srv_xdata->stat_bytes_out >= 0)
1725                 STATS_KBS_INC(srv_xdata->stat_bytes_out, req->bytes_out);
1726             if (srv_xdata->stat_http_bytes_in >= 0)
1727                 STATS_KBS_INC(srv_xdata->stat_http_bytes_in, req->http_bytes_in);
1728             if (srv_xdata->stat_http_bytes_out >= 0)
1729                 STATS_KBS_INC(srv_xdata->stat_http_bytes_out, req->http_bytes_out);
1730             if (srv_xdata->stat_body_bytes_in >= 0)
1731                 STATS_KBS_INC(srv_xdata->stat_body_bytes_in, req->body_bytes_in);
1732             if (srv_xdata->stat_body_bytes_out >= 0)
1733                 STATS_KBS_INC(srv_xdata->stat_body_bytes_out, req->body_bytes_out);
1734         }
1735         STATS_UNLOCK();
1736     }
1737 
1738     return res; /*Allow to log even the failed requests*/
1739 }
1740