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